feat(core): 모듈/플러그인 프론트엔드 에셋 서버측 번들 병합

활성 모듈/플러그인마다 프론트엔드 IIFE JS·CSS 가 개별 HTTP 요청으로 로드되어
확장 수에 비례해 요청이 늘어나는 오버헤드를, 종류별 1개 번들로 서버 병합해 줄인다.
각 확장 IIFE 자가등록 계약(핸들러/리스너/preblocker)은 priority 순 물리 병합으로
실행 순서가 보존되어 그대로 동작한다.

## 백엔드
- 신규 ExtensionBundleService — 정렬(uasort priority)·필터(global)·concat(\n;\n
 구분자로 ASI 경계 보호)·소스맵(prod strip / dev rewrite)·version-in-path 디스크
 캐시·확장별 fine-grained try/catch(한 확장 실패가 번들 전체를 붕괴시키지 않음)
- AbstractModule/AbstractPlugin::getBuiltAssetAbsolutePaths — _bundled 경로
 정확 해석용 절대경로 게터(getAssetFilePath 하드코딩 복제 회피)
- PublicModule/PluginController::serveBundle{Js,Css} + routes/api.php 4개
 (/api/{modules,plugins}/bundle.{js,css}?v={version}, fileResponse ETag/304 재사용)
- config/filesystems.php ext-bundles 디스크 + storage/.gitignore + 루트 .gitignore
- 신규 ext-bundles:cleanup 커맨드 + {module,plugin,template}:cache-clear 번들
 정리 통합 + dev-dashboard 버튼

## 프론트엔드 (engine-v1.52.0)
- TemplateApp.loadExtensionAssets — 개별 로딩 → bundleUrls 기반 모듈→플러그인
 순 번들 로딩. bundleUrls 부재 시 개별 로딩 폴백(회귀 안전)
- ModuleAssetLoader.loadBundle + parseBundleUrlsFromConfig + ExtensionBundleUrls
- TemplateComposer/UserTemplateComposer bundleUrls 뷰변수 + app/admin.blade.php
- core:build 재빌드 산출물(public/build/core/*)

## 버전 동기화 판정 ( 결정)
코어 add-only(개별 서빙 라우트 존치 + 프론트 폴백). 6개 프론트 에셋 확장이 신규
코어 표면을 자기 코드에서 호출하지 않아 코어 7.0.0 에서도 동작 → 실제 의존 없음.
확장 g7_version 상향 안 함(>=7.0.0 유지). 코어 버전 무변경(7.0.1 accumulate).

## 규정/audit/문서/테스트
- ("확장 번들 병합" 절+파일유형표+E2E경로) / AGENTS.md /
 docs/extension/module-assets.md / docs/cheatsheet.md
- coverage.json 4항목 + codified 룰 4종(url-same-origin, concat-separator,
 asset-path-getter, clears-template-caches-no-file-delete)
- 루트 CHANGELOG [7.0.1] Added / 엔진 CHANGELOG engine-v1.52.0 Added
- Vitest 11(loadBundle + concat 자가등록) + PHPUnit 17(Service 12 + Feature 5)
 + Playwright spec + 시나리오 매니페스트
- 브라우저 실측(g7.dev): 홈/관리자 번들 각 1건·개별 iife 0건, gdpr 인터셉터
 정상, 활성화 토글 반영, 장바구니→체크아웃·게시판 글쓰기 정상. g7_2.dev 미적용
 대비 확장 요청 11~12→4건, DOMContentLoaded ~843~957→605~741ms(페이로드 무손실)

## 도구 보완
- pre-commit-review 스킬 에 엔진 경로 감지 게이트(5-pre + 보고 5e행) 신설 —
 매핑 표에 엔진 파일이 있으면 엔진 CHANGELOG 판정을 강제(이번 초기 누락 재발 방지)
This commit is contained in:
HeuJung committed 2026-07-04 22:19:55 +09:00
1 parent 7c18adc09d
commit f267f21ea6
35 files changed
+1754 -53

No files matched your search

+3
View File
@@ -49,6 +49,9 @@ node_modules/
# Settings JSON files (환경별 설정) # Settings JSON files (환경별 설정)
/storage/app/settings/ /storage/app/settings/
# 확장 프론트엔드 병합 번들 캐시 (version-in-path, 런타임 생성)
/storage/app/ext-bundles/
# Bootstrap cache (auto-generated) # Bootstrap cache (auto-generated)
/bootstrap/cache/* /bootstrap/cache/*
!/bootstrap/cache/.gitkeep !/bootstrap/cache/.gitkeep
+12
View File
@@ -788,6 +788,18 @@ php artisan plugin:update sirsoft-payment --force
lazy 번들(편집기/devtools)이 코어 런타임(DynamicRenderer·엔진 싱글톤·React Context·DevTools 코어)을 재사용할 때는 재번들하지 않고 `window.G7Core.__runtime` 을 빌려 쓴다 — React/컨텍스트/싱글톤 인스턴스 동일성이 강제되기 때문(사본이 둘이면 "Invalid hook call"·컨텍스트 미매칭). 메인 번들이 `G7CoreGlobals` 에서 공유 대상을 `G7Core.__runtime` 에 노출하고, lazy 번들 vite config 는 React 4종(`react`/`react-dom`/`react-dom/client`/`react/jsx-runtime`)을 external→window 로, 코어 런타임 모듈을 `resolveId` 플러그인으로 `__runtime-shims/` 로 치환한다. lazy 번들(편집기/devtools)이 코어 런타임(DynamicRenderer·엔진 싱글톤·React Context·DevTools 코어)을 재사용할 때는 재번들하지 않고 `window.G7Core.__runtime` 을 빌려 쓴다 — React/컨텍스트/싱글톤 인스턴스 동일성이 강제되기 때문(사본이 둘이면 "Invalid hook call"·컨텍스트 미매칭). 메인 번들이 `G7CoreGlobals` 에서 공유 대상을 `G7Core.__runtime` 에 노출하고, lazy 번들 vite config 는 React 4종(`react`/`react-dom`/`react-dom/client`/`react/jsx-runtime`)을 external→window 로, 코어 런타임 모듈을 `resolveId` 플러그인으로 `__runtime-shims/` 로 치환한다.
### 확장 번들 병합 (서버측 concat)
활성 모듈/플러그인의 프론트엔드 IIFE JS·CSS 는 타입별로 서버에서 하나의 번들로 병합해 서빙한다(`/api/{modules,plugins}/bundle.{js,css}?v={version}`). `ExtensionBundleService` 가 정렬·필터·concat·캐시를 전담하고, 프론트는 `window.G7Config.bundleUrls` 를 읽어 모듈 번들 → 플러그인 번들 순으로 로드한다. 병합 규율:
- priority 순서는 선언형 — 실행 순서는 오직 manifest `loading.priority` 오름차순(`uasort`). 특정 확장 이름을 지목하는 분기를 두지 않는다.
- IIFE 사이는 `\n;\n`(JS)/`\n`(CSS) 로 잇는다. 미사용 시 ASI 경계가 깨져 번들 전체 파싱 에러가 난다.
- 소스맵은 prod strip, dev 는 개별 에셋 서빙 절대 URL 로 rewrite. 개별 에셋 서빙 라우트(`*.map` 포함)는 존치한다.
- 번들 URL 은 반드시 same-origin(`/api/...`). 외부 origin/CDN·protocol-relative 는 gdpr preblocker 에 자기 차단된다.
- 확장 에셋 절대경로는 `getBuiltAssetAbsolutePaths()`(=`getModulePath()`/`getPluginPath()`) 만 쓴다. `base_path("modules"|"plugins")` 직접 조립은 `_bundled` 경로 오해석 → 빈 번들.
- concat 루프는 확장별 try/catch — 실패 확장만 skip 하고 나머지 병합을 지속한다.
- 번들 파일명에 확장 캐시 버전을 포함(`{type}.{version}.{js,css}`). 조합 변경 시 version bump → 새 파일명 → 자동 재생성. 구파일 GC 는 `ext-bundles:cleanup` + `{module,plugin,template}:cache-clear` 가 담당한다. prod 은 version-in-path 디스크 캐시, 비프로덕션은 매 요청 concat.
### 빌드 명령어 (Artisan) ### 빌드 명령어 (Artisan)
```bash ```bash
+4
View File
@@ -6,6 +6,10 @@
## [7.0.1] - 2026-07-03 ## [7.0.1] - 2026-07-03
### Added
- 설치된 모듈·플러그인이 늘어날수록 화면마다 개별로 내려받던 확장 스크립트·스타일 요청을 종류별로 하나로 묶어 내려받도록 개선해, 확장이 많은 사이트의 초기 로딩 요청 수를 크게 줄였습니다. 확장을 설치·활성화·비활성화하면 묶음이 자동으로 다시 만들어져 항상 현재 활성 상태와 일치합니다.
### Changed ### Changed
- 첫 화면 접속 시 내려받는 코어 스크립트 용량을 절반 이하로 줄여 초기 로딩을 개선했습니다. 레이아웃 편집기와 개발자 진단도구를 코어에서 분리해, 편집기는 편집 화면에 들어갈 때만, 진단도구는 디버그 모드를 켰을 때만 내려받도록 했습니다. 일반 사용자는 평소 쓰지 않는 편집기·진단도구 코드를 더 이상 받지 않습니다. - 첫 화면 접속 시 내려받는 코어 스크립트 용량을 절반 이하로 줄여 초기 로딩을 개선했습니다. 레이아웃 편집기와 개발자 진단도구를 코어에서 분리해, 편집기는 편집 화면에 들어갈 때만, 진단도구는 디버그 모드를 켰을 때만 내려받도록 했습니다. 일반 사용자는 평소 쓰지 않는 편집기·진단도구 코드를 더 이상 받지 않습니다.
@@ -0,0 +1,43 @@
<?php
namespace App\Console\Commands;
use App\Services\ExtensionBundleService;
use Illuminate\Console\Command;
/**
* 오래된 확장 프론트엔드 병합 번들 파일을 정리하는 커맨드
*
* 번들 캐시 파일(`storage/app/ext-bundles/{type}.{version}.{js|css}`)은 Laravel
* 캐시 스토어 밖 파일시스템이라 version bump 나 cache:clear 가 구버전 파일을
* 지우지 않는다(TTL/GC 없음). 이 커맨드가 현재 version 외의 구파일을 삭제한다.
* (`CleanupLayoutPreviewsCommand` 파일 산출물 GC 패턴 미러)
*/
class CleanupExtensionBundlesCommand extends Command
{
/**
* The name and signature of the console command.
*/
protected $signature = 'ext-bundles:cleanup';
/**
* The console command description.
*/
protected $description = '오래된 확장 프론트엔드 병합 번들 파일(구 version)을 삭제합니다';
/**
* Execute the console command.
*
* @param ExtensionBundleService $service 번들 서비스
* @return int 명령 실행 결과 코드
*/
public function handle(ExtensionBundleService $service): int
{
$currentVersion = $service->getCurrentVersion();
$deleted = $service->cleanupStaleBundles($currentVersion);
$this->info("오래된 확장 번들 {$deleted}건이 삭제되었습니다. (현재 version: {$currentVersion})");
return self::SUCCESS;
}
}
@@ -5,6 +5,7 @@ namespace App\Console\Commands\Module;
use App\Contracts\Extension\CacheInterface; use App\Contracts\Extension\CacheInterface;
use App\Contracts\Repositories\ModuleRepositoryInterface; use App\Contracts\Repositories\ModuleRepositoryInterface;
use App\Extension\ModuleManager; use App\Extension\ModuleManager;
use App\Services\ExtensionBundleService;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -27,7 +28,8 @@ class ClearModuleCacheCommand extends Command
public function __construct( public function __construct(
private ModuleManager $moduleManager, private ModuleManager $moduleManager,
private ModuleRepositoryInterface $moduleRepository, private ModuleRepositoryInterface $moduleRepository,
private CacheInterface $cache private CacheInterface $cache,
private ExtensionBundleService $bundleService
) { ) {
parent::__construct(); parent::__construct();
} }
@@ -86,6 +88,9 @@ class ClearModuleCacheCommand extends Command
$clearedCount += $this->clearModuleCache($module->getIdentifier()); $clearedCount += $this->clearModuleCache($module->getIdentifier());
} }
// 모듈 프론트엔드 병합 번들 파일 삭제 (캐시 키 forget 만으로는 미삭제)
$clearedCount += $this->bundleService->clearBundles('module');
$this->info('✅ '.__('modules.commands.cache_clear.success_all', ['count' => $clearedCount])); $this->info('✅ '.__('modules.commands.cache_clear.success_all', ['count' => $clearedCount]));
} }
@@ -5,6 +5,7 @@ namespace App\Console\Commands\Plugin;
use App\Contracts\Extension\CacheInterface; use App\Contracts\Extension\CacheInterface;
use App\Contracts\Repositories\PluginRepositoryInterface; use App\Contracts\Repositories\PluginRepositoryInterface;
use App\Extension\PluginManager; use App\Extension\PluginManager;
use App\Services\ExtensionBundleService;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -27,7 +28,8 @@ class ClearPluginCacheCommand extends Command
public function __construct( public function __construct(
private PluginManager $pluginManager, private PluginManager $pluginManager,
private PluginRepositoryInterface $pluginRepository, private PluginRepositoryInterface $pluginRepository,
private CacheInterface $cache private CacheInterface $cache,
private ExtensionBundleService $bundleService
) { ) {
parent::__construct(); parent::__construct();
} }
@@ -86,6 +88,9 @@ class ClearPluginCacheCommand extends Command
$clearedCount += $this->clearPluginCache($plugin->getIdentifier()); $clearedCount += $this->clearPluginCache($plugin->getIdentifier());
} }
// 플러그인 프론트엔드 병합 번들 파일 삭제 (캐시 키 forget 만으로는 미삭제)
$clearedCount += $this->bundleService->clearBundles('plugin');
$this->info('✅ '.__('plugins.commands.cache_clear.success_all', ['count' => $clearedCount])); $this->info('✅ '.__('plugins.commands.cache_clear.success_all', ['count' => $clearedCount]));
} }
@@ -6,6 +6,7 @@ use App\Contracts\Extension\CacheInterface;
use App\Extension\TemplateManager; use App\Extension\TemplateManager;
use App\Models\Template; use App\Models\Template;
use App\Models\TemplateLayout; use App\Models\TemplateLayout;
use App\Services\ExtensionBundleService;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -27,7 +28,8 @@ class ClearTemplateCacheCommand extends Command
*/ */
public function __construct( public function __construct(
private TemplateManager $templateManager, private TemplateManager $templateManager,
private CacheInterface $cache private CacheInterface $cache,
private ExtensionBundleService $bundleService
) { ) {
parent::__construct(); parent::__construct();
} }
@@ -153,6 +155,9 @@ class ClearTemplateCacheCommand extends Command
$this->cache->forget('templates.active.user'); $this->cache->forget('templates.active.user');
$clearedCount += 2; $clearedCount += 2;
// 5. 확장 프론트엔드 병합 번들 파일 전체 삭제 (템플릿 캐시 정리는 페이지 전면 갱신)
$clearedCount += $this->bundleService->clearBundles();
$this->info('✅ '.__('templates.commands.cache_clear.success_all', [ $this->info('✅ '.__('templates.commands.cache_clear.success_all', [
'count' => $clearedCount, 'count' => $clearedCount,
])); ]));
+23
View File
@@ -1190,6 +1190,29 @@ abstract class AbstractModule implements CacheableExtensionInterface, ModuleInte
return $result; return $result;
} }
/**
* 빌드된 에셋의 절대 파일 경로를 반환합니다.
*
* `getBuiltAssetPaths()` 는 module.json 의 상대 output 경로를 돌려주므로
* 파일을 실제로 읽으려면 모듈 루트(`getModulePath()`: 활성 dir 또는 `_bundled`
* 실제 위치)를 앞에 붙여야 한다. 서버측 번들 병합(ExtensionBundleService)이
* `getAssetFilePath()` 의 `base_path("modules/{id}/...")` 하드코딩을 복제하지
* 않고 `_bundled` 확장에서도 정확한 경로를 얻도록 이 게터를 SSoT 로 쓴다.
*
* @return array 빌드된 에셋 절대 경로 배열 ['js' => '...', 'css' => '...']
*/
public function getBuiltAssetAbsolutePaths(): array
{
$relative = $this->getBuiltAssetPaths();
$result = [];
foreach ($relative as $kind => $output) {
$result[$kind] = $this->getModulePath().'/'.$output;
}
return $result;
}
/** /**
* 모듈 스토리지 드라이버 인스턴스 반환 * 모듈 스토리지 드라이버 인스턴스 반환
* *
+24
View File
@@ -1011,6 +1011,30 @@ abstract class AbstractPlugin implements CacheableExtensionInterface, PluginInte
return $result; return $result;
} }
/**
* 빌드된 에셋의 절대 파일 경로를 반환합니다.
*
* `getBuiltAssetPaths()` 는 plugin.json 의 상대 output 경로를 돌려주므로
* 파일을 실제로 읽으려면 플러그인 루트(`getPluginPath()`: 활성 dir 또는
* `_bundled` 실제 위치)를 앞에 붙여야 한다. 서버측 번들 병합
* (ExtensionBundleService)이 `getAssetFilePath()` 의
* `base_path("plugins/{id}/...")` 하드코딩을 복제하지 않고 `_bundled`
* 확장에서도 정확한 경로를 얻도록 이 게터를 SSoT 로 쓴다.
*
* @return array 빌드된 에셋 절대 경로 배열 ['js' => '...', 'css' => '...']
*/
public function getBuiltAssetAbsolutePaths(): array
{
$relative = $this->getBuiltAssetPaths();
$result = [];
foreach ($relative as $kind => $output) {
$result[$kind] = $this->getPluginPath().'/'.$output;
}
return $result;
}
/** /**
* 플러그인이 설정 페이지를 가지고 있는지 확인합니다. * 플러그인이 설정 페이지를 가지고 있는지 확인합니다.
* *
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Public;
use App\Http\Controllers\Api\Base\PublicBaseController; use App\Http\Controllers\Api\Base\PublicBaseController;
use App\Http\Requests\Public\Module\ServeModuleAssetRequest; use App\Http\Requests\Public\Module\ServeModuleAssetRequest;
use App\Services\ExtensionBundleService;
use App\Services\ModuleService; use App\Services\ModuleService;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response; use Illuminate\Http\Response;
@@ -17,11 +18,54 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse;
class PublicModuleController extends PublicBaseController class PublicModuleController extends PublicBaseController
{ {
public function __construct( public function __construct(
private readonly ModuleService $moduleService private readonly ModuleService $moduleService,
private readonly ExtensionBundleService $bundleService
) { ) {
parent::__construct(); parent::__construct();
} }
/**
* 활성 모듈 프론트엔드 IIFE 병합 번들(JS)을 서빙합니다.
*
* 활성 global 모듈 에셋이 없으면 빈 200 응답(text/javascript)을 반환한다
* (프론트는 빈 스크립트 로드로 무해). 그 외에는 병합 파일을 fileResponse 로
* 서빙(ETag/304/환경별 Cache-Control 재사용).
*
* @return BinaryFileResponse|Response 병합 JS 파일 응답 또는 빈 응답
*/
public function serveBundleJs(): BinaryFileResponse|Response
{
$this->logApiUsage('modules.bundle', ['kind' => 'js']);
$version = $this->bundleService->getCurrentVersion();
$path = $this->bundleService->getBundleFilePath('module', 'js', $version);
if ($path === '') {
return response('', 200)->header('Content-Type', 'text/javascript');
}
return $this->fileResponse($path, 'text/javascript', 31536000);
}
/**
* 활성 모듈 프론트엔드 병합 번들(CSS)을 서빙합니다.
*
* @return BinaryFileResponse|Response 병합 CSS 파일 응답 또는 빈 응답
*/
public function serveBundleCss(): BinaryFileResponse|Response
{
$this->logApiUsage('modules.bundle', ['kind' => 'css']);
$version = $this->bundleService->getCurrentVersion();
$path = $this->bundleService->getBundleFilePath('module', 'css', $version);
if ($path === '') {
return response('', 200)->header('Content-Type', 'text/css');
}
return $this->fileResponse($path, 'text/css', 31536000);
}
/** /**
* 모듈 에셋 서빙 * 모듈 에셋 서빙
* *
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Public;
use App\Http\Controllers\Api\Base\PublicBaseController; use App\Http\Controllers\Api\Base\PublicBaseController;
use App\Http\Requests\Public\Plugin\ServePluginAssetRequest; use App\Http\Requests\Public\Plugin\ServePluginAssetRequest;
use App\Services\ExtensionBundleService;
use App\Services\PluginService; use App\Services\PluginService;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response; use Illuminate\Http\Response;
@@ -17,11 +18,53 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse;
class PublicPluginController extends PublicBaseController class PublicPluginController extends PublicBaseController
{ {
public function __construct( public function __construct(
private readonly PluginService $pluginService private readonly PluginService $pluginService,
private readonly ExtensionBundleService $bundleService
) { ) {
parent::__construct(); parent::__construct();
} }
/**
* 활성 플러그인 프론트엔드 IIFE 병합 번들(JS)을 서빙합니다.
*
* 활성 global 플러그인 에셋이 없으면 빈 200 응답(text/javascript)을 반환한다.
* 그 외에는 병합 파일을 fileResponse 로 서빙(ETag/304/환경별 Cache-Control 재사용).
*
* @return BinaryFileResponse|Response 병합 JS 파일 응답 또는 빈 응답
*/
public function serveBundleJs(): BinaryFileResponse|Response
{
$this->logApiUsage('plugins.bundle', ['kind' => 'js']);
$version = $this->bundleService->getCurrentVersion();
$path = $this->bundleService->getBundleFilePath('plugin', 'js', $version);
if ($path === '') {
return response('', 200)->header('Content-Type', 'text/javascript');
}
return $this->fileResponse($path, 'text/javascript', 31536000);
}
/**
* 활성 플러그인 프론트엔드 병합 번들(CSS)을 서빙합니다.
*
* @return BinaryFileResponse|Response 병합 CSS 파일 응답 또는 빈 응답
*/
public function serveBundleCss(): BinaryFileResponse|Response
{
$this->logApiUsage('plugins.bundle', ['kind' => 'css']);
$version = $this->bundleService->getCurrentVersion();
$path = $this->bundleService->getBundleFilePath('plugin', 'css', $version);
if ($path === '') {
return response('', 200)->header('Content-Type', 'text/css');
}
return $this->fileResponse($path, 'text/css', 31536000);
}
/** /**
* 플러그인 에셋 서빙 * 플러그인 에셋 서빙
* *
@@ -99,6 +99,9 @@ class TemplateComposer
// 확장 기능 캐시 버전 (브라우저 캐시 무효화용) // 확장 기능 캐시 버전 (브라우저 캐시 무효화용)
$extensionCacheVersion = ClearsTemplateCaches::getExtensionCacheVersion(); $extensionCacheVersion = ClearsTemplateCaches::getExtensionCacheVersion();
// 확장 프론트엔드 병합 번들 URL (상시 ON — 활성 에셋이 없으면 null)
$bundleUrls = $this->buildExtensionBundleUrls($moduleAssets, $pluginAssets, $extensionCacheVersion);
$view->with('activeAdminTemplate', $activeTemplate); $view->with('activeAdminTemplate', $activeTemplate);
$view->with('extensionCacheVersion', $extensionCacheVersion); $view->with('extensionCacheVersion', $extensionCacheVersion);
$view->with('frontendSettings', $frontendSettings); $view->with('frontendSettings', $frontendSettings);
@@ -106,12 +109,39 @@ class TemplateComposer
$view->with('moduleSettings', $moduleSettings); $view->with('moduleSettings', $moduleSettings);
$view->with('moduleAssets', $moduleAssets); $view->with('moduleAssets', $moduleAssets);
$view->with('pluginAssets', $pluginAssets); $view->with('pluginAssets', $pluginAssets);
$view->with('bundleUrls', $bundleUrls);
$view->with('activeModulesMeta', $activeModulesMeta); $view->with('activeModulesMeta', $activeModulesMeta);
$view->with('activePluginsMeta', $activePluginsMeta); $view->with('activePluginsMeta', $activePluginsMeta);
$view->with('appConfig', $appConfig); $view->with('appConfig', $appConfig);
$view->with('templateExternals', $templateExternals); $view->with('templateExternals', $templateExternals);
} }
/**
* 확장 프론트엔드 병합 번들 URL을 계산합니다.
*
* 활성 global 에셋(JS/CSS)이 하나라도 있는 타입만 해당 번들 URL을 채우고,
* 없으면 null을 두어 프론트가 로드를 스킵하게 한다. URL은 same-origin
* (`/api/...`)이어야 gdpr preblocker 의 same-origin 통과 규칙에 자기 차단되지
* 않는다(CDN 호스팅 금지).
*
* @param array $moduleAssets 수집된 모듈 개별 에셋 맵
* @param array $pluginAssets 수집된 플러그인 개별 에셋 맵
* @param int $version 확장 캐시 버전
* @return array{moduleJs: ?string, moduleCss: ?string, pluginJs: ?string, pluginCss: ?string}
*/
private function buildExtensionBundleUrls(array $moduleAssets, array $pluginAssets, int $version): array
{
$hasJs = static fn (array $assets): bool => ! empty(array_filter($assets, fn ($a) => ! empty($a['js'])));
$hasCss = static fn (array $assets): bool => ! empty(array_filter($assets, fn ($a) => ! empty($a['css'])));
return [
'moduleJs' => $hasJs($moduleAssets) ? "/api/modules/bundle.js?v={$version}" : null,
'moduleCss' => $hasCss($moduleAssets) ? "/api/modules/bundle.css?v={$version}" : null,
'pluginJs' => $hasJs($pluginAssets) ? "/api/plugins/bundle.js?v={$version}" : null,
'pluginCss' => $hasCss($pluginAssets) ? "/api/plugins/bundle.css?v={$version}" : null,
];
}
/** /**
* 활성화된 모듈의 프론트엔드 에셋 정보를 수집합니다. * 활성화된 모듈의 프론트엔드 에셋 정보를 수집합니다.
* *
@@ -105,6 +105,9 @@ class UserTemplateComposer
// 확장 기능 캐시 버전 (브라우저 캐시 무효화용) // 확장 기능 캐시 버전 (브라우저 캐시 무효화용)
$extensionCacheVersion = ClearsTemplateCaches::getExtensionCacheVersion(); $extensionCacheVersion = ClearsTemplateCaches::getExtensionCacheVersion();
// 확장 프론트엔드 병합 번들 URL (상시 ON — 활성 에셋이 없으면 null)
$bundleUrls = $this->buildExtensionBundleUrls($moduleAssets, $pluginAssets, $extensionCacheVersion);
$view->with('activeUserTemplate', $activeTemplate); $view->with('activeUserTemplate', $activeTemplate);
$view->with('extensionCacheVersion', $extensionCacheVersion); $view->with('extensionCacheVersion', $extensionCacheVersion);
$view->with('frontendSettings', $frontendSettings); $view->with('frontendSettings', $frontendSettings);
@@ -112,12 +115,39 @@ class UserTemplateComposer
$view->with('moduleSettings', $moduleSettings); $view->with('moduleSettings', $moduleSettings);
$view->with('moduleAssets', $moduleAssets); $view->with('moduleAssets', $moduleAssets);
$view->with('pluginAssets', $pluginAssets); $view->with('pluginAssets', $pluginAssets);
$view->with('bundleUrls', $bundleUrls);
$view->with('activeModulesMeta', $activeModulesMeta); $view->with('activeModulesMeta', $activeModulesMeta);
$view->with('activePluginsMeta', $activePluginsMeta); $view->with('activePluginsMeta', $activePluginsMeta);
$view->with('appConfig', $appConfig); $view->with('appConfig', $appConfig);
$view->with('templateExternals', $templateExternals); $view->with('templateExternals', $templateExternals);
} }
/**
* 확장 프론트엔드 병합 번들 URL을 계산합니다.
*
* 활성 global 에셋(JS/CSS)이 하나라도 있는 타입만 해당 번들 URL을 채우고,
* 없으면 null을 두어 프론트가 로드를 스킵하게 한다. URL은 same-origin
* (`/api/...`)이어야 gdpr preblocker 의 same-origin 통과 규칙에 자기 차단되지
* 않는다(CDN 호스팅 금지).
*
* @param array $moduleAssets 수집된 모듈 개별 에셋 맵
* @param array $pluginAssets 수집된 플러그인 개별 에셋 맵
* @param int $version 확장 캐시 버전
* @return array{moduleJs: ?string, moduleCss: ?string, pluginJs: ?string, pluginCss: ?string}
*/
private function buildExtensionBundleUrls(array $moduleAssets, array $pluginAssets, int $version): array
{
$hasJs = static fn (array $assets): bool => ! empty(array_filter($assets, fn ($a) => ! empty($a['js'])));
$hasCss = static fn (array $assets): bool => ! empty(array_filter($assets, fn ($a) => ! empty($a['css'])));
return [
'moduleJs' => $hasJs($moduleAssets) ? "/api/modules/bundle.js?v={$version}" : null,
'moduleCss' => $hasCss($moduleAssets) ? "/api/modules/bundle.css?v={$version}" : null,
'pluginJs' => $hasJs($pluginAssets) ? "/api/plugins/bundle.js?v={$version}" : null,
'pluginCss' => $hasCss($pluginAssets) ? "/api/plugins/bundle.css?v={$version}" : null,
];
}
/** /**
* 활성화된 모듈의 프론트엔드 에셋 정보를 수집합니다. * 활성화된 모듈의 프론트엔드 에셋 정보를 수집합니다.
* *
+475
View File
@@ -0,0 +1,475 @@
<?php
namespace App\Services;
use App\Extension\ModuleManager;
use App\Extension\PluginManager;
use App\Extension\Storage\CoreStorageDriver;
use App\Extension\Traits\ClearsTemplateCaches;
use App\Http\View\Composers\TemplateComposer;
use Illuminate\Support\Facades\Log;
/**
* 확장(모듈/플러그인) 프론트엔드 IIFE/CSS 번들 병합 서비스
*
* 활성 모듈/플러그인의 개별 IIFE JS·CSS 에셋을 타입별로 하나의 번들 파일로
* 이어붙여(concat) 서빙 오버헤드(HTTP 요청 수)를 줄인다. 각 확장 IIFE 는
* 자체 클로저에서 자가등록(`window.G7ModuleRegistry`/`G7PluginRegistry` +
* 핸들러/리스너)을 수행하므로, N개 IIFE 를 priority 순으로 이어붙여 1개
* `<script>` 로 실행해도 등록 로직은 동일하게 동작한다.
*
* 정렬/필터(`hasAssets()` && strategy==='global' + `uasort(priority)`) 는
* TemplateComposer 와 공유하는 SSoT 로 이 서비스에 둔다(drift 방지).
*
* 경로는 절대경로 게터(`getBuiltAssetAbsolutePaths()`)를 재사용한다 —
* `ModuleService::getAssetFilePath()` 의 `base_path("modules/{id}/...")`
* 하드코딩을 복제하지 않아야 `_bundled` 확장에서도 정확히 읽는다(제약 4).
*
* @see TemplateComposer
*/
class ExtensionBundleService
{
// ext.cache_version 게터 재사용 — 트레이트를 use 해 self:: 로 호출(트레이트명
// 직접 정적 호출은 PHP 8.3+ deprecated). 인스턴스 캐시 무효화 메서드는 미사용.
use ClearsTemplateCaches;
/**
* 번들 캐시 파일이 저장되는 스토리지 디스크(= storage/app/ext-bundles).
*/
private const BUNDLE_DISK = 'ext-bundles';
/**
* 서비스 주입
*
* @param ModuleManager $moduleManager 모듈 매니저
* @param PluginManager $pluginManager 플러그인 매니저
*/
public function __construct(
private readonly ModuleManager $moduleManager,
private readonly PluginManager $pluginManager
) {}
/**
* 확장 타입별 global 전략 에셋을 priority 오름차순으로 정렬해 반환합니다.
*
* TemplateComposer 의 개별 에셋 URL 생성과 번들러의 concat 이 동일한
* 필터/정렬을 쓰도록 하는 SSoT. 순서 제어는 오직 manifest
* `loading.priority` 숫자 오름차순뿐이며 특정 확장 이름 하드코딩은 없다(제약 1).
*
* @param string $type 'module' | 'plugin'
* @return array<string, array{jsAbsPath: ?string, cssAbsPath: ?string, priority: int}>
* identifier => 절대경로/우선순위 (priority 오름차순 정렬)
*/
public function getOrderedGlobalAssetPaths(string $type): array
{
$extensions = $type === 'plugin'
? $this->pluginManager->getActivePlugins()
: $this->moduleManager->getActiveModules();
$ordered = [];
foreach ($extensions as $extension) {
if (! $extension->hasAssets()) {
continue;
}
$loadingConfig = $extension->getAssetLoadingConfig();
// global 전략만 번들 대상 (layout, lazy 는 레이아웃에서 개별 처리)
if (($loadingConfig['strategy'] ?? 'global') !== 'global') {
continue;
}
$absolutePaths = $extension->getBuiltAssetAbsolutePaths();
$jsAbsPath = $absolutePaths['js'] ?? null;
$cssAbsPath = $absolutePaths['css'] ?? null;
// JS/CSS 둘 다 없으면 번들에 기여할 것이 없으므로 제외
if ($jsAbsPath === null && $cssAbsPath === null) {
continue;
}
$ordered[$extension->getIdentifier()] = [
'jsAbsPath' => $jsAbsPath,
'cssAbsPath' => $cssAbsPath,
'priority' => (int) ($loadingConfig['priority'] ?? 100),
];
}
// priority 오름차순 (낮을수록 먼저) — 개별 로딩과 동일 규칙
uasort($ordered, fn ($a, $b) => $a['priority'] <=> $b['priority']);
return $ordered;
}
/**
* 확장 타입의 JS 번들 문자열을 생성합니다.
*
* priority 순으로 각 IIFE 파일을 읽어 `\n;\n` 구분자로 이어붙인다(제약 2 —
* ASI 경계 보호). 각 파일 끝의 `//# sourceMappingURL` 주석은 prod 에서는
* strip(맵 생략), dev 에서는 개별 에셋 서빙 절대 URL 로 rewrite 한다(제약 3).
*
* 확장별 fine-grained try/catch — 파일 읽기 실패 시 해당 확장만 skip +
* Log::warning, 나머지 병합 지속(한 확장 실패가 번들 전체를 붕괴시키지 않음).
*
* @param string $type 'module' | 'plugin'
* @return string 병합된 JS (활성 global 에셋이 없으면 빈 문자열)
*/
public function buildJsBundle(string $type): string
{
$ordered = $this->getOrderedGlobalAssetPaths($type);
$isProduction = app()->environment('production');
$segments = [];
foreach ($ordered as $identifier => $paths) {
if (empty($paths['jsAbsPath'])) {
continue;
}
try {
$content = @file_get_contents($paths['jsAbsPath']);
if ($content === false) {
Log::warning('확장 JS 번들 병합: 파일 읽기 실패, 해당 확장 skip', [
'type' => $type,
'identifier' => $identifier,
'path' => $paths['jsAbsPath'],
]);
continue;
}
$segments[] = $this->processJsSourceMap($content, $type, $identifier, $isProduction);
} catch (\Throwable $e) {
Log::warning('확장 JS 번들 병합 중 오류, 해당 확장 skip', [
'type' => $type,
'identifier' => $identifier,
'error' => $e->getMessage(),
]);
}
}
return implode("\n;\n", $segments);
}
/**
* 확장 타입의 CSS 번들 문자열을 생성합니다.
*
* priority 순으로 각 CSS 파일을 읽어 `\n` 구분자로 이어붙인다. 상대경로
* `url(...)` 참조가 있는 CSS 는 병합 시 경로가 깨지므로 번들에서 제외하고
* 경고 로그를 남긴다(안전장치 — 현재 번들 CSS 는 url() 0건).
*
* @param string $type 'module' | 'plugin'
* @return string 병합된 CSS (활성 global 에셋이 없으면 빈 문자열)
*/
public function buildCssBundle(string $type): string
{
$ordered = $this->getOrderedGlobalAssetPaths($type);
$segments = [];
foreach ($ordered as $identifier => $paths) {
if (empty($paths['cssAbsPath'])) {
continue;
}
try {
$content = @file_get_contents($paths['cssAbsPath']);
if ($content === false) {
Log::warning('확장 CSS 번들 병합: 파일 읽기 실패, 해당 확장 skip', [
'type' => $type,
'identifier' => $identifier,
'path' => $paths['cssAbsPath'],
]);
continue;
}
// 상대경로 url() 참조가 있으면 병합 시 폰트/이미지 경로가 깨진다.
// 절대/data URI 는 안전하므로 상대경로만 검출해 해당 CSS 제외.
if ($this->hasRelativeUrl($content)) {
Log::warning('확장 CSS 에 상대경로 url() 존재 — 번들에서 제외(개별 폴백 유지)', [
'type' => $type,
'identifier' => $identifier,
]);
continue;
}
$segments[] = $content;
} catch (\Throwable $e) {
Log::warning('확장 CSS 번들 병합 중 오류, 해당 확장 skip', [
'type' => $type,
'identifier' => $identifier,
'error' => $e->getMessage(),
]);
}
}
return implode("\n", $segments);
}
/**
* 캐시된 번들 파일의 절대 경로를 반환합니다(없으면 build → 원자적 write).
*
* 파일명에 version 을 포함(`{type}.{version}.{js|css}`)하므로 활성 조합이
* 바뀌어 version 이 bump 되면 새 파일명으로 자연 무효화된다. 프로덕션에서만
* 디스크 캐시하며, 비프로덕션(dev/watch)에서는 캐시하지 않고 매 요청 build 해
* rebuild 를 즉시 반영한다(PO 결정).
*
* @param string $type 'module' | 'plugin'
* @param string $kind 'js' | 'css'
* @param int $version 확장 캐시 버전(ClearsTemplateCaches::getExtensionCacheVersion)
* @return string 캐시(또는 방금 build 한) 파일의 절대 경로. 병합 결과가 빈 문자열이면 빈 문자열.
*/
public function getBundleFilePath(string $type, string $kind, int $version): string
{
$content = $kind === 'css'
? $this->buildCssBundle($type)
: $this->buildJsBundle($type);
// 병합할 에셋이 하나도 없으면 파일을 만들지 않는다(호출측이 빈 문자열로 판단).
if ($content === '') {
return '';
}
$storage = $this->bundleStorage();
$relativeName = $this->bundleFileName($type, $kind, $version);
// 비프로덕션은 캐시하지 않고 임시 파일로 매번 build → rebuild 즉시 반영
if (! app()->environment('production')) {
return $this->writeAtomically($storage, $relativeName, $content, cache: false);
}
// 프로덕션: 동일 version 캐시가 있으면 그대로 사용
if ($storage->exists('', $relativeName)) {
return $storage->getBasePath('').'/'.$relativeName;
}
return $this->writeAtomically($storage, $relativeName, $content, cache: true);
}
/**
* 현재 version 외의 오래된 번들 파일을 삭제하고 삭제 건수를 반환합니다.
*
* @param int $currentVersion 보존할 현재 캐시 버전
* @return int 삭제된 파일 수
*/
public function cleanupStaleBundles(int $currentVersion): int
{
$storage = $this->bundleStorage();
$deleted = 0;
foreach ($storage->files('', '') as $file) {
$name = basename($file);
// 현재 version 파일과 .gitignore 는 보존
if ($name === '.gitignore' || $this->matchesVersion($name, $currentVersion)) {
continue;
}
if ($this->isBundleFile($name) && $storage->delete('', $name)) {
$deleted++;
}
}
return $deleted;
}
/**
* 번들 캐시 파일을 삭제합니다(cache-clear 커맨드용).
*
* @param string|null $type 'module' | 'plugin' 지정 시 해당 타입만, null 이면 전체
* @return int 삭제된 파일 수
*/
public function clearBundles(?string $type = null): int
{
$storage = $this->bundleStorage();
$deleted = 0;
foreach ($storage->files('', '') as $file) {
$name = basename($file);
if ($name === '.gitignore' || ! $this->isBundleFile($name)) {
continue;
}
// 타입 필터 (파일명 접두사 `{type}.`)
if ($type !== null && ! str_starts_with($name, $type.'.')) {
continue;
}
if ($storage->delete('', $name)) {
$deleted++;
}
}
return $deleted;
}
/**
* 번들 파일명을 생성합니다(`{type}.{version}.{kind}`).
*
* @param string $type 'module' | 'plugin'
* @param string $kind 'js' | 'css'
* @param int $version 캐시 버전
* @return string 파일명 (디렉토리 제외)
*/
private function bundleFileName(string $type, string $kind, int $version): string
{
return "{$type}.{$version}.{$kind}";
}
/**
* 파일명이 번들 파일 패턴(`{type}.{version}.{kind}`)인지 확인합니다.
*
* @param string $name 파일명
* @return bool 번들 파일이면 true
*/
private function isBundleFile(string $name): bool
{
return (bool) preg_match('/^(module|plugin)\.\d+\.(js|css)$/', $name);
}
/**
* 파일명이 지정한 version 의 번들인지 확인합니다.
*
* @param string $name 파일명
* @param int $version 비교할 버전
* @return bool 해당 version 파일이면 true
*/
private function matchesVersion(string $name, int $version): bool
{
return (bool) preg_match('/^(module|plugin)\.'.preg_quote((string) $version, '/').'\.(js|css)$/', $name);
}
/**
* 병합 결과를 원자적으로(임시 파일 → rename) 기록하고 절대 경로를 반환합니다.
*
* @param CoreStorageDriver $storage 번들 디스크 스토리지
* @param string $relativeName 대상 파일명
* @param string $content 기록할 내용
* @param bool $cache true 면 version 파일명 유지, false 면 임시 파일 사용
* @return string 기록된 파일의 절대 경로
*/
private function writeAtomically(CoreStorageDriver $storage, string $relativeName, string $content, bool $cache): string
{
$basePath = $storage->getBasePath('');
if (! is_dir($basePath)) {
@mkdir($basePath, 0o755, true);
}
$finalPath = $basePath.'/'.$relativeName;
if (! $cache) {
// 비프로덕션: 매 요청 덮어써도 무방(원자성 불요), 그대로 write
$storage->put('', $relativeName, $content);
return $finalPath;
}
// 프로덕션: 임시 파일에 쓴 뒤 rename 으로 원자적 게시(부분 파일 서빙 방지)
$tmpName = $relativeName.'.tmp.'.getmypid();
$storage->put('', $tmpName, $content);
$tmpPath = $basePath.'/'.$tmpName;
if (! @rename($tmpPath, $finalPath)) {
// rename 실패 시(경합으로 이미 존재 등) 임시 파일 정리 후 최종 경로 사용
$storage->delete('', $tmpName);
}
return $finalPath;
}
/**
* IIFE 소스맵 주석을 환경에 맞게 처리합니다.
*
* prod: `//# sourceMappingURL` 라인 strip(맵 생략).
* dev: 개별 에셋 서빙 절대 URL(`/api/{type}s/assets/{id}/dist/js/*.map`)로
* rewrite → 브라우저가 확장별 원본 맵을 추적(완벽한 통합 맵은 아님).
*
* @param string $content 원본 IIFE 내용
* @param string $type 'module' | 'plugin'
* @param string $identifier 확장 식별자
* @param bool $isProduction 프로덕션 여부
* @return string 처리된 내용
*/
private function processJsSourceMap(string $content, string $type, string $identifier, bool $isProduction): string
{
// 구분자로 `~` 사용 — 패턴 자체에 `#`(`//#`)가 포함되어 `#` 구분자는 못 씀
$pattern = '~//# sourceMappingURL=(\S+)~';
if ($isProduction) {
// prod: 맵 참조 제거
return preg_replace($pattern, '', $content) ?? $content;
}
// dev: 상대 맵 파일명을 개별 에셋 서빙 절대 URL 로 rewrite
$typeSegment = $type === 'plugin' ? 'plugins' : 'modules';
return preg_replace_callback($pattern, function (array $m) use ($typeSegment, $identifier) {
$mapFile = ltrim($m[1], './');
return '//# sourceMappingURL=/api/'.$typeSegment.'/assets/'.$identifier.'/dist/js/'.basename($mapFile);
}, $content) ?? $content;
}
/**
* CSS 내용에 상대경로 url() 참조가 있는지 확인합니다.
*
* 절대 URL(http/https), 루트 절대경로(/), data URI 는 병합에 안전하므로
* 그 외의 url() 참조만 상대경로로 간주한다.
*
* @param string $css CSS 내용
* @return bool 상대경로 url() 이 하나라도 있으면 true
*/
private function hasRelativeUrl(string $css): bool
{
if (! preg_match_all('/url\(\s*[\'"]?([^\'")]+)[\'"]?\s*\)/i', $css, $matches)) {
return false;
}
foreach ($matches[1] as $url) {
$url = trim($url);
if ($url === '') {
continue;
}
$isAbsolute = str_starts_with($url, 'http://')
|| str_starts_with($url, 'https://')
|| str_starts_with($url, '//')
|| str_starts_with($url, '/')
|| str_starts_with($url, 'data:');
if (! $isAbsolute) {
return true;
}
}
return false;
}
/**
* 번들 디스크용 스토리지 드라이버를 반환합니다(StorageInterface 경유).
*
* @return CoreStorageDriver ext-bundles 디스크 스토리지
*/
private function bundleStorage(): CoreStorageDriver
{
return (new CoreStorageDriver)->withDisk(self::BUNDLE_DISK);
}
/**
* 현재 확장 캐시 버전을 반환합니다.
*
* @return int 캐시 버전
*/
public function getCurrentVersion(): int
{
return self::getExtensionCacheVersion();
}
}
+10
View File
@@ -74,6 +74,16 @@ return [
'report' => false, 'report' => false,
], ],
// 확장(모듈/플러그인) 프론트엔드 IIFE/CSS 번들 병합 결과 캐시.
// ExtensionBundleService 가 version-in-path 파일명으로 저장/서빙한다.
'ext-bundles' => [
'driver' => 'local',
'root' => storage_path('app/ext-bundles'),
'serve' => false,
'throw' => true,
'report' => false,
],
'public' => [ 'public' => [
'driver' => 'local', 'driver' => 'local',
'root' => storage_path('app/public'), 'root' => storage_path('app/public'),
+2
View File
@@ -27,6 +27,8 @@ _bundled에서 TSX/TS 파일 수정한 경우 → 빌드 후 확장 업데이
| `modules/**/resources/js/**/*.ts` (핸들러) | `module:build` + `module:update {id} --force` | | `modules/**/resources/js/**/*.ts` (핸들러) | `module:build` + `module:update {id} --force` |
| `templates/**/src/**/*.tsx` (컴포넌트) | `template:build` + `template:update {id} --force` | | `templates/**/src/**/*.tsx` (컴포넌트) | `template:build` + `template:update {id} --force` |
> **확장 프론트엔드 번들**: 활성 모듈/플러그인 IIFE 는 서버측에서 종류별 1개 번들로 병합 서빙된다(`/api/{modules,plugins}/bundle.{js,css}`). `{type}:update` 후 확장 캐시 버전이 bump 되면 번들이 자동 재생성된다(prod 캐시, dev 매 요청 concat). 구버전 번들 파일은 `ext-bundles:cleanup` 또는 `{type}:cache-clear` 로 정리. 상세: [module-assets.md](extension/module-assets.md#서버측-번들-병합).
--- ---
## 확장 업데이트 (_bundled → 활성 반영) ## 확장 업데이트 (_bundled → 활성 반영)
+56
View File
@@ -381,6 +381,62 @@ GET /api/modules/assets/{identifier}/{path}
--- ---
## 서버측 번들 병합 (Server-side Bundle)
활성 모듈/플러그인이 늘어날수록 개별 IIFE JS/CSS 요청이 선형 증가한다. 이를 줄이기 위해 코어는 타입별(모듈/플러그인)로 활성 `global` 에셋을 서버에서 하나의 번들로 병합해 서빙한다. 각 확장 IIFE 는 자체 클로저에서 자가등록(레지스트리 + 핸들러/리스너)을 수행하므로, priority 순으로 이어붙여 단일 `<script>` 로 실행해도 등록 동작은 동일하다.
### 서빙 엔드포인트
```
GET /api/modules/bundle.js?v={version}
GET /api/modules/bundle.css?v={version}
GET /api/plugins/bundle.js?v={version}
GET /api/plugins/bundle.css?v={version}
```
`{version}` = 확장 캐시 버전(`ClearsTemplateCaches::getExtensionCacheVersion()`). 활성 조합이 바뀌면 install/activate/deactivate/update 라이프사이클에서 version 이 bump 되어 새 URL → 새 캐시 파일명으로 자동 무효화된다.
### 동작 흐름
```
1. blade → window.G7Config.bundleUrls 주입 (활성 에셋 없는 타입은 null)
2. TemplateApp.loadExtensionAssets()
└─ ModuleAssetLoader.loadBundle('module', ...) → loadBundle('plugin', ...)
├─ 단일 <script async=false> + 단일 <link> append
└─ 번들 내부 물리 순서(=priority 정렬)로 IIFE 자가등록 실행
```
`bundleUrls` 가 없으면(구버전 blade) `ModuleAssetLoader.loadActiveExtensionAssets` 개별 로딩으로 폴백한다.
### 병합 규율
| 규율 | 내용 | audit 룰 |
|------|------|---------|
| priority 순서 | manifest `loading.priority` 오름차순만. 확장 이름 하드코딩 금지 | (선언형) |
| `\n;\n` 구분자 | IIFE 사이는 `\n;\n`(JS)/`\n`(CSS). 미사용 시 ASI 붕괴 → 전체 파싱 에러 | `extension-bundle-concat-separator` |
| 소스맵 | prod strip, dev 는 개별 에셋 서빙 절대 URL 로 rewrite | - |
| same-origin | 번들 URL 은 `/api/...` 만 (CDN 금지 — gdpr preblocker 자기차단 방지) | `extension-bundle-url-same-origin` |
| 절대경로 게터 | `getBuiltAssetAbsolutePaths()` 사용. `base_path("modules"\|"plugins")` 직접 조립 금지 | `extension-bundle-asset-path-getter` |
| 확장별 try/catch | 파일 읽기 실패 시 해당 확장만 skip, 나머지 병합 지속 | (메모리+회귀테스트) |
| CSS url() | 상대경로 url() 을 가진 CSS 는 번들 제외(개별 폴백) | - |
### 캐시 stale 관리
번들 파일(`storage/app/ext-bundles/{type}.{version}.{js,css}`)은 Laravel 캐시 스토어 밖 파일시스템이라 version bump/`cache:clear` 가 구파일을 지우지 않는다. 정리 경로:
```bash
php artisan ext-bundles:cleanup # 현재 version 외 구파일 삭제
php artisan module:cache-clear # 모듈 번들 파일 정리 포함
php artisan plugin:cache-clear # 플러그인 번들 파일 정리 포함
php artisan template:cache-clear # 전체 번들 파일 정리 포함
```
프로덕션은 version-in-path 디스크 캐시, 비프로덕션(dev/watch)은 캐시 없이 매 요청 concat(rebuild 즉시 반영). `_bundled` 수정 후에는 `{type}:update {id} --force` 로 활성 반영 후 version bump 로 번들이 재생성된다.
> 개별 에셋 서빙 라우트(`/api/{type}/assets/...`, `*.map` 포함)는 소스맵·static 참조를 위해 존치한다.
---
## 에셋 로딩 전략 ## 에셋 로딩 전략
### global (기본값) ### global (기본값)
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"devtools.min.js","sources":["../../../resources/js/core/devtools/__runtime-shims/G7DevToolsCore.ts","../../../resources/js/core/devtools/DiagnosticEngine.ts","../../../resources/js/core/devtools/ServerConnector.ts","../../../resources/js/core/devtools/StyleTracker.ts","../../../resources/js/core/devtools/ui/styles.ts","../../../resources/js/core/devtools/ui/constants.ts","../../../resources/js/core/devtools/ui/utils.ts","../../../resources/js/core/devtools/ui/components/JsonTreeNode.tsx","../../../resources/js/core/devtools/ui/tabs/StateTab.tsx","../../../resources/js/core/devtools/ui/tabs/ActionsTab.tsx","../../../resources/js/core/devtools/ui/tabs/CacheTab.tsx","../../../resources/js/core/devtools/ui/tabs/DiagnoseTab.tsx","../../../resources/js/core/devtools/ui/tabs/PerformanceTab.tsx","../../../resources/js/core/devtools/ui/tabs/LifecycleTab.tsx","../../../resources/js/core/devtools/ui/tabs/NetworkTab.tsx","../../../resources/js/core/devtools/ui/tabs/FormTab.tsx","../../../resources/js/core/devtools/ui/tabs/ConditionalTab.tsx","../../../resources/js/core/devtools/ui/tabs/ExpressionTab.tsx","../../../resources/js/core/devtools/ui/tabs/HandlersTab.tsx","../../../resources/js/core/devtools/ui/tabs/EventsTab.tsx","../../../resources/js/core/devtools/ui/tabs/DataSourcesTab.tsx","../../../resources/js/core/devtools/ui/tabs/RendersTab.tsx","../../../resources/js/core/devtools/ui/tabs/StylesTab.tsx","../../../resources/js/core/devtools/ui/tabs/AuthTab.tsx","../../../resources/js/core/devtools/ui/tabs/LogsTab.tsx","../../../resources/js/core/devtools/ui/tabs/LayoutTab.tsx","../../../resources/js/core/devtools/ui/tabs/ChangeDetectionTab.tsx","../../../resources/js/core/devtools/ui/tabs/StaleClosureTab.tsx","../../../resources/js/core/devtools/ui/tabs/NestedContextTab.tsx","../../../resources/js/core/devtools/ui/tabs/ModalScopeTab.tsx","../../../resources/js/core/devtools/ui/tabs/NamedActionsTab.tsx","../../../resources/js/core/devtools/ui/DevToolsPanel.tsx","../../../resources/js/core/devtools-entry.ts"],"sourcesContent":["/**\n * G7DevToolsCore 런타임 shim — DevTools lazy 번들 전용 (vite.config.devtools.js alias 대상)\n * @since engine-v1.52.0\n *\n * DevTools 추적 코어는 디버그 무관 항상 필요해 메인 번들에 남는다. 디버그 lazy 번들\n * (DevToolsPanel 등)은 이 shim 으로 메인 번들의 단일 인스턴스를 빌려 쓴다(싱글톤 동일성).\n * 값은 window.G7Core.__runtime, 타입은 원본에서 재export.\n */\n\nconst runtime = (typeof window !== 'undefined'\n ? (window as any).G7Core?.__runtime\n : undefined) as { G7DevToolsCore?: unknown } | undefined;\n\nif (!runtime?.G7DevToolsCore) {\n throw new Error(\n '[devtools] window.G7Core.__runtime.G7DevToolsCore 이 없습니다. ' +\n '코어 번들(template-engine.min.js)이 devtools 번들보다 먼저 로드되어야 합니다.'\n );\n}\n\nexport const G7DevToolsCore = runtime.G7DevToolsCore as typeof import('../G7DevToolsCore').G7DevToolsCore;\nexport default G7DevToolsCore;\n","/**\n * G7 DevTools 진단 엔진\n *\n * 증상 기반으로 템플릿 엔진 문제를 자동 진단하는 규칙 엔진\n *\n * @module DiagnosticEngine\n */\n\nimport type {\n DiagnosticRule,\n DiagnosticCategory,\n DiagnosticContext,\n DiagnosisResult,\n FixSuggestion,\n CommonIssue,\n StateSnapshot,\n ActionLog,\n CacheStats,\n StateView,\n LifecycleInfo,\n PerformanceInfo,\n NetworkInfo,\n ConditionalInfo,\n FormInfo,\n WebSocketInfo,\n} from './types';\nimport { G7DevToolsCore } from './G7DevToolsCore';\n\n/**\n * 진단 규칙 정의\n *\n * 트러블슈팅 가이드의 주요 이슈를 규칙으로 정의\n */\nconst diagnosticRules: DiagnosticRule[] = [\n // ============================================\n // 상태 관련 문제\n // ============================================\n {\n id: 'stale-closure',\n name: 'Stale Closure',\n category: 'state',\n symptoms: [\n '이전 값이 전송됨',\n '저장 시 오래된 데이터',\n 'API 호출 시 첫 값만 전송',\n '클릭할 때마다 같은 값',\n ],\n detector: (ctx) => {\n // 액션 이력에서 동일한 값이 반복되는 패턴 감지\n const recentActions = ctx.actionHistory.slice(-10);\n const apiCalls = recentActions.filter(a => a.type === 'apiCall');\n if (apiCalls.length < 2) return false;\n\n // 연속된 API 호출에서 동일한 파라미터가 사용되는지 확인\n for (let i = 1; i < apiCalls.length; i++) {\n const prevParams = JSON.stringify(apiCalls[i - 1].params);\n const currParams = JSON.stringify(apiCalls[i].params);\n if (prevParams === currParams && apiCalls[i].params) {\n return true;\n }\n }\n return fLine truncated {"version":3,"file":"devtools.min.js","sources":["../../../resources/js/core/devtools/__runtime-shims/G7DevToolsCore.ts","../../../resources/js/core/devtools/DiagnosticEngine.ts","../../../resources/js/core/devtools/ServerConnector.ts","../../../resources/js/core/devtools/StyleTracker.ts","../../../resources/js/core/devtools/ui/styles.ts","../../../resources/js/core/devtools/ui/constants.ts","../../../resources/js/core/devtools/ui/utils.ts","../../../resources/js/core/devtools/ui/components/JsonTreeNode.tsx","../../../resources/js/core/devtools/ui/tabs/StateTab.tsx","../../../resources/js/core/devtools/ui/tabs/ActionsTab.tsx","../../../resources/js/core/devtools/ui/tabs/CacheTab.tsx","../../../resources/js/core/devtools/ui/tabs/DiagnoseTab.tsx","../../../resources/js/core/devtools/ui/tabs/PerformanceTab.tsx","../../../resources/js/core/devtools/ui/tabs/LifecycleTab.tsx","../../../resources/js/core/devtools/ui/tabs/NetworkTab.tsx","../../../resources/js/core/devtools/ui/tabs/FormTab.tsx","../../../resources/js/core/devtools/ui/tabs/ConditionalTab.tsx","../../../resources/js/core/devtools/ui/tabs/ExpressionTab.tsx","../../../resources/js/core/devtools/ui/tabs/HandlersTab.tsx","../../../resources/js/core/devtools/ui/tabs/EventsTab.tsx","../../../resources/js/core/devtools/ui/tabs/DataSourcesTab.tsx","../../../resources/js/core/devtools/ui/tabs/RendersTab.tsx","../../../resources/js/core/devtools/ui/tabs/StylesTab.tsx","../../../resources/js/core/devtools/ui/tabs/AuthTab.tsx","../../../resources/js/core/devtools/ui/tabs/LogsTab.tsx","../../../resources/js/core/devtools/ui/tabs/LayoutTab.tsx","../../../resources/js/core/devtools/ui/tabs/ChangeDetectionTab.tsx","../../../resources/js/core/devtools/ui/tabs/StaleClosureTab.tsx","../../../resources/js/core/devtools/ui/tabs/NestedContextTab.tsx","../../../resources/js/core/devtools/ui/tabs/ModalScopeTab.tsx","../../../resources/js/core/devtools/ui/tabs/NamedActionsTab.tsx","../../../resources/js/core/devtools/ui/DevToolsPanel.tsx","../../../resources/js/core/devtools-entry.ts"],"sourcesContent":["/**\n * G7DevToolsCore 런타임 shim — DevTools lazy 번들 전용 (vite.config.devtools.js alias 대상)\n * @since engine-v1.51.0\n *\n * DevTools 추적 코어는 디버그 무관 항상 필요해 메인 번들에 남는다. 디버그 lazy 번들\n * (DevToolsPanel 등)은 이 shim 으로 메인 번들의 단일 인스턴스를 빌려 쓴다(싱글톤 동일성).\n * 값은 window.G7Core.__runtime, 타입은 원본에서 재export.\n */\n\nconst runtime = (typeof window !== 'undefined'\n ? (window as any).G7Core?.__runtime\n : undefined) as { G7DevToolsCore?: unknown } | undefined;\n\nif (!runtime?.G7DevToolsCore) {\n throw new Error(\n '[devtools] window.G7Core.__runtime.G7DevToolsCore 이 없습니다. ' +\n '코어 번들(template-engine.min.js)이 devtools 번들보다 먼저 로드되어야 합니다.'\n );\n}\n\nexport const G7DevToolsCore = runtime.G7DevToolsCore as typeof import('../G7DevToolsCore').G7DevToolsCore;\nexport default G7DevToolsCore;\n","/**\n * G7 DevTools 진단 엔진\n *\n * 증상 기반으로 템플릿 엔진 문제를 자동 진단하는 규칙 엔진\n *\n * @module DiagnosticEngine\n */\n\nimport type {\n DiagnosticRule,\n DiagnosticCategory,\n DiagnosticContext,\n DiagnosisResult,\n FixSuggestion,\n CommonIssue,\n StateSnapshot,\n ActionLog,\n CacheStats,\n StateView,\n LifecycleInfo,\n PerformanceInfo,\n NetworkInfo,\n ConditionalInfo,\n FormInfo,\n WebSocketInfo,\n} from './types';\nimport { G7DevToolsCore } from './G7DevToolsCore';\n\n/**\n * 진단 규칙 정의\n *\n * 트러블슈팅 가이드의 주요 이슈를 규칙으로 정의\n */\nconst diagnosticRules: DiagnosticRule[] = [\n // ============================================\n // 상태 관련 문제\n // ============================================\n {\n id: 'stale-closure',\n name: 'Stale Closure',\n category: 'state',\n symptoms: [\n '이전 값이 전송됨',\n '저장 시 오래된 데이터',\n 'API 호출 시 첫 값만 전송',\n '클릭할 때마다 같은 값',\n ],\n detector: (ctx) => {\n // 액션 이력에서 동일한 값이 반복되는 패턴 감지\n const recentActions = ctx.actionHistory.slice(-10);\n const apiCalls = recentActions.filter(a => a.type === 'apiCall');\n if (apiCalls.length < 2) return false;\n\n // 연속된 API 호출에서 동일한 파라미터가 사용되는지 확인\n for (let i = 1; i < apiCalls.length; i++) {\n const prevParams = JSON.stringify(apiCalls[i - 1].params);\n const currParams = JSON.stringify(apiCalls[i].params);\n if (prevParams === currParams && apiCalls[i].params) {\n return true;\n }\n }\n return fLine truncated
+1 -1
View File
@@ -1,4 +1,4 @@
var Rz=Object.defineProperty;var eM=(ln,i,u)=>i in ln?Rz(ln,i,{enumerable:!0,configurable:!0,writable:!0,value:u}):ln[i]=u;var Ii=(ln,i,u)=>eM(ln,typeof i!="symbol"?i+"":i,u);(function(ln,i,u,Sn){"use strict";function Lt(){const e=typeof window<"u"?window.G7Core?.__runtime:void 0;if(!e)throw new Error("[layout-editor] window.G7Core.__runtime 이 없습니다. 코어 번들(template-engine.min.js)이 편집기 번들보다 먼저 로드되어야 합니다.");return e}const Ai=Lt();Ai.TranslationProvider;const tt=Ai.useTranslation;Ai.TranslationReactContext;function rt(){return typeof window>"u"?null:window.__g7Devtools??null}function wl(e,t){const n=rt();if(!n?.trackEditorState)return;const o={templateIdentifier:e.templateIdentifier,editMode:e.editMode,selectedRoutePath:e.selectedRoute?.path??null,selectedLayoutName:e.selectedRoute?.layoutName??null,routeTreeSize:e.routeTree.length,isRouteTreeCollapsed:e.isRouteTreeCollapsed,locale:e.locale,previewDevice:e.previewDevice,previewZoom:e.previewZoom,lastAction:t,timestamp:Date.now()};try{n.trackEditorState(o)}catch{}}function Bh(){const e=rt();if(e?.clearEditorStateData)try{e.clearEditorStateData()}catch{}}function Wh(e){const t=rt();if(t?.trackEditorSampleMatch)try{t.trackEditorSampleMatch(e)}catch{}}function jh(){const e=rt();if(e?.clearEditorSampleData)try{e.clearEditorSampleData()}catch{}}function Hh(e){const t=rt();if(t?.trackEditorHistoryEntry)try{t.trackEditorHistoryEntry(e)}catch{}}function Fh(){const e=rt();if(e?.clearEditorHistoryData)try{e.clearEditorHistoryData()}catch{}}function kl(e){const t=rt();if(t?.trackEditorSelection)try{t.trackEditorSelection(e)}catch{}}function Kh(){const e=rt();if(e?.clearEditorSelectionData)try{e.clearEditorSelectionData()}catch{}}function or(e){const t=rt();if(t?.trackEditorPropertyPatch)try{t.trackEditorPropertyPatch(e)}catch{}}function Cn(e){const t=rt();if(t?.trackEditorDnd)try{t.trackEditorDnd(e)}catch{}}function Vh(){const e=rt();if(e?.clearEditorDndData)try{e.clearEditorDndData()}catch{}}function st(e){const t=rt();if(t?.trackEditorDocument)try{t.trackEditorDocument(e)}catch{}}function Uh(){const e=rt();if(e?.clearEditorDocumentData)try{e.clearEditorDocumentData()}catch{}}function qh(e){const t=rt();if(t?.trackEditorSpecMerge)try{t.trackEditorSpecMerge(e)}catch{}}function Gh(){const e=rt();if(e?.clearEditorSpecMergeData)try{e.clearEditorSpecMergeData()}catch{}}function Ti(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)>>>0;return t}function Et(e){const t=rt();if(t?.trackEditorI18n)try{t.trackEditorI18n(e)}catch{}}function Yh(){const e=rt();if(e?.clearEditorI18nData)try{e.clearEditorI18nData()}catch{}}function Sl(e){const t=rt();if(t?.trackPageState)try{t.trackPageState(e)}catch{}}function Xh(){const e=rt();if(e?.clearPageStateData)try{e.clearPageStateData()}catch{}}const Cl="g7le.routeTree.collapsed";function Jh(){if(typeof window>"u")return!1;try{return window.localStorage?.getItem(Cl)==="1"}catch{return!1}}function Zh(e){if(!(typeof window>"u"))try{window.localStorage?.setItem(Cl,e?"1":"0")}catch{}}function Qh(e,t){return{templateIdentifier:e,routeTree:[],routesError:null,selectedRoute:null,isRouteTreeCollapsed:Jh(),editMode:"route",returnRoute:null,returnEditMode:null,locale:t,previewDevice:"desktop",previewZoom:1,previewCustomWidth:1024,previewColorScheme:"light",history:{canUndo:!1,canRedo:!1},isPaletteOpen:!1,availableStates:[],activeStateId:null,layoutVersions:{},extensionVersions:{}}}function Rh(e,t){switch(t.type){case"SET_ROUTE_TREE":return{...e,routeTree:t.tree,routesError:null};case"SET_ROUTES_ERROR":return{...e,routesError:t.error};case"SELECT_ROUTE":return{...e,editMode:"route",selectedRoute:t.route,returnRoute:null,returnEditMode:null};case"TOGGLE_ROUTE_TREE":return{...e,isRouteTreeCollapsed:!e.isRouteTreeCollapsed};case"SET_LOCALE":return{...e,locale:t.locale};case"ENTER_BASE_EDIT":return{...e,editMode:"base",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,selectedRoute:{path:`__base__/${t.layoutName}`,layoutName:t.layoutName}};case"EXIT_BASE_EDIT":return{...e,editMode:"route",selectedRoute:e.returnRoute,returnRoute:null};case"ENTER_MODAL_EDIT":return{...e,editMode:"modal",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,selectedRoute:{path:`__modal__/${t.modalId}`,layoutName:t.hostLayout}};case"EXIT_MODAL_EDIT":return{...e,editMode:"route",selectedRoute:e.returnRoute,returnRoute:null};case"ENTER_EXTENSION_EDIT":return{...e,editMode:"extension",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,selectedRoute:{path:`__extension__/${t.extensionId}`,layoutName:t.extensionHost??null}};case"SET_RETURN_ROUTE":return e.editMode==="route"||e.returnRoute!==null?e:{...e,returnRoute:t.route};case"EXIT_EXTENSION_EDIT":return{...e,editMode:"route",selectedRoute:e.returnRoute,returnRoute:null};case"ENTER_ITERATION_ITEM_EDIT":return{...e,editMode:"iteration_item",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,returnEditMode:e.ediLine truncated var Rz=Object.defineProperty;var eM=(ln,i,u)=>i in ln?Rz(ln,i,{enumerable:!0,configurable:!0,writable:!0,value:u}):ln[i]=u;var Ii=(ln,i,u)=>eM(ln,typeof i!="symbol"?i+"":i,u);(function(ln,i,u,Sn){"use strict";function Lt(){const e=typeof window<"u"?window.G7Core?.__runtime:void 0;if(!e)throw new Error("[layout-editor] window.G7Core.__runtime 이 없습니다. 코어 번들(template-engine.min.js)이 편집기 번들보다 먼저 로드되어야 합니다.");return e}const Ai=Lt();Ai.TranslationProvider;const tt=Ai.useTranslation;Ai.TranslationReactContext;function rt(){return typeof window>"u"?null:window.__g7Devtools??null}function wl(e,t){const n=rt();if(!n?.trackEditorState)return;const o={templateIdentifier:e.templateIdentifier,editMode:e.editMode,selectedRoutePath:e.selectedRoute?.path??null,selectedLayoutName:e.selectedRoute?.layoutName??null,routeTreeSize:e.routeTree.length,isRouteTreeCollapsed:e.isRouteTreeCollapsed,locale:e.locale,previewDevice:e.previewDevice,previewZoom:e.previewZoom,lastAction:t,timestamp:Date.now()};try{n.trackEditorState(o)}catch{}}function Bh(){const e=rt();if(e?.clearEditorStateData)try{e.clearEditorStateData()}catch{}}function Wh(e){const t=rt();if(t?.trackEditorSampleMatch)try{t.trackEditorSampleMatch(e)}catch{}}function jh(){const e=rt();if(e?.clearEditorSampleData)try{e.clearEditorSampleData()}catch{}}function Hh(e){const t=rt();if(t?.trackEditorHistoryEntry)try{t.trackEditorHistoryEntry(e)}catch{}}function Fh(){const e=rt();if(e?.clearEditorHistoryData)try{e.clearEditorHistoryData()}catch{}}function kl(e){const t=rt();if(t?.trackEditorSelection)try{t.trackEditorSelection(e)}catch{}}function Kh(){const e=rt();if(e?.clearEditorSelectionData)try{e.clearEditorSelectionData()}catch{}}function or(e){const t=rt();if(t?.trackEditorPropertyPatch)try{t.trackEditorPropertyPatch(e)}catch{}}function Cn(e){const t=rt();if(t?.trackEditorDnd)try{t.trackEditorDnd(e)}catch{}}function Vh(){const e=rt();if(e?.clearEditorDndData)try{e.clearEditorDndData()}catch{}}function st(e){const t=rt();if(t?.trackEditorDocument)try{t.trackEditorDocument(e)}catch{}}function Uh(){const e=rt();if(e?.clearEditorDocumentData)try{e.clearEditorDocumentData()}catch{}}function qh(e){const t=rt();if(t?.trackEditorSpecMerge)try{t.trackEditorSpecMerge(e)}catch{}}function Gh(){const e=rt();if(e?.clearEditorSpecMergeData)try{e.clearEditorSpecMergeData()}catch{}}function Ti(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)>>>0;return t}function Et(e){const t=rt();if(t?.trackEditorI18n)try{t.trackEditorI18n(e)}catch{}}function Yh(){const e=rt();if(e?.clearEditorI18nData)try{e.clearEditorI18nData()}catch{}}function Sl(e){const t=rt();if(t?.trackPageState)try{t.trackPageState(e)}catch{}}function Xh(){const e=rt();if(e?.clearPageStateData)try{e.clearPageStateData()}catch{}}const Cl="g7le.routeTree.collapsed";function Jh(){if(typeof window>"u")return!1;try{return window.localStorage?.getItem(Cl)==="1"}catch{return!1}}function Zh(e){if(!(typeof window>"u"))try{window.localStorage?.setItem(Cl,e?"1":"0")}catch{}}function Qh(e,t){return{templateIdentifier:e,routeTree:[],routesError:null,selectedRoute:null,isRouteTreeCollapsed:Jh(),editMode:"route",returnRoute:null,returnEditMode:null,locale:t,previewDevice:"desktop",previewZoom:1,previewCustomWidth:1024,previewColorScheme:"light",history:{canUndo:!1,canRedo:!1},isPaletteOpen:!1,availableStates:[],activeStateId:null,layoutVersions:{},extensionVersions:{}}}function Rh(e,t){switch(t.type){case"SET_ROUTE_TREE":return{...e,routeTree:t.tree,routesError:null};case"SET_ROUTES_ERROR":return{...e,routesError:t.error};case"SELECT_ROUTE":return{...e,editMode:"route",selectedRoute:t.route,returnRoute:null,returnEditMode:null};case"TOGGLE_ROUTE_TREE":return{...e,isRouteTreeCollapsed:!e.isRouteTreeCollapsed};case"SET_LOCALE":return{...e,locale:t.locale};case"ENTER_BASE_EDIT":return{...e,editMode:"base",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,selectedRoute:{path:`__base__/${t.layoutName}`,layoutName:t.layoutName}};case"EXIT_BASE_EDIT":return{...e,editMode:"route",selectedRoute:e.returnRoute,returnRoute:null};case"ENTER_MODAL_EDIT":return{...e,editMode:"modal",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,selectedRoute:{path:`__modal__/${t.modalId}`,layoutName:t.hostLayout}};case"EXIT_MODAL_EDIT":return{...e,editMode:"route",selectedRoute:e.returnRoute,returnRoute:null};case"ENTER_EXTENSION_EDIT":return{...e,editMode:"extension",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,selectedRoute:{path:`__extension__/${t.extensionId}`,layoutName:t.extensionHost??null}};case"SET_RETURN_ROUTE":return e.editMode==="route"||e.returnRoute!==null?e:{...e,returnRoute:t.route};case"EXIT_EXTENSION_EDIT":return{...e,editMode:"route",selectedRoute:e.returnRoute,returnRoute:null};case"ENTER_ITERATION_ITEM_EDIT":return{...e,editMode:"iteration_item",returnRoute:t.returnRoute!==void 0?t.returnRoute:e.selectedRoute,returnEditMode:e.ediLine truncated
"keyword": "", "keyword": "",
"page": 1 "page": 1
}`,shapeErrorKey:"layout_editor.json_block.must_be_object",validate:_=>{const S=Object.keys(_??{}).filter(E=>!$s(E));return S.length?a("layout_editor.json_block.invalid_keys",{keys:S.join(", ")}):null}}):i.jsxs(i.Fragment,{children:[v.length===0?i.jsx("p",{"data-testid":`g7le-initstate-${e}-empty`,style:ES,children:a("layout_editor.initstate.no_values")}):v.map(_=>{const E=Ew(b,r,_)==="inherited",C=e==="isolated"&&l[_];return i.jsx(aS,{scope:e,itemKey:_,value:o[_],inherited:E,isOrphan:!!C,onChangeValue:N=>x(_,N),onRemove:()=>k(_),t:a},_)}),i.jsxs("div",{style:xS,children:[i.jsx("input",{type:"text","data-testid":`g7le-initstate-${e}-add-name`,value:d,placeholder:a("layout_editor.initstate.value_name"),onChange:_=>{c(_.target.value),y&&g(null)},onKeyDown:_=>{_.key==="Enter"&&(_.preventDefault(),w())},"aria-invalid":y?!0:void 0,style:{...wS,...y?kS:null}}),i.jsx("select",{"data-testid":`g7le-initstate-${e}-add-kind`,value:p,onChange:_=>f(_.target.value),"aria-label":a("layout_editor.initstate.value_kind"),style:CS,children:iS.map(_=>i.jsx("option",{value:_.kind,children:a(_.labelKey)},_.kind))}),i.jsxs("button",{type:"button","data-testid":`g7le-initstate-${e}-add`,onClick:w,style:$S,children:["+ ",a("layout_editor.initstate.add_value")]})]}),y?i.jsx("p",{"data-testid":`g7le-initstate-${e}-add-error`,style:SS,children:y}):null]})]})}function aS({scope:e,itemKey:t,value:n,inherited:o,isOrphan:r,onChangeValue:s,onRemove:a,t:l}){const[d,c]=u.useState(!1);let p;try{p=JSON.stringify(n,null,2)??String(n)}catch{p=String(n)}return i.jsxs("div",{"data-testid":`g7le-initstate-${e}-item-${t}`,style:yS,children:[i.jsxs("div",{style:bS,children:[o?i.jsx("span",{"data-testid":`g7le-initstate-inherited-${t}`,style:mS,children:"🔗"}):null,i.jsx("code",{style:vS,children:t}),i.jsx("span",{style:{flex:1}}),i.jsx("button",{type:"button","data-testid":`g7le-initstate-code-${t}`,onClick:()=>c(f=>!f),style:Ws,"aria-label":l("layout_editor.value_tree.show_source"),title:l("layout_editor.value_tree.show_source"),children:"</>"}),o?i.jsx("button",{type:"button","data-testid":`g7le-initstate-revert-${t}`,onClick:a,style:Ws,children:l("layout_editor.initstate.revert")}):i.jsx("button",{type:"button","data-testid":`g7le-initstate-remove-${t}`,onClick:a,style:Ws,"aria-label":l("layout_editor.init_actions.remove"),children:"✕"})]}),d?i.jsx("pre",{"data-testid":`g7le-initstate-code-block-${t}`,style:AS,children:p}):null,i.jsx(Dn,{value:n,onChange:s,t:l,path:t,scope:e}),r?i.jsxs("p",{"data-testid":`g7le-initstate-isolated-orphan-${t}`,style:_S,children:["⚠ ",l("layout_editor.initstate.isolated_orphan")]}):null]})}const lS={display:"flex",flexDirection:"column",gap:14,minWidth:0},dS={margin:0,fontSize:13,fontWeight:700,color:"#0f172a"},cS={margin:0,fontSize:11,color:"#1d4ed8",background:"#eff6ff",padding:"6px 8px",borderRadius:6},uS={display:"flex",flexDirection:"column",gap:8,padding:10,border:"1px solid #e2e8f0",borderRadius:10,minWidth:0},pS={display:"flex",alignItems:"center",justifyContent:"space-between",gap:8},fS={fontSize:12,fontWeight:700,color:"#475569"},gS={margin:0,fontSize:11,color:"#94a3b8"},hS={padding:"2px 8px",fontSize:11,border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",color:"#475569",cursor:"pointer"},yS={display:"flex",flexDirection:"column",gap:4,padding:"6px 8px",border:"1px solid #f1f5f9",borderRadius:6,minWidth:0},bS={display:"flex",alignItems:"center",gap:6},mS={fontSize:12},vS={fontSize:12,color:"#0f172a",fontFamily:"monospace"},Ws={border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",color:"#475569",cursor:"pointer",fontSize:11,padding:"2px 6px"},_S={margin:0,fontSize:11,color:"#b45309",background:"#fef3c7",padding:"4px 6px",borderRadius:6},xS={display:"flex",gap:6,alignItems:"center"},wS={padding:"4px 8px",fontSize:12,border:"1px solid #cbd5e1",borderRadius:6},kS={border:"1px solid #dc2626"},SS={margin:0,fontSize:11,color:"#dc2626"},CS={padding:"4px 8px",fontSize:12,border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",color:"#0f172a"},$S={padding:"2px 10px",fontSize:11,border:"1px dashed #94a3b8",borderRadius:6,background:"#fff",color:"#475569",cursor:"pointer"},ES={margin:0,fontSize:12,color:"#94a3b8"},IS={margin:0,fontSize:11,color:"#94a3b8"},AS={margin:"2px 0",padding:"6px 8px",fontSize:11,fontFamily:"monospace",color:"#0f172a",background:"#f1f5f9",border:"1px solid #e2e8f0",borderRadius:6,whiteSpace:"pre-wrap",wordBreak:"break-all",overflowX:"auto"},TS={self:"layout_editor.error_rows.source_self",inherited:"layout_editor.error_rows.source_inherited",template:"layout_editor.error_rows.source_template",none:"layout_editor.error_rows.source_none"};function js({value:e,onChange:t,t:n,codes:o,mode:r="local",sourceOf:s,renderActionList:a,testIdPrefix:l="g7le-error-rows"}){const d=o??Object.keys(e),c=u.useCallback((f,y)=>{t({...e,[f]:y})},[e,t]),p=u.useCallback(f=>{const y={...e};delete y[f],t(y)},[e,t]);return i.jsx("div",{className:l,"data-testid":l,children:d.map(f=>{const y=e[f],g= Line truncated }`,shapeErrorKey:"layout_editor.json_block.must_be_object",validate:_=>{const S=Object.keys(_??{}).filter(E=>!$s(E));return S.length?a("layout_editor.json_block.invalid_keys",{keys:S.join(", ")}):null}}):i.jsxs(i.Fragment,{children:[v.length===0?i.jsx("p",{"data-testid":`g7le-initstate-${e}-empty`,style:ES,children:a("layout_editor.initstate.no_values")}):v.map(_=>{const E=Ew(b,r,_)==="inherited",C=e==="isolated"&&l[_];return i.jsx(aS,{scope:e,itemKey:_,value:o[_],inherited:E,isOrphan:!!C,onChangeValue:N=>x(_,N),onRemove:()=>k(_),t:a},_)}),i.jsxs("div",{style:xS,children:[i.jsx("input",{type:"text","data-testid":`g7le-initstate-${e}-add-name`,value:d,placeholder:a("layout_editor.initstate.value_name"),onChange:_=>{c(_.target.value),y&&g(null)},onKeyDown:_=>{_.key==="Enter"&&(_.preventDefault(),w())},"aria-invalid":y?!0:void 0,style:{...wS,...y?kS:null}}),i.jsx("select",{"data-testid":`g7le-initstate-${e}-add-kind`,value:p,onChange:_=>f(_.target.value),"aria-label":a("layout_editor.initstate.value_kind"),style:CS,children:iS.map(_=>i.jsx("option",{value:_.kind,children:a(_.labelKey)},_.kind))}),i.jsxs("button",{type:"button","data-testid":`g7le-initstate-${e}-add`,onClick:w,style:$S,children:["+ ",a("layout_editor.initstate.add_value")]})]}),y?i.jsx("p",{"data-testid":`g7le-initstate-${e}-add-error`,style:SS,children:y}):null]})]})}function aS({scope:e,itemKey:t,value:n,inherited:o,isOrphan:r,onChangeValue:s,onRemove:a,t:l}){const[d,c]=u.useState(!1);let p;try{p=JSON.stringify(n,null,2)??String(n)}catch{p=String(n)}return i.jsxs("div",{"data-testid":`g7le-initstate-${e}-item-${t}`,style:yS,children:[i.jsxs("div",{style:bS,children:[o?i.jsx("span",{"data-testid":`g7le-initstate-inherited-${t}`,style:mS,children:"🔗"}):null,i.jsx("code",{style:vS,children:t}),i.jsx("span",{style:{flex:1}}),i.jsx("button",{type:"button","data-testid":`g7le-initstate-code-${t}`,onClick:()=>c(f=>!f),style:Ws,"aria-label":l("layout_editor.value_tree.show_source"),title:l("layout_editor.value_tree.show_source"),children:"</>"}),o?i.jsx("button",{type:"button","data-testid":`g7le-initstate-revert-${t}`,onClick:a,style:Ws,children:l("layout_editor.initstate.revert")}):i.jsx("button",{type:"button","data-testid":`g7le-initstate-remove-${t}`,onClick:a,style:Ws,"aria-label":l("layout_editor.init_actions.remove"),children:"✕"})]}),d?i.jsx("pre",{"data-testid":`g7le-initstate-code-block-${t}`,style:AS,children:p}):null,i.jsx(Dn,{value:n,onChange:s,t:l,path:t,scope:e}),r?i.jsxs("p",{"data-testid":`g7le-initstate-isolated-orphan-${t}`,style:_S,children:["⚠ ",l("layout_editor.initstate.isolated_orphan")]}):null]})}const lS={display:"flex",flexDirection:"column",gap:14,minWidth:0},dS={margin:0,fontSize:13,fontWeight:700,color:"#0f172a"},cS={margin:0,fontSize:11,color:"#1d4ed8",background:"#eff6ff",padding:"6px 8px",borderRadius:6},uS={display:"flex",flexDirection:"column",gap:8,padding:10,border:"1px solid #e2e8f0",borderRadius:10,minWidth:0},pS={display:"flex",alignItems:"center",justifyContent:"space-between",gap:8},fS={fontSize:12,fontWeight:700,color:"#475569"},gS={margin:0,fontSize:11,color:"#94a3b8"},hS={padding:"2px 8px",fontSize:11,border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",color:"#475569",cursor:"pointer"},yS={display:"flex",flexDirection:"column",gap:4,padding:"6px 8px",border:"1px solid #f1f5f9",borderRadius:6,minWidth:0},bS={display:"flex",alignItems:"center",gap:6},mS={fontSize:12},vS={fontSize:12,color:"#0f172a",fontFamily:"monospace"},Ws={border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",color:"#475569",cursor:"pointer",fontSize:11,padding:"2px 6px"},_S={margin:0,fontSize:11,color:"#b45309",background:"#fef3c7",padding:"4px 6px",borderRadius:6},xS={display:"flex",gap:6,alignItems:"center"},wS={padding:"4px 8px",fontSize:12,border:"1px solid #cbd5e1",borderRadius:6},kS={border:"1px solid #dc2626"},SS={margin:0,fontSize:11,color:"#dc2626"},CS={padding:"4px 8px",fontSize:12,border:"1px solid #cbd5e1",borderRadius:6,background:"#fff",color:"#0f172a"},$S={padding:"2px 10px",fontSize:11,border:"1px dashed #94a3b8",borderRadius:6,background:"#fff",color:"#475569",cursor:"pointer"},ES={margin:0,fontSize:12,color:"#94a3b8"},IS={margin:0,fontSize:11,color:"#94a3b8"},AS={margin:"2px 0",padding:"6px 8px",fontSize:11,fontFamily:"monospace",color:"#0f172a",background:"#f1f5f9",border:"1px solid #e2e8f0",borderRadius:6,whiteSpace:"pre-wrap",wordBreak:"break-all",overflowX:"auto"},TS={self:"layout_editor.error_rows.source_self",inherited:"layout_editor.error_rows.source_inherited",template:"layout_editor.error_rows.source_template",none:"layout_editor.error_rows.source_none"};function js({value:e,onChange:t,t:n,codes:o,mode:r="local",sourceOf:s,renderActionList:a,testIdPrefix:l="g7le-error-rows"}){const d=o??Object.keys(e),c=u.useCallback((f,y)=>{t({...e,[f]:y})},[e,t]),p=u.useCallback(f=>{const y={...e};delete y[f],t(y)},[e,t]);return i.jsx("div",{className:l,"data-testid":l,children:d.map(f=>{const y=e[f],g= Line truncated
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"layout-editor.min.js","sources":["../../../resources/js/core/template-engine/layout-editor/__runtime-shims/runtime.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/TranslationContext.ts","../../../resources/js/core/template-engine/layout-editor/devtools/editorTrackers.ts","../../../resources/js/core/template-engine/layout-editor/LayoutEditorContext.tsx","../../../resources/js/core/template-engine/layout-editor/LayoutDocumentContext.tsx","../../../resources/js/core/template-engine/layout-editor/EditorModalContext.tsx","../../../resources/js/core/template-engine/layout-editor/components/EditorToolbar.tsx","../../../resources/js/core/template-engine/layout-editor/utils/authToken.ts","../../../resources/js/core/template-engine/layout-editor/utils/layoutAttachments.ts","../../../resources/js/core/template-engine/layout-editor/components/property-controls/LayoutAttachmentManager.tsx","../../../resources/js/core/template-engine/layout-editor/utils/customTranslations.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/TranslationEngine.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/Logger.ts","../../../resources/js/core/template-engine/layout-editor/spec/editorSpecLoader.ts","../../../resources/js/core/template-engine/layout-editor/spec/bindingCandidates.ts","../../../resources/js/core/template-engine/layout-editor/spec/inlineBindingUtils.ts","../../../resources/js/core/template-engine/layout-editor/utils/layoutTreeUtils.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useInlineEdit.ts","../../../resources/js/core/template-engine/layout-editor/hooks/pendingCustomTranslations.ts","../../../resources/js/core/template-engine/layout-editor/components/LocaleSwitcher.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/PlaceholderChipInput.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/CustomTranslationManager.tsx","../../../resources/js/core/template-engine/layout-editor/hooks/usePageSettings.ts","../../../resources/js/core/template-engine/layout-editor/sample-data/sampleDataProvider.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/DataBindingEngine.ts","../../../resources/js/core/template-engine/layout-editor/spec/computedRecipeEngine.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useBindingCandidates.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useSeoBindingCandidates.ts","../../../resources/js/core/template-engine/layout-editor/spec/candidatePools.ts","../../../resources/js/core/template-engine/layout-editor/spec/actionRecipeEngine.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useCustomTranslation.ts","../../../resources/js/core/template-engine/layout-editor/components/property-controls/inlineBindingApi.ts","../../../resources/js/core/template-engine/layout-editor/components/property-controls/TranslationField.tsx","../../../resources/js/core/template-engine/layout-editor/components/shared/FloatingDropdown.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/InlineBindingScalarPicker.tsx","../../../resources/js/core/template-engine/layout-editor/spec/expressionValueTree.ts","../../../resources/js/core/template-engine/layout-editor/components/DropLine.tsx","../../../resources/js/core/template-engine/layout-editor/hooks/useListDragReorder.ts","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SegmentedValueEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/ConditionalValueEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/I18nTextField.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/TagInputControl.tsx","../../../resources/js/core/template-engine/layout-editor/spec/widgetRegistry.ts","../../../resources/js/core/template-engine/layout-editor/components/page-settings/MetaForm.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/FormPrimitives.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/BindingChipTextInput.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/DataChipValueInput.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/KeyValueChipEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoOgForm.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoStructuredDataEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoVarsEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoBotPreviewPanel.tsx","../../..Line truncated {"version":3,"file":"layout-editor.min.js","sources":["../../../resources/js/core/template-engine/layout-editor/__runtime-shims/runtime.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/TranslationContext.ts","../../../resources/js/core/template-engine/layout-editor/devtools/editorTrackers.ts","../../../resources/js/core/template-engine/layout-editor/LayoutEditorContext.tsx","../../../resources/js/core/template-engine/layout-editor/LayoutDocumentContext.tsx","../../../resources/js/core/template-engine/layout-editor/EditorModalContext.tsx","../../../resources/js/core/template-engine/layout-editor/components/EditorToolbar.tsx","../../../resources/js/core/template-engine/layout-editor/utils/authToken.ts","../../../resources/js/core/template-engine/layout-editor/utils/layoutAttachments.ts","../../../resources/js/core/template-engine/layout-editor/components/property-controls/LayoutAttachmentManager.tsx","../../../resources/js/core/template-engine/layout-editor/utils/customTranslations.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/TranslationEngine.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/Logger.ts","../../../resources/js/core/template-engine/layout-editor/spec/editorSpecLoader.ts","../../../resources/js/core/template-engine/layout-editor/spec/bindingCandidates.ts","../../../resources/js/core/template-engine/layout-editor/spec/inlineBindingUtils.ts","../../../resources/js/core/template-engine/layout-editor/utils/layoutTreeUtils.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useInlineEdit.ts","../../../resources/js/core/template-engine/layout-editor/hooks/pendingCustomTranslations.ts","../../../resources/js/core/template-engine/layout-editor/components/LocaleSwitcher.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/PlaceholderChipInput.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/CustomTranslationManager.tsx","../../../resources/js/core/template-engine/layout-editor/hooks/usePageSettings.ts","../../../resources/js/core/template-engine/layout-editor/sample-data/sampleDataProvider.ts","../../../resources/js/core/template-engine/layout-editor/__runtime-shims/DataBindingEngine.ts","../../../resources/js/core/template-engine/layout-editor/spec/computedRecipeEngine.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useBindingCandidates.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useSeoBindingCandidates.ts","../../../resources/js/core/template-engine/layout-editor/spec/candidatePools.ts","../../../resources/js/core/template-engine/layout-editor/spec/actionRecipeEngine.ts","../../../resources/js/core/template-engine/layout-editor/hooks/useCustomTranslation.ts","../../../resources/js/core/template-engine/layout-editor/components/property-controls/inlineBindingApi.ts","../../../resources/js/core/template-engine/layout-editor/components/property-controls/TranslationField.tsx","../../../resources/js/core/template-engine/layout-editor/components/shared/FloatingDropdown.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/InlineBindingScalarPicker.tsx","../../../resources/js/core/template-engine/layout-editor/spec/expressionValueTree.ts","../../../resources/js/core/template-engine/layout-editor/components/DropLine.tsx","../../../resources/js/core/template-engine/layout-editor/hooks/useListDragReorder.ts","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SegmentedValueEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/ConditionalValueEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/I18nTextField.tsx","../../../resources/js/core/template-engine/layout-editor/components/property-controls/TagInputControl.tsx","../../../resources/js/core/template-engine/layout-editor/spec/widgetRegistry.ts","../../../resources/js/core/template-engine/layout-editor/components/page-settings/MetaForm.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/FormPrimitives.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/BindingChipTextInput.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/DataChipValueInput.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/KeyValueChipEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoOgForm.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoStructuredDataEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoVarsEditor.tsx","../../../resources/js/core/template-engine/layout-editor/components/page-settings/SeoBotPreviewPanel.tsx","../../..Line truncated
+22 -22
View File
@@ -1,4 +1,4 @@
var ex=Object.defineProperty;var tx=(Gt,Ka,Wa)=>Ka in Gt?ex(Gt,Ka,{enumerable:!0,configurable:!0,writable:!0,value:Wa}):Gt[Ka]=Wa;var $=(Gt,Ka,Wa)=>tx(Gt,typeof Ka!="symbol"?Ka+"":Ka,Wa);(function(Gt){"use strict";function Ka(l,e){for(var a=0;a<e.length;a++){const r=e[a];if(typeof r!="string"&&!Array.isArray(r)){for(const i in r)if(i!=="default"&&!(i in l)){const o=Object.getOwnPropertyDescriptor(r,i);o&&Object.defineProperty(l,i,o.get?o:{enumerable:!0,get:()=>r[i]})}}}return Object.freeze(Object.defineProperty(l,Symbol.toStringTag,{value:"Module"}))}function Wa(l){return l&&l.__esModule&&Object.prototype.hasOwnProperty.call(l,"default")?l.default:l}var zu={exports:{}},Fe={};/** var tx=Object.defineProperty;var nx=(Vt,Ka,Wa)=>Ka in Vt?tx(Vt,Ka,{enumerable:!0,configurable:!0,writable:!0,value:Wa}):Vt[Ka]=Wa;var $=(Vt,Ka,Wa)=>nx(Vt,typeof Ka!="symbol"?Ka+"":Ka,Wa);(function(Vt){"use strict";function Ka(l,e){for(var a=0;a<e.length;a++){const r=e[a];if(typeof r!="string"&&!Array.isArray(r)){for(const i in r)if(i!=="default"&&!(i in l)){const o=Object.getOwnPropertyDescriptor(r,i);o&&Object.defineProperty(l,i,o.get?o:{enumerable:!0,get:()=>r[i]})}}}return Object.freeze(Object.defineProperty(l,Symbol.toStringTag,{value:"Module"}))}function Wa(l){return l&&l.__esModule&&Object.prototype.hasOwnProperty.call(l,"default")?l.default:l}var zu={exports:{}},Fe={};/**
* @license React * @license React
* react.production.js * react.production.js
* *
@@ -6,7 +6,7 @@ var ex=Object.defineProperty;var tx=(Gt,Ka,Wa)=>Ka in Gt?ex(Gt,Ka,{enumerable:!0
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/var dg;function rS(){if(dg)return Fe;dg=1;var l=Symbol.for("react.transitional.element"),e=Symbol.for("react.portal"),a=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),o=Symbol.for("react.consumer"),u=Symbol.for("react.context"),d=Symbol.for("react.forward_ref"),f=Symbol.for("react.suspense"),g=Symbol.for("react.memo"),m=Symbol.for("react.lazy"),b=Symbol.for("react.activity"),v=Symbol.iterator;function E(x){return x===null||typeof x!="object"?null:(x=v&&x[v]||x["@@iterator"],typeof x=="function"?x:null)}var S={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},A=Object.assign,T={};function D(x,F,ue){this.props=x,this.context=F,this.refs=T,this.updater=ue||S}D.prototype.isReactComponent={},D.prototype.setState=function(x,F){if(typeof x!="object"&&typeof x!="function"&&x!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,x,F,"setState")},D.prototype.forceUpdate=function(x){this.updater.enqueueForceUpdate(this,x,"forceUpdate")};function M(){}M.prototype=D.prototype;function O(x,F,ue){this.props=x,this.context=F,this.refs=T,this.updater=ue||S}var L=O.prototype=new M;L.constructor=O,A(L,D.prototype),L.isPureReactComponent=!0;var P=Array.isArray;function U(){}var B={H:null,A:null,T:null,S:null},Y=Object.prototype.hasOwnProperty;function ge(x,F,ue){var fe=ue.ref;return{$$typeof:l,type:x,key:F,ref:fe!==void 0?fe:null,props:ue}}function Ae(x,F){return ge(x.type,F,x.props)}function Oe(x){return typeof x=="object"&&x!==null&&x.$$typeof===l}function Ne(x){var F={"=":"=0",":":"=2"};return"$"+x.replace(/[=:]/g,function(ue){return F[ue]})}var He=/\/+/g;function Ze(x,F){return typeof x=="object"&&x!==null&&x.key!=null?Ne(""+x.key):F.toString(36)}function pt(x){switch(x.status){case"fulfilled":return x.value;case"rejected":throw x.reason;default:switch(typeof x.status=="string"?x.then(U,U):(x.status="pending",x.then(function(F){x.status==="pending"&&(x.status="fulfilled",x.value=F)},function(F){x.status==="pending"&&(x.status="rejected",x.reason=F)})),x.status){case"fulfilled":return x.value;case"rejected":throw x.reason}}throw x}function J(x,F,ue,fe,te){var ye=typeof x;(ye==="undefined"||ye==="boolean")&&(x=null);var je=!1;if(x===null)je=!0;else switch(ye){case"bigint":case"string":case"number":je=!0;break;case"object":switch(x.$$typeof){case l:case e:je=!0;break;case m:return je=x._init,J(je(x._payload),F,ue,fe,te)}}if(je)return te=te(x),je=fe===""?"."+Ze(x,0):fe,P(te)?(ue="",je!=null&&(ue=je.replace(He,"$&/")+"/"),J(te,F,ue,"",function(Ie){return Ie})):te!=null&&(Oe(te)&&(te=Ae(te,ue+(te.key==null||x&&x.key===te.key?"":(""+te.key).replace(He,"$&/")+"/")+je)),F.push(te)),1;je=0;var Me=fe===""?".":fe+":";if(P(x))for(var Pe=0;Pe<x.length;Pe++)fe=x[Pe],ye=Me+Ze(fe,Pe),je+=J(fe,F,ue,ye,te);else if(Pe=E(x),typeof Pe=="function")for(x=Pe.call(x),Pe=0;!(fe=x.next()).done;)fe=fe.value,ye=Me+Ze(fe,Pe++),je+=J(fe,F,ue,ye,te);else if(ye==="object"){if(typeof x.then=="function")return J(pt(x),F,ue,fe,te);throw F=String(x),Error("Objects are not valid as a React child (found: "+(F==="[object Object]"?"object with keys {"+Object.keys(x).join(", ")+"}":F)+"). If you meant to render a collection of children, use an array instead.")}return je}function de(x,F,ue){if(x==null)return x;var fe=[],te=0;return J(x,fe,"","",function(ye){return F.call(ue,ye,te++)}),fe}function me(x){if(x._status===-1){var F=x._result;F=F(),F.then(function(ue){(x._status===0||x._status===-1)&&(x._status=1,x._result=ue)},function(ue){(x._status===0||x._status===-1)&&(x._status=2,x._result=ue)}),x._status===-1&&(x._status=0,x._result=F)}if(x._status===1)return x._result.default;throw x._result}var ne=typeof reportError=="function"?reportError:function(x){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var F=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof x=="object"&&x!==null&&typeof x.message=="string"?String(x.message):String(x),error:x});if(!window.dispatchEvent(F))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",x);return}console.error(x)},pe={map:de,forEach:function(x,F,ue){de(x,function(){F.apply(this,arguments)},ue)},count:function(x){var F=0;return de(x,function(){F++}),F},toArray:function(x){return de(x,function(F){return F})||[]},only:function(x){if(!Oe(x))throw Error("React.Children.only expected to receive a single React element child.");return x}};return Fe.Activity=b,Fe.Children=pe,Fe.Component=D,Fe.Fragment=a,Fe.Profiler=i,Fe.PureComponent=O,Fe.StrictMode=r,Fe.Suspense=f,Fe.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=B,Fe.__COMPILER_RUNTIME={__proto__:null,c:function(x){return B.H.useMemoCache(x)}},Fe.cache=function(x){return function(){return x.apply(null,arguments)}},Fe.cacheSignal=function(){return null},Line truncated */var dg;function iS(){if(dg)return Fe;dg=1;var l=Symbol.for("react.transitional.element"),e=Symbol.for("react.portal"),a=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),o=Symbol.for("react.consumer"),u=Symbol.for("react.context"),d=Symbol.for("react.forward_ref"),f=Symbol.for("react.suspense"),g=Symbol.for("react.memo"),m=Symbol.for("react.lazy"),b=Symbol.for("react.activity"),v=Symbol.iterator;function E(x){return x===null||typeof x!="object"?null:(x=v&&x[v]||x["@@iterator"],typeof x=="function"?x:null)}var S={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},A=Object.assign,T={};function D(x,F,ue){this.props=x,this.context=F,this.refs=T,this.updater=ue||S}D.prototype.isReactComponent={},D.prototype.setState=function(x,F){if(typeof x!="object"&&typeof x!="function"&&x!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,x,F,"setState")},D.prototype.forceUpdate=function(x){this.updater.enqueueForceUpdate(this,x,"forceUpdate")};function M(){}M.prototype=D.prototype;function O(x,F,ue){this.props=x,this.context=F,this.refs=T,this.updater=ue||S}var L=O.prototype=new M;L.constructor=O,A(L,D.prototype),L.isPureReactComponent=!0;var P=Array.isArray;function U(){}var B={H:null,A:null,T:null,S:null},Y=Object.prototype.hasOwnProperty;function ge(x,F,ue){var fe=ue.ref;return{$$typeof:l,type:x,key:F,ref:fe!==void 0?fe:null,props:ue}}function Ae(x,F){return ge(x.type,F,x.props)}function Oe(x){return typeof x=="object"&&x!==null&&x.$$typeof===l}function Ne(x){var F={"=":"=0",":":"=2"};return"$"+x.replace(/[=:]/g,function(ue){return F[ue]})}var He=/\/+/g;function Ze(x,F){return typeof x=="object"&&x!==null&&x.key!=null?Ne(""+x.key):F.toString(36)}function pt(x){switch(x.status){case"fulfilled":return x.value;case"rejected":throw x.reason;default:switch(typeof x.status=="string"?x.then(U,U):(x.status="pending",x.then(function(F){x.status==="pending"&&(x.status="fulfilled",x.value=F)},function(F){x.status==="pending"&&(x.status="rejected",x.reason=F)})),x.status){case"fulfilled":return x.value;case"rejected":throw x.reason}}throw x}function Q(x,F,ue,fe,te){var ye=typeof x;(ye==="undefined"||ye==="boolean")&&(x=null);var je=!1;if(x===null)je=!0;else switch(ye){case"bigint":case"string":case"number":je=!0;break;case"object":switch(x.$$typeof){case l:case e:je=!0;break;case m:return je=x._init,Q(je(x._payload),F,ue,fe,te)}}if(je)return te=te(x),je=fe===""?"."+Ze(x,0):fe,P(te)?(ue="",je!=null&&(ue=je.replace(He,"$&/")+"/"),Q(te,F,ue,"",function(Ie){return Ie})):te!=null&&(Oe(te)&&(te=Ae(te,ue+(te.key==null||x&&x.key===te.key?"":(""+te.key).replace(He,"$&/")+"/")+je)),F.push(te)),1;je=0;var Me=fe===""?".":fe+":";if(P(x))for(var Pe=0;Pe<x.length;Pe++)fe=x[Pe],ye=Me+Ze(fe,Pe),je+=Q(fe,F,ue,ye,te);else if(Pe=E(x),typeof Pe=="function")for(x=Pe.call(x),Pe=0;!(fe=x.next()).done;)fe=fe.value,ye=Me+Ze(fe,Pe++),je+=Q(fe,F,ue,ye,te);else if(ye==="object"){if(typeof x.then=="function")return Q(pt(x),F,ue,fe,te);throw F=String(x),Error("Objects are not valid as a React child (found: "+(F==="[object Object]"?"object with keys {"+Object.keys(x).join(", ")+"}":F)+"). If you meant to render a collection of children, use an array instead.")}return je}function de(x,F,ue){if(x==null)return x;var fe=[],te=0;return Q(x,fe,"","",function(ye){return F.call(ue,ye,te++)}),fe}function me(x){if(x._status===-1){var F=x._result;F=F(),F.then(function(ue){(x._status===0||x._status===-1)&&(x._status=1,x._result=ue)},function(ue){(x._status===0||x._status===-1)&&(x._status=2,x._result=ue)}),x._status===-1&&(x._status=0,x._result=F)}if(x._status===1)return x._result.default;throw x._result}var ne=typeof reportError=="function"?reportError:function(x){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var F=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof x=="object"&&x!==null&&typeof x.message=="string"?String(x.message):String(x),error:x});if(!window.dispatchEvent(F))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",x);return}console.error(x)},pe={map:de,forEach:function(x,F,ue){de(x,function(){F.apply(this,arguments)},ue)},count:function(x){var F=0;return de(x,function(){F++}),F},toArray:function(x){return de(x,function(F){return F})||[]},only:function(x){if(!Oe(x))throw Error("React.Children.only expected to receive a single React element child.");return x}};return Fe.Activity=b,Fe.Children=pe,Fe.Component=D,Fe.Fragment=a,Fe.Profiler=i,Fe.PureComponent=O,Fe.StrictMode=r,Fe.Suspense=f,Fe.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=B,Fe.__COMPILER_RUNTIME={__proto__:null,c:function(x){return B.H.useMemoCache(x)}},Fe.cache=function(x){return function(){return x.apply(null,arguments)}},Fe.cacheSignal=function(){return null},Line truncated
* @license React * @license React
* scheduler.production.js * scheduler.production.js
* *
@@ -14,7 +14,7 @@ var ex=Object.defineProperty;var tx=(Gt,Ka,Wa)=>Ka in Gt?ex(Gt,Ka,{enumerable:!0
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/var hg;function iS(){return hg||(hg=1,(function(l){function e(J,de){var me=J.length;J.push(de);e:for(;0<me;){var ne=me-1>>>1,pe=J[ne];if(0<i(pe,de))J[ne]=de,J[me]=pe,me=ne;else break e}}function a(J){return J.length===0?null:J[0]}function r(J){if(J.length===0)return null;var de=J[0],me=J.pop();if(me!==de){J[0]=me;e:for(var ne=0,pe=J.length,x=pe>>>1;ne<x;){var F=2*(ne+1)-1,ue=J[F],fe=F+1,te=J[fe];if(0>i(ue,me))fe<pe&&0>i(te,ue)?(J[ne]=te,J[fe]=me,ne=fe):(J[ne]=ue,J[F]=me,ne=F);else if(fe<pe&&0>i(te,me))J[ne]=te,J[fe]=me,ne=fe;else break e}}return de}function i(J,de){var me=J.sortIndex-de.sortIndex;return me!==0?me:J.id-de.id}if(l.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var o=performance;l.unstable_now=function(){return o.now()}}else{var u=Date,d=u.now();l.unstable_now=function(){return u.now()-d}}var f=[],g=[],m=1,b=null,v=3,E=!1,S=!1,A=!1,T=!1,D=typeof setTimeout=="function"?setTimeout:null,M=typeof clearTimeout=="function"?clearTimeout:null,O=typeof setImmediate<"u"?setImmediate:null;function L(J){for(var de=a(g);de!==null;){if(de.callback===null)r(g);else if(de.startTime<=J)r(g),de.sortIndex=de.expirationTime,e(f,de);else break;de=a(g)}}function P(J){if(A=!1,L(J),!S)if(a(f)!==null)S=!0,U||(U=!0,Ne());else{var de=a(g);de!==null&&pt(P,de.startTime-J)}}var U=!1,B=-1,Y=5,ge=-1;function Ae(){return T?!0:!(l.unstable_now()-ge<Y)}function Oe(){if(T=!1,U){var J=l.unstable_now();ge=J;var de=!0;try{e:{S=!1,A&&(A=!1,M(B),B=-1),E=!0;var me=v;try{t:{for(L(J),b=a(f);b!==null&&!(b.expirationTime>J&&Ae());){var ne=b.callback;if(typeof ne=="function"){b.callback=null,v=b.priorityLevel;var pe=ne(b.expirationTime<=J);if(J=l.unstable_now(),typeof pe=="function"){b.callback=pe,L(J),de=!0;break t}b===a(f)&&r(f),L(J)}else r(f);b=a(f)}if(b!==null)de=!0;else{var x=a(g);x!==null&&pt(P,x.startTime-J),de=!1}}break e}finally{b=null,v=me,E=!1}de=void 0}}finally{de?Ne():U=!1}}}var Ne;if(typeof O=="function")Ne=function(){O(Oe)};else if(typeof MessageChannel<"u"){var He=new MessageChannel,Ze=He.port2;He.port1.onmessage=Oe,Ne=function(){Ze.postMessage(null)}}else Ne=function(){D(Oe,0)};function pt(J,de){B=D(function(){J(l.unstable_now())},de)}l.unstable_IdlePriority=5,l.unstable_ImmediatePriority=1,l.unstable_LowPriority=4,l.unstable_NormalPriority=3,l.unstable_Profiling=null,l.unstable_UserBlockingPriority=2,l.unstable_cancelCallback=function(J){J.callback=null},l.unstable_forceFrameRate=function(J){0>J||125<J?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):Y=0<J?Math.floor(1e3/J):5},l.unstable_getCurrentPriorityLevel=function(){return v},l.unstable_next=function(J){switch(v){case 1:case 2:case 3:var de=3;break;default:de=v}var me=v;v=de;try{return J()}finally{v=me}},l.unstable_requestPaint=function(){T=!0},l.unstable_runWithPriority=function(J,de){switch(J){case 1:case 2:case 3:case 4:case 5:break;default:J=3}var me=v;v=J;try{return de()}finally{v=me}},l.unstable_scheduleCallback=function(J,de,me){var ne=l.unstable_now();switch(typeof me=="object"&&me!==null?(me=me.delay,me=typeof me=="number"&&0<me?ne+me:ne):me=ne,J){case 1:var pe=-1;break;case 2:pe=250;break;case 5:pe=1073741823;break;case 4:pe=1e4;break;default:pe=5e3}return pe=me+pe,J={id:m++,callback:de,priorityLevel:J,startTime:me,expirationTime:pe,sortIndex:-1},me>ne?(J.sortIndex=me,e(g,J),a(f)===null&&J===a(g)&&(A?(M(B),B=-1):A=!0,pt(P,me-ne))):(J.sortIndex=pe,e(f,J),S||E||(S=!0,U||(U=!0,Ne()))),J},l.unstable_shouldYield=Ae,l.unstable_wrapCallback=function(J){var de=v;return function(){var me=v;v=de;try{return J.apply(this,arguments)}finally{v=me}}}})(Bu)),Bu}var gg;function sS(){return gg||(gg=1,Uu.exports=iS()),Uu.exports}var qu={exports:{}},gn={};/** */var hg;function sS(){return hg||(hg=1,(function(l){function e(Q,de){var me=Q.length;Q.push(de);e:for(;0<me;){var ne=me-1>>>1,pe=Q[ne];if(0<i(pe,de))Q[ne]=de,Q[me]=pe,me=ne;else break e}}function a(Q){return Q.length===0?null:Q[0]}function r(Q){if(Q.length===0)return null;var de=Q[0],me=Q.pop();if(me!==de){Q[0]=me;e:for(var ne=0,pe=Q.length,x=pe>>>1;ne<x;){var F=2*(ne+1)-1,ue=Q[F],fe=F+1,te=Q[fe];if(0>i(ue,me))fe<pe&&0>i(te,ue)?(Q[ne]=te,Q[fe]=me,ne=fe):(Q[ne]=ue,Q[F]=me,ne=F);else if(fe<pe&&0>i(te,me))Q[ne]=te,Q[fe]=me,ne=fe;else break e}}return de}function i(Q,de){var me=Q.sortIndex-de.sortIndex;return me!==0?me:Q.id-de.id}if(l.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var o=performance;l.unstable_now=function(){return o.now()}}else{var u=Date,d=u.now();l.unstable_now=function(){return u.now()-d}}var f=[],g=[],m=1,b=null,v=3,E=!1,S=!1,A=!1,T=!1,D=typeof setTimeout=="function"?setTimeout:null,M=typeof clearTimeout=="function"?clearTimeout:null,O=typeof setImmediate<"u"?setImmediate:null;function L(Q){for(var de=a(g);de!==null;){if(de.callback===null)r(g);else if(de.startTime<=Q)r(g),de.sortIndex=de.expirationTime,e(f,de);else break;de=a(g)}}function P(Q){if(A=!1,L(Q),!S)if(a(f)!==null)S=!0,U||(U=!0,Ne());else{var de=a(g);de!==null&&pt(P,de.startTime-Q)}}var U=!1,B=-1,Y=5,ge=-1;function Ae(){return T?!0:!(l.unstable_now()-ge<Y)}function Oe(){if(T=!1,U){var Q=l.unstable_now();ge=Q;var de=!0;try{e:{S=!1,A&&(A=!1,M(B),B=-1),E=!0;var me=v;try{t:{for(L(Q),b=a(f);b!==null&&!(b.expirationTime>Q&&Ae());){var ne=b.callback;if(typeof ne=="function"){b.callback=null,v=b.priorityLevel;var pe=ne(b.expirationTime<=Q);if(Q=l.unstable_now(),typeof pe=="function"){b.callback=pe,L(Q),de=!0;break t}b===a(f)&&r(f),L(Q)}else r(f);b=a(f)}if(b!==null)de=!0;else{var x=a(g);x!==null&&pt(P,x.startTime-Q),de=!1}}break e}finally{b=null,v=me,E=!1}de=void 0}}finally{de?Ne():U=!1}}}var Ne;if(typeof O=="function")Ne=function(){O(Oe)};else if(typeof MessageChannel<"u"){var He=new MessageChannel,Ze=He.port2;He.port1.onmessage=Oe,Ne=function(){Ze.postMessage(null)}}else Ne=function(){D(Oe,0)};function pt(Q,de){B=D(function(){Q(l.unstable_now())},de)}l.unstable_IdlePriority=5,l.unstable_ImmediatePriority=1,l.unstable_LowPriority=4,l.unstable_NormalPriority=3,l.unstable_Profiling=null,l.unstable_UserBlockingPriority=2,l.unstable_cancelCallback=function(Q){Q.callback=null},l.unstable_forceFrameRate=function(Q){0>Q||125<Q?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):Y=0<Q?Math.floor(1e3/Q):5},l.unstable_getCurrentPriorityLevel=function(){return v},l.unstable_next=function(Q){switch(v){case 1:case 2:case 3:var de=3;break;default:de=v}var me=v;v=de;try{return Q()}finally{v=me}},l.unstable_requestPaint=function(){T=!0},l.unstable_runWithPriority=function(Q,de){switch(Q){case 1:case 2:case 3:case 4:case 5:break;default:Q=3}var me=v;v=Q;try{return de()}finally{v=me}},l.unstable_scheduleCallback=function(Q,de,me){var ne=l.unstable_now();switch(typeof me=="object"&&me!==null?(me=me.delay,me=typeof me=="number"&&0<me?ne+me:ne):me=ne,Q){case 1:var pe=-1;break;case 2:pe=250;break;case 5:pe=1073741823;break;case 4:pe=1e4;break;default:pe=5e3}return pe=me+pe,Q={id:m++,callback:de,priorityLevel:Q,startTime:me,expirationTime:pe,sortIndex:-1},me>ne?(Q.sortIndex=me,e(g,Q),a(f)===null&&Q===a(g)&&(A?(M(B),B=-1):A=!0,pt(P,me-ne))):(Q.sortIndex=pe,e(f,Q),S||E||(S=!0,U||(U=!0,Ne()))),Q},l.unstable_shouldYield=Ae,l.unstable_wrapCallback=function(Q){var de=v;return function(){var me=v;v=de;try{return Q.apply(this,arguments)}finally{v=me}}}})(Bu)),Bu}var gg;function oS(){return gg||(gg=1,Uu.exports=sS()),Uu.exports}var qu={exports:{}},pn={};/**
* @license React * @license React
* react-dom.production.js * react-dom.production.js
* *
@@ -22,7 +22,7 @@ var ex=Object.defineProperty;var tx=(Gt,Ka,Wa)=>Ka in Gt?ex(Gt,Ka,{enumerable:!0
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/var pg;function oS(){if(pg)return gn;pg=1;var l=Iu();function e(f){var g="https://react.dev/errors/"+f;if(1<arguments.length){g+="?args[]="+encodeURIComponent(arguments[1]);for(var m=2;m<arguments.length;m++)g+="&args[]="+encodeURIComponent(arguments[m])}return"Minified React error #"+f+"; visit "+g+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function a(){}var r={d:{f:a,r:function(){throw Error(e(522))},D:a,C:a,L:a,m:a,X:a,S:a,M:a},p:0,findDOMNode:null},i=Symbol.for("react.portal");function o(f,g,m){var b=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:i,key:b==null?null:""+b,children:f,containerInfo:g,implementation:m}}var u=l.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function d(f,g){if(f==="font")return"";if(typeof g=="string")return g==="use-credentials"?g:""}return gn.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=r,gn.createPortal=function(f,g){var m=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!g||g.nodeType!==1&&g.nodeType!==9&&g.nodeType!==11)throw Error(e(299));return o(f,g,null,m)},gn.flushSync=function(f){var g=u.T,m=r.p;try{if(u.T=null,r.p=2,f)return f()}finally{u.T=g,r.p=m,r.d.f()}},gn.preconnect=function(f,g){typeof f=="string"&&(g?(g=g.crossOrigin,g=typeof g=="string"?g==="use-credentials"?g:"":void 0):g=null,r.d.C(f,g))},gn.prefetchDNS=function(f){typeof f=="string"&&r.d.D(f)},gn.preinit=function(f,g){if(typeof f=="string"&&g&&typeof g.as=="string"){var m=g.as,b=d(m,g.crossOrigin),v=typeof g.integrity=="string"?g.integrity:void 0,E=typeof g.fetchPriority=="string"?g.fetchPriority:void 0;m==="style"?r.d.S(f,typeof g.precedence=="string"?g.precedence:void 0,{crossOrigin:b,integrity:v,fetchPriority:E}):m==="script"&&r.d.X(f,{crossOrigin:b,integrity:v,fetchPriority:E,nonce:typeof g.nonce=="string"?g.nonce:void 0})}},gn.preinitModule=function(f,g){if(typeof f=="string")if(typeof g=="object"&&g!==null){if(g.as==null||g.as==="script"){var m=d(g.as,g.crossOrigin);r.d.M(f,{crossOrigin:m,integrity:typeof g.integrity=="string"?g.integrity:void 0,nonce:typeof g.nonce=="string"?g.nonce:void 0})}}else g==null&&r.d.M(f)},gn.preload=function(f,g){if(typeof f=="string"&&typeof g=="object"&&g!==null&&typeof g.as=="string"){var m=g.as,b=d(m,g.crossOrigin);r.d.L(f,m,{crossOrigin:b,integrity:typeof g.integrity=="string"?g.integrity:void 0,nonce:typeof g.nonce=="string"?g.nonce:void 0,type:typeof g.type=="string"?g.type:void 0,fetchPriority:typeof g.fetchPriority=="string"?g.fetchPriority:void 0,referrerPolicy:typeof g.referrerPolicy=="string"?g.referrerPolicy:void 0,imageSrcSet:typeof g.imageSrcSet=="string"?g.imageSrcSet:void 0,imageSizes:typeof g.imageSizes=="string"?g.imageSizes:void 0,media:typeof g.media=="string"?g.media:void 0})}},gn.preloadModule=function(f,g){if(typeof f=="string")if(g){var m=d(g.as,g.crossOrigin);r.d.m(f,{as:typeof g.as=="string"&&g.as!=="script"?g.as:void 0,crossOrigin:m,integrity:typeof g.integrity=="string"?g.integrity:void 0})}else r.d.m(f)},gn.requestFormReset=function(f){r.d.r(f)},gn.unstable_batchedUpdates=function(f,g){return f(g)},gn.useFormState=function(f,g,m){return u.H.useFormState(f,g,m)},gn.useFormStatus=function(){return u.H.useHostTransitionStatus()},gn.version="19.2.0",gn}var mg;function yg(){if(mg)return qu.exports;mg=1;function l(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(l)}catch(e){console.error(e)}}return l(),qu.exports=oS(),qu.exports}/** */var pg;function lS(){if(pg)return pn;pg=1;var l=Iu();function e(f){var g="https://react.dev/errors/"+f;if(1<arguments.length){g+="?args[]="+encodeURIComponent(arguments[1]);for(var m=2;m<arguments.length;m++)g+="&args[]="+encodeURIComponent(arguments[m])}return"Minified React error #"+f+"; visit "+g+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function a(){}var r={d:{f:a,r:function(){throw Error(e(522))},D:a,C:a,L:a,m:a,X:a,S:a,M:a},p:0,findDOMNode:null},i=Symbol.for("react.portal");function o(f,g,m){var b=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:i,key:b==null?null:""+b,children:f,containerInfo:g,implementation:m}}var u=l.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function d(f,g){if(f==="font")return"";if(typeof g=="string")return g==="use-credentials"?g:""}return pn.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=r,pn.createPortal=function(f,g){var m=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!g||g.nodeType!==1&&g.nodeType!==9&&g.nodeType!==11)throw Error(e(299));return o(f,g,null,m)},pn.flushSync=function(f){var g=u.T,m=r.p;try{if(u.T=null,r.p=2,f)return f()}finally{u.T=g,r.p=m,r.d.f()}},pn.preconnect=function(f,g){typeof f=="string"&&(g?(g=g.crossOrigin,g=typeof g=="string"?g==="use-credentials"?g:"":void 0):g=null,r.d.C(f,g))},pn.prefetchDNS=function(f){typeof f=="string"&&r.d.D(f)},pn.preinit=function(f,g){if(typeof f=="string"&&g&&typeof g.as=="string"){var m=g.as,b=d(m,g.crossOrigin),v=typeof g.integrity=="string"?g.integrity:void 0,E=typeof g.fetchPriority=="string"?g.fetchPriority:void 0;m==="style"?r.d.S(f,typeof g.precedence=="string"?g.precedence:void 0,{crossOrigin:b,integrity:v,fetchPriority:E}):m==="script"&&r.d.X(f,{crossOrigin:b,integrity:v,fetchPriority:E,nonce:typeof g.nonce=="string"?g.nonce:void 0})}},pn.preinitModule=function(f,g){if(typeof f=="string")if(typeof g=="object"&&g!==null){if(g.as==null||g.as==="script"){var m=d(g.as,g.crossOrigin);r.d.M(f,{crossOrigin:m,integrity:typeof g.integrity=="string"?g.integrity:void 0,nonce:typeof g.nonce=="string"?g.nonce:void 0})}}else g==null&&r.d.M(f)},pn.preload=function(f,g){if(typeof f=="string"&&typeof g=="object"&&g!==null&&typeof g.as=="string"){var m=g.as,b=d(m,g.crossOrigin);r.d.L(f,m,{crossOrigin:b,integrity:typeof g.integrity=="string"?g.integrity:void 0,nonce:typeof g.nonce=="string"?g.nonce:void 0,type:typeof g.type=="string"?g.type:void 0,fetchPriority:typeof g.fetchPriority=="string"?g.fetchPriority:void 0,referrerPolicy:typeof g.referrerPolicy=="string"?g.referrerPolicy:void 0,imageSrcSet:typeof g.imageSrcSet=="string"?g.imageSrcSet:void 0,imageSizes:typeof g.imageSizes=="string"?g.imageSizes:void 0,media:typeof g.media=="string"?g.media:void 0})}},pn.preloadModule=function(f,g){if(typeof f=="string")if(g){var m=d(g.as,g.crossOrigin);r.d.m(f,{as:typeof g.as=="string"&&g.as!=="script"?g.as:void 0,crossOrigin:m,integrity:typeof g.integrity=="string"?g.integrity:void 0})}else r.d.m(f)},pn.requestFormReset=function(f){r.d.r(f)},pn.unstable_batchedUpdates=function(f,g){return f(g)},pn.useFormState=function(f,g,m){return u.H.useFormState(f,g,m)},pn.useFormStatus=function(){return u.H.useHostTransitionStatus()},pn.version="19.2.0",pn}var mg;function yg(){if(mg)return qu.exports;mg=1;function l(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(l)}catch(e){console.error(e)}}return l(),qu.exports=lS(),qu.exports}/**
* @license React * @license React
* react-dom-client.production.js * react-dom-client.production.js
* *
@@ -30,20 +30,20 @@ var ex=Object.defineProperty;var tx=(Gt,Ka,Wa)=>Ka in Gt?ex(Gt,Ka,{enumerable:!0
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/var bg;function lS(){if(bg)return qs;bg=1;var l=sS(),e=Iu(),a=yg();function r(t){var n="https://react.dev/errors/"+t;if(1<arguments.length){n+="?args[]="+encodeURIComponent(arguments[1]);for(var s=2;s<arguments.length;s++)n+="&args[]="+encodeURIComponent(arguments[s])}return"Minified React error #"+t+"; visit "+n+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function i(t){return!(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)}function o(t){var n=t,s=t;if(t.alternate)for(;n.return;)n=n.return;else{t=n;do n=t,(n.flags&4098)!==0&&(s=n.return),t=n.return;while(t)}return n.tag===3?s:null}function u(t){if(t.tag===13){var n=t.memoizedState;if(n===null&&(t=t.alternate,t!==null&&(n=t.memoizedState)),n!==null)return n.dehydrated}return null}function d(t){if(t.tag===31){var n=t.memoizedState;if(n===null&&(t=t.alternate,t!==null&&(n=t.memoizedState)),n!==null)return n.dehydrated}return null}function f(t){if(o(t)!==t)throw Error(r(188))}function g(t){var n=t.alternate;if(!n){if(n=o(t),n===null)throw Error(r(188));return n!==t?null:t}for(var s=t,c=n;;){var h=s.return;if(h===null)break;var p=h.alternate;if(p===null){if(c=h.return,c!==null){s=c;continue}break}if(h.child===p.child){for(p=h.child;p;){if(p===s)return f(h),t;if(p===c)return f(h),n;p=p.sibling}throw Error(r(188))}if(s.return!==c.return)s=h,c=p;else{for(var w=!1,k=h.child;k;){if(k===s){w=!0,s=h,c=p;break}if(k===c){w=!0,c=h,s=p;break}k=k.sibling}if(!w){for(k=p.child;k;){if(k===s){w=!0,s=p,c=h;break}if(k===c){w=!0,c=p,s=h;break}k=k.sibling}if(!w)throw Error(r(189))}}if(s.alternate!==c)throw Error(r(190))}if(s.tag!==3)throw Error(r(188));return s.stateNode.current===s?t:n}function m(t){var n=t.tag;if(n===5||n===26||n===27||n===6)return t;for(t=t.child;t!==null;){if(n=m(t),n!==null)return n;t=t.sibling}return null}var b=Object.assign,v=Symbol.for("react.element"),E=Symbol.for("react.transitional.element"),S=Symbol.for("react.portal"),A=Symbol.for("react.fragment"),T=Symbol.for("react.strict_mode"),D=Symbol.for("react.profiler"),M=Symbol.for("react.consumer"),O=Symbol.for("react.context"),L=Symbol.for("react.forward_ref"),P=Symbol.for("react.suspense"),U=Symbol.for("react.suspense_list"),B=Symbol.for("react.memo"),Y=Symbol.for("react.lazy"),ge=Symbol.for("react.activity"),Ae=Symbol.for("react.memo_cache_sentinel"),Oe=Symbol.iterator;function Ne(t){return t===null||typeof t!="object"?null:(t=Oe&&t[Oe]||t["@@iterator"],typeof t=="function"?t:null)}var He=Symbol.for("react.client.reference");function Ze(t){if(t==null)return null;if(typeof t=="function")return t.$$typeof===He?null:t.displayName||t.name||null;if(typeof t=="string")return t;switch(t){case A:return"Fragment";case D:return"Profiler";case T:return"StrictMode";case P:return"Suspense";case U:return"SuspenseList";case ge:return"Activity"}if(typeof t=="object")switch(t.$$typeof){case S:return"Portal";case O:return t.displayName||"Context";case M:return(t._context.displayName||"Context")+".Consumer";case L:var n=t.render;return t=t.displayName,t||(t=n.displayName||n.name||"",t=t!==""?"ForwardRef("+t+")":"ForwardRef"),t;case B:return n=t.displayName||null,n!==null?n:Ze(t.type)||"Memo";case Y:n=t._payload,t=t._init;try{return Ze(t(n))}catch{}}return null}var pt=Array.isArray,J=e.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,de=a.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,me={pending:!1,data:null,method:null,action:null},ne=[],pe=-1;function x(t){return{current:t}}function F(t){0>pe||(t.current=ne[pe],ne[pe]=null,pe--)}function ue(t,n){pe++,ne[pe]=t.current,t.current=n}var fe=x(null),te=x(null),ye=x(null),je=x(null);function Me(t,n){switch(ue(ye,n),ue(te,t),ue(fe,null),n.nodeType){case 9:case 11:t=(t=n.documentElement)&&(t=t.namespaceURI)?Av(t):0;break;default:if(t=n.tagName,n=n.namespaceURI)n=Av(n),t=xv(n,t);else switch(t){case"svg":t=1;break;case"math":t=2;break;default:t=0}}F(fe),ue(fe,t)}function Pe(){F(fe),F(te),F(ye)}function Ie(t){t.memoizedState!==null&&ue(je,t);var n=fe.current,s=xv(n,t.type);n!==s&&(ue(te,t),ue(fe,s))}function Lt(t){te.current===t&&(F(fe),F(te)),je.current===t&&(F(je),Al._currentValue=me)}var At,Zt;function Tt(t){if(At===void 0)try{throw Error()}catch(s){var n=s.stack.trim().match(/\n( *(at )?)/);At=n&&n[1]||"",Zt=-1<s.stack.indexOf(` */var bg;function cS(){if(bg)return qs;bg=1;var l=oS(),e=Iu(),a=yg();function r(t){var n="https://react.dev/errors/"+t;if(1<arguments.length){n+="?args[]="+encodeURIComponent(arguments[1]);for(var s=2;s<arguments.length;s++)n+="&args[]="+encodeURIComponent(arguments[s])}return"Minified React error #"+t+"; visit "+n+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function i(t){return!(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)}function o(t){var n=t,s=t;if(t.alternate)for(;n.return;)n=n.return;else{t=n;do n=t,(n.flags&4098)!==0&&(s=n.return),t=n.return;while(t)}return n.tag===3?s:null}function u(t){if(t.tag===13){var n=t.memoizedState;if(n===null&&(t=t.alternate,t!==null&&(n=t.memoizedState)),n!==null)return n.dehydrated}return null}function d(t){if(t.tag===31){var n=t.memoizedState;if(n===null&&(t=t.alternate,t!==null&&(n=t.memoizedState)),n!==null)return n.dehydrated}return null}function f(t){if(o(t)!==t)throw Error(r(188))}function g(t){var n=t.alternate;if(!n){if(n=o(t),n===null)throw Error(r(188));return n!==t?null:t}for(var s=t,c=n;;){var h=s.return;if(h===null)break;var p=h.alternate;if(p===null){if(c=h.return,c!==null){s=c;continue}break}if(h.child===p.child){for(p=h.child;p;){if(p===s)return f(h),t;if(p===c)return f(h),n;p=p.sibling}throw Error(r(188))}if(s.return!==c.return)s=h,c=p;else{for(var w=!1,k=h.child;k;){if(k===s){w=!0,s=h,c=p;break}if(k===c){w=!0,c=h,s=p;break}k=k.sibling}if(!w){for(k=p.child;k;){if(k===s){w=!0,s=p,c=h;break}if(k===c){w=!0,c=p,s=h;break}k=k.sibling}if(!w)throw Error(r(189))}}if(s.alternate!==c)throw Error(r(190))}if(s.tag!==3)throw Error(r(188));return s.stateNode.current===s?t:n}function m(t){var n=t.tag;if(n===5||n===26||n===27||n===6)return t;for(t=t.child;t!==null;){if(n=m(t),n!==null)return n;t=t.sibling}return null}var b=Object.assign,v=Symbol.for("react.element"),E=Symbol.for("react.transitional.element"),S=Symbol.for("react.portal"),A=Symbol.for("react.fragment"),T=Symbol.for("react.strict_mode"),D=Symbol.for("react.profiler"),M=Symbol.for("react.consumer"),O=Symbol.for("react.context"),L=Symbol.for("react.forward_ref"),P=Symbol.for("react.suspense"),U=Symbol.for("react.suspense_list"),B=Symbol.for("react.memo"),Y=Symbol.for("react.lazy"),ge=Symbol.for("react.activity"),Ae=Symbol.for("react.memo_cache_sentinel"),Oe=Symbol.iterator;function Ne(t){return t===null||typeof t!="object"?null:(t=Oe&&t[Oe]||t["@@iterator"],typeof t=="function"?t:null)}var He=Symbol.for("react.client.reference");function Ze(t){if(t==null)return null;if(typeof t=="function")return t.$$typeof===He?null:t.displayName||t.name||null;if(typeof t=="string")return t;switch(t){case A:return"Fragment";case D:return"Profiler";case T:return"StrictMode";case P:return"Suspense";case U:return"SuspenseList";case ge:return"Activity"}if(typeof t=="object")switch(t.$$typeof){case S:return"Portal";case O:return t.displayName||"Context";case M:return(t._context.displayName||"Context")+".Consumer";case L:var n=t.render;return t=t.displayName,t||(t=n.displayName||n.name||"",t=t!==""?"ForwardRef("+t+")":"ForwardRef"),t;case B:return n=t.displayName||null,n!==null?n:Ze(t.type)||"Memo";case Y:n=t._payload,t=t._init;try{return Ze(t(n))}catch{}}return null}var pt=Array.isArray,Q=e.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,de=a.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,me={pending:!1,data:null,method:null,action:null},ne=[],pe=-1;function x(t){return{current:t}}function F(t){0>pe||(t.current=ne[pe],ne[pe]=null,pe--)}function ue(t,n){pe++,ne[pe]=t.current,t.current=n}var fe=x(null),te=x(null),ye=x(null),je=x(null);function Me(t,n){switch(ue(ye,n),ue(te,t),ue(fe,null),n.nodeType){case 9:case 11:t=(t=n.documentElement)&&(t=t.namespaceURI)?xv(t):0;break;default:if(t=n.tagName,n=n.namespaceURI)n=xv(n),t=Tv(n,t);else switch(t){case"svg":t=1;break;case"math":t=2;break;default:t=0}}F(fe),ue(fe,t)}function Pe(){F(fe),F(te),F(ye)}function Ie(t){t.memoizedState!==null&&ue(je,t);var n=fe.current,s=Tv(n,t.type);n!==s&&(ue(te,t),ue(fe,s))}function Lt(t){te.current===t&&(F(fe),F(te)),je.current===t&&(F(je),Al._currentValue=me)}var At,en;function Tt(t){if(At===void 0)try{throw Error()}catch(s){var n=s.stack.trim().match(/\n( *(at )?)/);At=n&&n[1]||"",en=-1<s.stack.indexOf(`
at`)?" (<anonymous>)":-1<s.stack.indexOf("@")?"@unknown:0:0":""}return` at`)?" (<anonymous>)":-1<s.stack.indexOf("@")?"@unknown:0:0":""}return`
`+At+t+Zt}var on=!1;function vt(t,n){if(!t||on)return"";on=!0;var s=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var c={DetermineComponentFrameRoot:function(){try{if(n){var ce=function(){throw Error()};if(Object.defineProperty(ce.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(ce,[])}catch(ee){var X=ee}Reflect.construct(t,[],ce)}else{try{ce.call()}catch(ee){X=ee}t.call(ce.prototype)}}else{try{throw Error()}catch(ee){X=ee}(ce=t())&&typeof ce.catch=="function"&&ce.catch(function(){})}}catch(ee){if(ee&&X&&typeof ee.stack=="string")return[ee.stack,X.stack]}return[null,null]}};c.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var h=Object.getOwnPropertyDescriptor(c.DetermineComponentFrameRoot,"name");h&&h.configurable&&Object.defineProperty(c.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var p=c.DetermineComponentFrameRoot(),w=p[0],k=p[1];if(w&&k){var I=w.split(` `+At+t+en}var ln=!1;function vt(t,n){if(!t||ln)return"";ln=!0;var s=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var c={DetermineComponentFrameRoot:function(){try{if(n){var ce=function(){throw Error()};if(Object.defineProperty(ce.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(ce,[])}catch(ee){var X=ee}Reflect.construct(t,[],ce)}else{try{ce.call()}catch(ee){X=ee}t.call(ce.prototype)}}else{try{throw Error()}catch(ee){X=ee}(ce=t())&&typeof ce.catch=="function"&&ce.catch(function(){})}}catch(ee){if(ee&&X&&typeof ee.stack=="string")return[ee.stack,X.stack]}return[null,null]}};c.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var h=Object.getOwnPropertyDescriptor(c.DetermineComponentFrameRoot,"name");h&&h.configurable&&Object.defineProperty(c.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var p=c.DetermineComponentFrameRoot(),w=p[0],k=p[1];if(w&&k){var I=w.split(`
`),W=k.split(` `),W=k.split(`
`);for(h=c=0;c<I.length&&!I[c].includes("DetermineComponentFrameRoot");)c++;for(;h<W.length&&!W[h].includes("DetermineComponentFrameRoot");)h++;if(c===I.length||h===W.length)for(c=I.length-1,h=W.length-1;1<=c&&0<=h&&I[c]!==W[h];)h--;for(;1<=c&&0<=h;c--,h--)if(I[c]!==W[h]){if(c!==1||h!==1)do if(c--,h--,0>h||I[c]!==W[h]){var ae=` `);for(h=c=0;c<I.length&&!I[c].includes("DetermineComponentFrameRoot");)c++;for(;h<W.length&&!W[h].includes("DetermineComponentFrameRoot");)h++;if(c===I.length||h===W.length)for(c=I.length-1,h=W.length-1;1<=c&&0<=h&&I[c]!==W[h];)h--;for(;1<=c&&0<=h;c--,h--)if(I[c]!==W[h]){if(c!==1||h!==1)do if(c--,h--,0>h||I[c]!==W[h]){var ae=`
`+I[c].replace(" at new "," at ");return t.displayName&&ae.includes("<anonymous>")&&(ae=ae.replace("<anonymous>",t.displayName)),ae}while(1<=c&&0<=h);break}}}finally{on=!1,Error.prepareStackTrace=s}return(s=t?t.displayName||t.name:"")?Tt(s):""}function Za(t,n){switch(t.tag){case 26:case 27:case 5:return Tt(t.type);case 16:return Tt("Lazy");case 13:return t.child!==n&&n!==null?Tt("Suspense Fallback"):Tt("Suspense");case 19:return Tt("SuspenseList");case 0:case 15:return vt(t.type,!1);case 11:return vt(t.type.render,!1);case 1:return vt(t.type,!0);case 31:return Tt("Activity");default:return""}}function Sn(t){try{var n="",s=null;do n+=Za(t,s),s=t,t=t.return;while(t);return n}catch(c){return` `+I[c].replace(" at new "," at ");return t.displayName&&ae.includes("<anonymous>")&&(ae=ae.replace("<anonymous>",t.displayName)),ae}while(1<=c&&0<=h);break}}}finally{ln=!1,Error.prepareStackTrace=s}return(s=t?t.displayName||t.name:"")?Tt(s):""}function Za(t,n){switch(t.tag){case 26:case 27:case 5:return Tt(t.type);case 16:return Tt("Lazy");case 13:return t.child!==n&&n!==null?Tt("Suspense Fallback"):Tt("Suspense");case 19:return Tt("SuspenseList");case 0:case 15:return vt(t.type,!1);case 11:return vt(t.type.render,!1);case 1:return vt(t.type,!0);case 31:return Tt("Activity");default:return""}}function wn(t){try{var n="",s=null;do n+=Za(t,s),s=t,t=t.return;while(t);return n}catch(c){return`
Error generating stack: `+c.message+` Error generating stack: `+c.message+`
`+c.stack}}var qn=Object.prototype.hasOwnProperty,Ut=l.unstable_scheduleCallback,Rn=l.unstable_cancelCallback,_a=l.unstable_shouldYield,Pn=l.unstable_requestPaint,Vt=l.unstable_now,yt=l.unstable_getCurrentPriorityLevel,er=l.unstable_ImmediatePriority,Gn=l.unstable_UserBlockingPriority,en=l.unstable_NormalPriority,mn=l.unstable_LowPriority,ta=l.unstable_IdlePriority,wn=l.log,tr=l.unstable_setDisableYieldValue,Vn=null,Bt=null;function Cn(t){if(typeof wn=="function"&&tr(t),Bt&&typeof Bt.setStrictMode=="function")try{Bt.setStrictMode(Vn,t)}catch{}}var q=Math.clz32?Math.clz32:Q,le=Math.log,oe=Math.LN2;function Q(t){return t>>>=0,t===0?32:31-(le(t)/oe|0)|0}var he=256,ve=262144,we=4194304;function _e(t){var n=t&42;if(n!==0)return n;switch(t&-t){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return t&261888;case 262144:case 524288:case 1048576:case 2097152:return t&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return t&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return t}}function Be(t,n,s){var c=t.pendingLanes;if(c===0)return 0;var h=0,p=t.suspendedLanes,w=t.pingedLanes;t=t.warmLanes;var k=c&134217727;return k!==0?(c=k&~p,c!==0?h=_e(c):(w&=k,w!==0?h=_e(w):s||(s=k&~t,s!==0&&(h=_e(s))))):(k=c&~p,k!==0?h=_e(k):w!==0?h=_e(w):s||(s=c&~t,s!==0&&(h=_e(s)))),h===0?0:n!==0&&n!==h&&(n&p)===0&&(p=h&-h,s=n&-n,p>=s||p===32&&(s&4194048)!==0)?n:h}function $e(t,n){return(t.pendingLanes&~(t.suspendedLanes&~t.pingedLanes)&n)===0}function Re(t,n){switch(t){case 1:case 2:case 4:case 8:case 64:return n+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return n+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function xe(){var t=we;return we<<=1,(we&62914560)===0&&(we=4194304),t}function Ke(t){for(var n=[],s=0;31>s;s++)n.push(t);return n}function qe(t,n){t.pendingLanes|=n,n!==268435456&&(t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0)}function Ce(t,n,s,c,h,p){var w=t.pendingLanes;t.pendingLanes=s,t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0,t.expiredLanes&=s,t.entangledLanes&=s,t.errorRecoveryDisabledLanes&=s,t.shellSuspendCounter=0;var k=t.entanglements,I=t.expirationTimes,W=t.hiddenUpdates;for(s=w&~s;0<s;){var ae=31-q(s),ce=1<<ae;k[ae]=0,I[ae]=-1;var X=W[ae];if(X!==null)for(W[ae]=null,ae=0;ae<X.length;ae++){var ee=X[ae];ee!==null&&(ee.lane&=-536870913)}s&=~ce}c!==0&&Ee(t,c,0),p!==0&&h===0&&t.tag!==0&&(t.suspendedLanes|=p&~(w&~n))}function Ee(t,n,s){t.pendingLanes|=n,t.suspendedLanes&=~n;var c=31-q(n);t.entangledLanes|=n,t.entanglements[c]=t.entanglements[c]|1073741824|s&261930}function Le(t,n){var s=t.entangledLanes|=n;for(t=t.entanglements;s;){var c=31-q(s),h=1<<c;h&n|t[c]&n&&(t[c]|=n),s&=~h}}function nt(t,n){var s=n&-n;return s=(s&42)!==0?1:kt(s),(s&(t.suspendedLanes|n))!==0?0:s}function kt(t){switch(t){case 2:t=1;break;case 8:t=4;break;case 32:t=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:t=128;break;case 268435456:t=134217728;break;default:t=0}return t}function yn(t){return t&=-t,2<t?8<t?(t&134217727)!==0?32:268435456:8:2}function Ft(){var t=de.p;return t!==0?t:(t=window.event,t===void 0?32:Yv(t.type))}function na(t,n){var s=de.p;try{return de.p=t,n()}finally{de.p=s}}var Dn=Math.random().toString(36).slice(2),tn="__reactFiber$"+Dn,cn="__reactProps$"+Dn,On="__reactContainer$"+Dn,_o="__reactEvents$"+Dn,Jd="__reactListeners$"+Dn,Zd="__reactHandles$"+Dn,as="__reactResources$"+Dn,nr="__reactMarker$"+Dn;function Ao(t){delete t[tn],delete t[cn],delete t[_o],delete t[Jd],delete t[Zd]}function Dr(t){var n=t[tn];if(n)return n;for(var s=t.parentNode;s;){if(n=s[On]||s[tn]){if(s=n.alternate,n.child!==null||s!==null&&s.child!==null)for(t=Mv(t);t!==null;){if(s=t[tn])return s;t=Mv(t)}return n}t=s,s=t.parentNode}return null}function Or(t){if(t=t[tn]||t[On]){var n=t.tag;if(n===5||n===6||n===13||n===31||n===26||n===27||n===3)return t}return null}function yi(t){var n=t.tag;if(n===5||n===26||n===27||n===6)return t.stateNode;throw Error(r(33))}function ja(t){var n=t[as];return n||(n=t[as]={hoistableStyles:new Map,hoistableScripts:new Map}),n}function Kt(t){t[nr]=!0}var vc=new Set,Sc={};function ar(t,n){Lr(t,n),Lr(t+"Capture",n)}function Lr(t,n){for(Sc[t]=n,t=0;t<n.length;t++)vc.add(n[t])}var Aa=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D Line truncated `+c.stack}}var qn=Object.prototype.hasOwnProperty,Bt=l.unstable_scheduleCallback,Rn=l.unstable_cancelCallback,_a=l.unstable_shouldYield,Pn=l.unstable_requestPaint,Ft=l.unstable_now,yt=l.unstable_getCurrentPriorityLevel,er=l.unstable_ImmediatePriority,Gn=l.unstable_UserBlockingPriority,tn=l.unstable_NormalPriority,yn=l.unstable_LowPriority,ta=l.unstable_IdlePriority,Cn=l.log,tr=l.unstable_setDisableYieldValue,Vn=null,qt=null;function En(t){if(typeof Cn=="function"&&tr(t),qt&&typeof qt.setStrictMode=="function")try{qt.setStrictMode(Vn,t)}catch{}}var q=Math.clz32?Math.clz32:J,le=Math.log,oe=Math.LN2;function J(t){return t>>>=0,t===0?32:31-(le(t)/oe|0)|0}var he=256,ve=262144,we=4194304;function _e(t){var n=t&42;if(n!==0)return n;switch(t&-t){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return t&261888;case 262144:case 524288:case 1048576:case 2097152:return t&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return t&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return t}}function Be(t,n,s){var c=t.pendingLanes;if(c===0)return 0;var h=0,p=t.suspendedLanes,w=t.pingedLanes;t=t.warmLanes;var k=c&134217727;return k!==0?(c=k&~p,c!==0?h=_e(c):(w&=k,w!==0?h=_e(w):s||(s=k&~t,s!==0&&(h=_e(s))))):(k=c&~p,k!==0?h=_e(k):w!==0?h=_e(w):s||(s=c&~t,s!==0&&(h=_e(s)))),h===0?0:n!==0&&n!==h&&(n&p)===0&&(p=h&-h,s=n&-n,p>=s||p===32&&(s&4194048)!==0)?n:h}function $e(t,n){return(t.pendingLanes&~(t.suspendedLanes&~t.pingedLanes)&n)===0}function Re(t,n){switch(t){case 1:case 2:case 4:case 8:case 64:return n+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return n+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function xe(){var t=we;return we<<=1,(we&62914560)===0&&(we=4194304),t}function Ke(t){for(var n=[],s=0;31>s;s++)n.push(t);return n}function qe(t,n){t.pendingLanes|=n,n!==268435456&&(t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0)}function Ce(t,n,s,c,h,p){var w=t.pendingLanes;t.pendingLanes=s,t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0,t.expiredLanes&=s,t.entangledLanes&=s,t.errorRecoveryDisabledLanes&=s,t.shellSuspendCounter=0;var k=t.entanglements,I=t.expirationTimes,W=t.hiddenUpdates;for(s=w&~s;0<s;){var ae=31-q(s),ce=1<<ae;k[ae]=0,I[ae]=-1;var X=W[ae];if(X!==null)for(W[ae]=null,ae=0;ae<X.length;ae++){var ee=X[ae];ee!==null&&(ee.lane&=-536870913)}s&=~ce}c!==0&&Ee(t,c,0),p!==0&&h===0&&t.tag!==0&&(t.suspendedLanes|=p&~(w&~n))}function Ee(t,n,s){t.pendingLanes|=n,t.suspendedLanes&=~n;var c=31-q(n);t.entangledLanes|=n,t.entanglements[c]=t.entanglements[c]|1073741824|s&261930}function Le(t,n){var s=t.entangledLanes|=n;for(t=t.entanglements;s;){var c=31-q(s),h=1<<c;h&n|t[c]&n&&(t[c]|=n),s&=~h}}function nt(t,n){var s=n&-n;return s=(s&42)!==0?1:kt(s),(s&(t.suspendedLanes|n))!==0?0:s}function kt(t){switch(t){case 2:t=1;break;case 8:t=4;break;case 32:t=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:t=128;break;case 268435456:t=134217728;break;default:t=0}return t}function bn(t){return t&=-t,2<t?8<t?(t&134217727)!==0?32:268435456:8:2}function Kt(){var t=de.p;return t!==0?t:(t=window.event,t===void 0?32:Xv(t.type))}function na(t,n){var s=de.p;try{return de.p=t,n()}finally{de.p=s}}var Dn=Math.random().toString(36).slice(2),nn="__reactFiber$"+Dn,un="__reactProps$"+Dn,On="__reactContainer$"+Dn,_o="__reactEvents$"+Dn,Qd="__reactListeners$"+Dn,Zd="__reactHandles$"+Dn,as="__reactResources$"+Dn,nr="__reactMarker$"+Dn;function Ao(t){delete t[nn],delete t[un],delete t[_o],delete t[Qd],delete t[Zd]}function Dr(t){var n=t[nn];if(n)return n;for(var s=t.parentNode;s;){if(n=s[On]||s[nn]){if(s=n.alternate,n.child!==null||s!==null&&s.child!==null)for(t=$v(t);t!==null;){if(s=t[nn])return s;t=$v(t)}return n}t=s,s=t.parentNode}return null}function Or(t){if(t=t[nn]||t[On]){var n=t.tag;if(n===5||n===6||n===13||n===31||n===26||n===27||n===3)return t}return null}function yi(t){var n=t.tag;if(n===5||n===26||n===27||n===6)return t.stateNode;throw Error(r(33))}function ja(t){var n=t[as];return n||(n=t[as]={hoistableStyles:new Map,hoistableScripts:new Map}),n}function Wt(t){t[nr]=!0}var vc=new Set,Sc={};function ar(t,n){Lr(t,n),Lr(t+"Capture",n)}function Lr(t,n){for(Sc[t]=n,t=0;t<n.length;t++)vc.add(n[t])}var Aa=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D Line truncated
`).replace(CA,"")}function Ev(t,n){return n=Cv(n),Cv(t)===n}function Et(t,n,s,c,h,p){switch(s){case"children":typeof c=="string"?n==="body"||n==="textarea"&&c===""||$r(t,c):(typeof c=="number"||typeof c=="bigint")&&n!=="body"&&$r(t,""+c);break;case"className":is(t,"class",c);break;case"tabIndex":is(t,"tabindex",c);break;case"dir":case"role":case"viewBox":case"width":case"height":is(t,s,c);break;case"style":Ba(t,c,p);break;case"data":if(n!=="object"){is(t,"data",c);break}case"src":case"href":if(c===""&&(n!=="a"||s!=="href")){t.removeAttribute(s);break}if(c==null||typeof c=="function"||typeof c=="symbol"||typeof c=="boolean"){t.removeAttribute(s);break}c=ls(""+c),t.setAttribute(s,c);break;case"action":case"formAction":if(typeof c=="function"){t.setAttribute(s,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof p=="function"&&(s==="formAction"?(n!=="input"&&Et(t,n,"name",h.name,h,null),Et(t,n,"formEncType",h.formEncType,h,null),Et(t,n,"formMethod",h.formMethod,h,null),Et(t,n,"formTarget",h.formTarget,h,null)):(Et(t,n,"encType",h.encType,h,null),Et(t,n,"method",h.method,h,null),Et(t,n,"target",h.target,h,null)));if(c==null||typeof c=="symbol"||typeof c=="boolean"){t.removeAttribute(s);break}c=ls(""+c),t.setAttribute(s,c);break;case"onClick":c!=null&&(t.onclick=aa);break;case"onScroll":c!=null&&tt("scroll",t);break;case"onScrollEnd":c!=null&&tt("scrollend",t);break;case"dangerouslySetInnerHTML":if(c!=null){if(typeof c!="object"||!("__html"in c))throw Error(r(61));if(s=c.__html,s!=null){if(h.children!=null)throw Error(r(60));t.innerHTML=s}}break;case"multiple":t.multiple=c&&typeof c!="function"&&typeof c!="symbol";break;case"muted":t.muted=c&&typeof c!="function"&&typeof c!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(c==null||typeof c=="function"||typeof c=="boolean"||typeof c=="symbol"){t.removeAttribute("xlink:href");break}s=ls(""+c),t.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",s);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":c!=null&&typeof c!="function"&&typeof c!="symbol"?t.setAttribute(s,""+c):t.removeAttribute(s);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":c&&typeof c!="function"&&typeof c!="symbol"?t.setAttribute(s,""):t.removeAttribute(s);break;case"capture":case"download":c===!0?t.setAttribute(s,""):c!==!1&&c!=null&&typeof c!="function"&&typeof c!="symbol"?t.setAttribute(s,c):t.removeAttribute(s);break;case"cols":case"rows":case"size":case"span":c!=null&&typeof c!="function"&&typeof c!="symbol"&&!isNaN(c)&&1<=c?t.setAttribute(s,c):t.removeAttribute(s);break;case"rowSpan":case"start":c==null||typeof c=="function"||typeof c=="symbol"||isNaN(c)?t.removeAttribute(s):t.setAttribute(s,c);break;case"popover":tt("beforetoggle",t),tt("toggle",t),rs(t,"popover",c);break;case"xlinkActuate":xa(t,"http://www.w3.org/1999/xlink","xlink:actuate",c);break;case"xlinkArcrole":xa(t,"http://www.w3.org/1999/xlink","xlink:arcrole",c);break;case"xlinkRole":xa(t,"http://www.w3.org/1999/xlink","xlink:role",c);break;case"xlinkShow":xa(t,"http://www.w3.org/1999/xlink","xlink:show",c);break;case"xlinkTitle":xa(t,"http://www.w3.org/1999/xlink","xlink:title",c);break;case"xlinkType":xa(t,"http://www.w3.org/1999/xlink","xlink:type",c);break;case"xmlBase":xa(t,"http://www.w3.org/XML/1998/namespace","xml:base",c);break;case"xmlLang":xa(t,"http://www.w3.org/XML/1998/namespace","xml:lang",c);break;case"xmlSpace":xa(t,"http://www.w3.org/XML/1998/namespace","xml:space",c);break;case"is":rs(t,"is",c);break;case"innerText":case"textContent":break;default:(!(2<s.length)||s[0]!=="o"&&s[0]!=="O"||s[1]!=="n"&&s[1]!=="N")&&(s=nf.get(s)||s,rs(t,s,c))}}function Kh(t,n,s,c,h,p){switch(s){case"style":Ba(t,c,p);break;case"dangerouslySetInnerHTML":if(c!=null){if(typeof c!="object"||!("__html"in c))throw Error(r(61));if(s=c.__html,s!=null){if(h.children!=null)throw Error(r(60));t.innerHTML=s}}break;case"children":typeof c=="string"?$r(t,c):(typeof c=="number"||typeof c=="bigint")&&$r(t,""+c);break;case"onScroll":c!=null&&tt("scroll",t);break;case"onScrollEnd":c!=null&&tt("scrollend",t);break;case"onClick":c!=null&&(t.onclick=aa);break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"inne Line truncated `).replace(EA,"")}function _v(t,n){return n=Ev(n),Ev(t)===n}function Et(t,n,s,c,h,p){switch(s){case"children":typeof c=="string"?n==="body"||n==="textarea"&&c===""||$r(t,c):(typeof c=="number"||typeof c=="bigint")&&n!=="body"&&$r(t,""+c);break;case"className":is(t,"class",c);break;case"tabIndex":is(t,"tabindex",c);break;case"dir":case"role":case"viewBox":case"width":case"height":is(t,s,c);break;case"style":Ba(t,c,p);break;case"data":if(n!=="object"){is(t,"data",c);break}case"src":case"href":if(c===""&&(n!=="a"||s!=="href")){t.removeAttribute(s);break}if(c==null||typeof c=="function"||typeof c=="symbol"||typeof c=="boolean"){t.removeAttribute(s);break}c=ls(""+c),t.setAttribute(s,c);break;case"action":case"formAction":if(typeof c=="function"){t.setAttribute(s,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof p=="function"&&(s==="formAction"?(n!=="input"&&Et(t,n,"name",h.name,h,null),Et(t,n,"formEncType",h.formEncType,h,null),Et(t,n,"formMethod",h.formMethod,h,null),Et(t,n,"formTarget",h.formTarget,h,null)):(Et(t,n,"encType",h.encType,h,null),Et(t,n,"method",h.method,h,null),Et(t,n,"target",h.target,h,null)));if(c==null||typeof c=="symbol"||typeof c=="boolean"){t.removeAttribute(s);break}c=ls(""+c),t.setAttribute(s,c);break;case"onClick":c!=null&&(t.onclick=aa);break;case"onScroll":c!=null&&tt("scroll",t);break;case"onScrollEnd":c!=null&&tt("scrollend",t);break;case"dangerouslySetInnerHTML":if(c!=null){if(typeof c!="object"||!("__html"in c))throw Error(r(61));if(s=c.__html,s!=null){if(h.children!=null)throw Error(r(60));t.innerHTML=s}}break;case"multiple":t.multiple=c&&typeof c!="function"&&typeof c!="symbol";break;case"muted":t.muted=c&&typeof c!="function"&&typeof c!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(c==null||typeof c=="function"||typeof c=="boolean"||typeof c=="symbol"){t.removeAttribute("xlink:href");break}s=ls(""+c),t.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",s);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":c!=null&&typeof c!="function"&&typeof c!="symbol"?t.setAttribute(s,""+c):t.removeAttribute(s);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":c&&typeof c!="function"&&typeof c!="symbol"?t.setAttribute(s,""):t.removeAttribute(s);break;case"capture":case"download":c===!0?t.setAttribute(s,""):c!==!1&&c!=null&&typeof c!="function"&&typeof c!="symbol"?t.setAttribute(s,c):t.removeAttribute(s);break;case"cols":case"rows":case"size":case"span":c!=null&&typeof c!="function"&&typeof c!="symbol"&&!isNaN(c)&&1<=c?t.setAttribute(s,c):t.removeAttribute(s);break;case"rowSpan":case"start":c==null||typeof c=="function"||typeof c=="symbol"||isNaN(c)?t.removeAttribute(s):t.setAttribute(s,c);break;case"popover":tt("beforetoggle",t),tt("toggle",t),rs(t,"popover",c);break;case"xlinkActuate":xa(t,"http://www.w3.org/1999/xlink","xlink:actuate",c);break;case"xlinkArcrole":xa(t,"http://www.w3.org/1999/xlink","xlink:arcrole",c);break;case"xlinkRole":xa(t,"http://www.w3.org/1999/xlink","xlink:role",c);break;case"xlinkShow":xa(t,"http://www.w3.org/1999/xlink","xlink:show",c);break;case"xlinkTitle":xa(t,"http://www.w3.org/1999/xlink","xlink:title",c);break;case"xlinkType":xa(t,"http://www.w3.org/1999/xlink","xlink:type",c);break;case"xmlBase":xa(t,"http://www.w3.org/XML/1998/namespace","xml:base",c);break;case"xmlLang":xa(t,"http://www.w3.org/XML/1998/namespace","xml:lang",c);break;case"xmlSpace":xa(t,"http://www.w3.org/XML/1998/namespace","xml:space",c);break;case"is":rs(t,"is",c);break;case"innerText":case"textContent":break;default:(!(2<s.length)||s[0]!=="o"&&s[0]!=="O"||s[1]!=="n"&&s[1]!=="N")&&(s=nf.get(s)||s,rs(t,s,c))}}function Kh(t,n,s,c,h,p){switch(s){case"style":Ba(t,c,p);break;case"dangerouslySetInnerHTML":if(c!=null){if(typeof c!="object"||!("__html"in c))throw Error(r(61));if(s=c.__html,s!=null){if(h.children!=null)throw Error(r(60));t.innerHTML=s}}break;case"children":typeof c=="string"?$r(t,c):(typeof c=="number"||typeof c=="bigint")&&$r(t,""+c);break;case"onScroll":c!=null&&tt("scroll",t);break;case"onScrollEnd":c!=null&&tt("scrollend",t);break;case"onClick":c!=null&&(t.onclick=aa);break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"inne Line truncated
`).forEach(function(u){i=u.indexOf(":"),a=u.substring(0,i).trim().toLowerCase(),r=u.substring(i+1).trim(),!(!a||e[a]&&Ew[a])&&(a==="set-cookie"?e[a]?e[a].push(r):e[a]=[r]:e[a]=e[a]?e[a]+", "+r:r)}),e},ep=Symbol("internals");function to(l){return l&&String(l).trim().toLowerCase()}function Bl(l){return l===!1||l==null?l:Z.isArray(l)?l.map(Bl):String(l)}function Aw(l){const e=Object.create(null),a=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=a.exec(l);)e[r[1]]=r[2];return e}const xw=l=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(l.trim());function id(l,e,a,r,i){if(Z.isFunction(r))return r.call(this,e,a);if(i&&(e=a),!!Z.isString(e)){if(Z.isString(r))return e.indexOf(r)!==-1;if(Z.isRegExp(r))return r.test(e)}}function Tw(l){return l.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(e,a,r)=>a.toUpperCase()+r)}function kw(l,e){const a=Z.toCamelCase(" "+e);["get","set","has"].forEach(r=>{Object.defineProperty(l,r+a,{value:function(i,o,u){return this[r].call(this,e,i,o,u)},configurable:!0})})}let An=class{constructor(e){e&&this.set(e)}set(e,a,r){const i=this;function o(d,f,g){const m=to(f);if(!m)throw new Error("header name must be a non-empty string");const b=Z.findKey(i,m);(!b||i[b]===void 0||g===!0||g===void 0&&i[b]!==!1)&&(i[b||f]=Bl(d))}const u=(d,f)=>Z.forEach(d,(g,m)=>o(g,m,f));if(Z.isPlainObject(e)||e instanceof this.constructor)u(e,a);else if(Z.isString(e)&&(e=e.trim())&&!xw(e))u(_w(e),a);else if(Z.isObject(e)&&Z.isIterable(e)){let d={},f,g;for(const m of e){if(!Z.isArray(m))throw TypeError("Object iterator must return a key-value pair");d[g=m[0]]=(f=d[g])?Z.isArray(f)?[...f,m[1]]:[f,m[1]]:m[1]}u(d,a)}else e!=null&&o(a,e,r);return this}get(e,a){if(e=to(e),e){const r=Z.findKey(this,e);if(r){const i=this[r];if(!a)return i;if(a===!0)return Aw(i);if(Z.isFunction(a))return a.call(this,i,r);if(Z.isRegExp(a))return a.exec(i);throw new TypeError("parser must be boolean|regexp|function")}}}has(e,a){if(e=to(e),e){const r=Z.findKey(this,e);return!!(r&&this[r]!==void 0&&(!a||id(this,this[r],r,a)))}return!1}delete(e,a){const r=this;let i=!1;function o(u){if(u=to(u),u){const d=Z.findKey(r,u);d&&(!a||id(r,r[d],d,a))&&(delete r[d],i=!0)}}return Z.isArray(e)?e.forEach(o):o(e),i}clear(e){const a=Object.keys(this);let r=a.length,i=!1;for(;r--;){const o=a[r];(!e||id(this,this[o],o,e,!0))&&(delete this[o],i=!0)}return i}normalize(e){const a=this,r={};return Z.forEach(this,(i,o)=>{const u=Z.findKey(r,o);if(u){a[u]=Bl(i),delete a[o];return}const d=e?Tw(o):String(o).trim();d!==o&&delete a[o],a[d]=Bl(i),r[d]=!0}),this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){const a=Object.create(null);return Z.forEach(this,(r,i)=>{r!=null&&r!==!1&&(a[i]=e&&Z.isArray(r)?r.join(", "):r)}),a}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([e,a])=>e+": "+a).join(` `).forEach(function(u){i=u.indexOf(":"),a=u.substring(0,i).trim().toLowerCase(),r=u.substring(i+1).trim(),!(!a||e[a]&&_w[a])&&(a==="set-cookie"?e[a]?e[a].push(r):e[a]=[r]:e[a]=e[a]?e[a]+", "+r:r)}),e},ep=Symbol("internals");function to(l){return l&&String(l).trim().toLowerCase()}function Bl(l){return l===!1||l==null?l:Z.isArray(l)?l.map(Bl):String(l)}function xw(l){const e=Object.create(null),a=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=a.exec(l);)e[r[1]]=r[2];return e}const Tw=l=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(l.trim());function id(l,e,a,r,i){if(Z.isFunction(r))return r.call(this,e,a);if(i&&(e=a),!!Z.isString(e)){if(Z.isString(r))return e.indexOf(r)!==-1;if(Z.isRegExp(r))return r.test(e)}}function kw(l){return l.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(e,a,r)=>a.toUpperCase()+r)}function Rw(l,e){const a=Z.toCamelCase(" "+e);["get","set","has"].forEach(r=>{Object.defineProperty(l,r+a,{value:function(i,o,u){return this[r].call(this,e,i,o,u)},configurable:!0})})}let xn=class{constructor(e){e&&this.set(e)}set(e,a,r){const i=this;function o(d,f,g){const m=to(f);if(!m)throw new Error("header name must be a non-empty string");const b=Z.findKey(i,m);(!b||i[b]===void 0||g===!0||g===void 0&&i[b]!==!1)&&(i[b||f]=Bl(d))}const u=(d,f)=>Z.forEach(d,(g,m)=>o(g,m,f));if(Z.isPlainObject(e)||e instanceof this.constructor)u(e,a);else if(Z.isString(e)&&(e=e.trim())&&!Tw(e))u(Aw(e),a);else if(Z.isObject(e)&&Z.isIterable(e)){let d={},f,g;for(const m of e){if(!Z.isArray(m))throw TypeError("Object iterator must return a key-value pair");d[g=m[0]]=(f=d[g])?Z.isArray(f)?[...f,m[1]]:[f,m[1]]:m[1]}u(d,a)}else e!=null&&o(a,e,r);return this}get(e,a){if(e=to(e),e){const r=Z.findKey(this,e);if(r){const i=this[r];if(!a)return i;if(a===!0)return xw(i);if(Z.isFunction(a))return a.call(this,i,r);if(Z.isRegExp(a))return a.exec(i);throw new TypeError("parser must be boolean|regexp|function")}}}has(e,a){if(e=to(e),e){const r=Z.findKey(this,e);return!!(r&&this[r]!==void 0&&(!a||id(this,this[r],r,a)))}return!1}delete(e,a){const r=this;let i=!1;function o(u){if(u=to(u),u){const d=Z.findKey(r,u);d&&(!a||id(r,r[d],d,a))&&(delete r[d],i=!0)}}return Z.isArray(e)?e.forEach(o):o(e),i}clear(e){const a=Object.keys(this);let r=a.length,i=!1;for(;r--;){const o=a[r];(!e||id(this,this[o],o,e,!0))&&(delete this[o],i=!0)}return i}normalize(e){const a=this,r={};return Z.forEach(this,(i,o)=>{const u=Z.findKey(r,o);if(u){a[u]=Bl(i),delete a[o];return}const d=e?kw(o):String(o).trim();d!==o&&delete a[o],a[d]=Bl(i),r[d]=!0}),this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){const a=Object.create(null);return Z.forEach(this,(r,i)=>{r!=null&&r!==!1&&(a[i]=e&&Z.isArray(r)?r.join(", "):r)}),a}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([e,a])=>e+": "+a).join(`
`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(e){return e instanceof this?e:new this(e)}static concat(e,...a){const r=new this(e);return a.forEach(i=>r.set(i)),r}static accessor(e){const r=(this[ep]=this[ep]={accessors:{}}).accessors,i=this.prototype;function o(u){const d=to(u);r[d]||(kw(i,u),r[d]=!0)}return Z.isArray(e)?e.forEach(o):o(e),this}};An.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]),Z.reduceDescriptors(An.prototype,({value:l},e)=>{let a=e[0].toUpperCase()+e.slice(1);return{get:()=>l,set(r){this[a]=r}}}),Z.freezeMethods(An);function sd(l,e){const a=this||eo,r=e||a,i=An.from(r.headers);let o=r.data;return Z.forEach(l,function(d){o=d.call(a,o,i.normalize(),e?e.status:void 0)}),i.normalize(),o}function tp(l){return!!(l&&l.__CANCEL__)}function Fi(l,e,a){Ye.call(this,l??"canceled",Ye.ERR_CANCELED,e,a),this.name="CanceledError"}Z.inherits(Fi,Ye,{__CANCEL__:!0});function np(l,e,a){const r=a.config.validateStatus;!a.status||!r||r(a.status)?l(a):e(new Ye("Request failed with status code "+a.status,[Ye.ERR_BAD_REQUEST,Ye.ERR_BAD_RESPONSE][Math.floor(a.status/100)-4],a.config,a.request,a))}function Rw(l){const e=/^([-+\w]{1,25})(:?\/\/|:)/.exec(l);return e&&e[1]||""}function Dw(l,e){l=l||10;const a=new Array(l),r=new Array(l);let i=0,o=0,u;return e=e!==void 0?e:1e3,function(f){const g=Date.now(),m=r[o];u||(u=g),a[i]=f,r[i]=g;let b=o,v=0;for(;b!==i;)v+=a[b++],b=b%l;if(i=(i+1)%l,i===o&&(o=(o+1)%l),g-u<e)return;const E=m&&g-m;return E?Math.round(v*1e3/E):void 0}}function Ow(l,e){let a=0,r=1e3/e,i,o;const u=(g,m=Date.now())=>{a=m,i=null,o&&(clearTimeout(o),o=null),l(...g)};return[(...g)=>{const m=Date.now(),b=m-a;b>=r?u(g,m):(i=g,o||(o=setTimeout(()=>{o=null,u(i)},r-b)))},()=>i&&u(i)]}const ql=(l,e,a=3)=>{let r=0;const i=Dw(50,250);return Ow(o=>{const u=o.loaded,d=o.lengthComputable?o.total:void 0,f=u-r,g=i(f),m=u<=d;r=u;const b={loaded:u,total:d,progress:d?u/d:void 0,bytes:f,rate:g||void 0,estimated:g&&d&&m?(d-u)/g:void 0,event:o,lengthComputable:d!=null,[e?"download":"upload"]:!0};l(b)},a)},ap=(l,e)=>{const a=l!=null;return[r=>e[0]({lengthComputable:a,total:l,loaded:r}),e[1]]},rp=l=>(...e)=>Z.asap(()=>l(...e)),Lw=pn.hasStandardBrowserEnv?((l,e)=>a=>(a=new URL(a,pn.origin),l.protocol===a.protocol&&l.host===a.host&&(e||l.port===a.port)))(new URL(pn.origin),pn.navigator&&/(msie|trident)/i.test(pn.navigator.userAgent)):()=>!0,Mw=pn.hasStandardBrowserEnv?{write(l,e,a,r,i,o){const u=[l+"="+encodeURIComponent(e)];Z.isNumber(a)&&u.push("expires="+new Date(a).toGMTString()),Z.isString(r)&&u.push("path="+r),Z.isString(i)&&u.push("domain="+i),o===!0&&u.push("secure"),document.cookie=u.join("; ")},read(l){const e=document.cookie.match(new RegExp("(^|;\\s*)("+l+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove(l){this.write(l,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function $w(l){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(l)}function Nw(l,e){return e?l.replace(/\/?\/$/,"")+"/"+e.replace(/^\/+/,""):l}function ip(l,e,a){let r=!$w(e);return l&&(r||a==!1)?Nw(l,e):e}const sp=l=>l instanceof An?{...l}:l;function di(l,e){e=e||{};const a={};function r(g,m,b,v){return Z.isPlainObject(g)&&Z.isPlainObject(m)?Z.merge.call({caseless:v},g,m):Z.isPlainObject(m)?Z.merge({},m):Z.isArray(m)?m.slice():m}function i(g,m,b,v){if(Z.isUndefined(m)){if(!Z.isUndefined(g))return r(void 0,g,b,v)}else return r(g,m,b,v)}function o(g,m){if(!Z.isUndefined(m))return r(void 0,m)}function u(g,m){if(Z.isUndefined(m)){if(!Z.isUndefined(g))return r(void 0,g)}else return r(void 0,m)}function d(g,m,b){if(b in e)return r(g,m);if(b in l)return r(void 0,g)}const f={url:o,method:o,data:o,baseURL:u,transformRequest:u,transformResponse:u,paramsSerializer:u,timeout:u,timeoutMessage:u,withCredentials:u,withXSRFToken:u,adapter:u,responseType:u,xsrfCookieName:u,xsrfHeaderName:u,onUploadProgress:u,onDownloadProgress:u,decompress:u,maxContentLength:u,maxBodyLength:u,beforeRedirect:u,transport:u,httpAgent:u,httpsAgent:u,cancelToken:u,socketPath:u,responseEncoding:u,validateStatus:d,headers:(g,m,b)=>i(sp(g),sp(m),b,!0)};return Z.forEach(Object.keys({...l,...e}),function(m){const b=f[m]||i,v=b(l[m],e[m],m);Z.isUndefined(v)&&b!==d||(a[m]=v)}),a}const op=l=>{const e=di({},l);let{data:a,withXSRFToken:r,xsrfHeaderName:i,xsrfCookieName:o,headers:u,auth:d}=e;if(e.headers=u=An.from(u),e.url=Xg(ip(e.baseURL,e.url,e.allowAbsoluteUrls),l.params,l.paramsSerializer),d&&u.set("Authorization","Basic "+btoa((d.username||"")+":"+(d.password?unescape(encodeURIComponent(d.password)):""))),Z.isFormData(a)){if(pn.hasStandardBrowserEnv||pn.hasStandardBrowserWebWorkerEnv)u.setContentType(void 0);else if(Z.isFunction(a.getHeaders)){const f=a.getHeaders(),g=["content-type","content-length"];Object.entries(f).forEach(([m,b])=>{g.includes(m.toLowerCase())&&u.set(m,b)})}}if(pn.hasStandardBrowserEnv&&(r&&Z.isFunction(r)&&(r=r(e)),r||r!==!1&&Lw(e.url))) Line truncated `)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(e){return e instanceof this?e:new this(e)}static concat(e,...a){const r=new this(e);return a.forEach(i=>r.set(i)),r}static accessor(e){const r=(this[ep]=this[ep]={accessors:{}}).accessors,i=this.prototype;function o(u){const d=to(u);r[d]||(Rw(i,u),r[d]=!0)}return Z.isArray(e)?e.forEach(o):o(e),this}};xn.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]),Z.reduceDescriptors(xn.prototype,({value:l},e)=>{let a=e[0].toUpperCase()+e.slice(1);return{get:()=>l,set(r){this[a]=r}}}),Z.freezeMethods(xn);function sd(l,e){const a=this||eo,r=e||a,i=xn.from(r.headers);let o=r.data;return Z.forEach(l,function(d){o=d.call(a,o,i.normalize(),e?e.status:void 0)}),i.normalize(),o}function tp(l){return!!(l&&l.__CANCEL__)}function Fi(l,e,a){Ye.call(this,l??"canceled",Ye.ERR_CANCELED,e,a),this.name="CanceledError"}Z.inherits(Fi,Ye,{__CANCEL__:!0});function np(l,e,a){const r=a.config.validateStatus;!a.status||!r||r(a.status)?l(a):e(new Ye("Request failed with status code "+a.status,[Ye.ERR_BAD_REQUEST,Ye.ERR_BAD_RESPONSE][Math.floor(a.status/100)-4],a.config,a.request,a))}function Dw(l){const e=/^([-+\w]{1,25})(:?\/\/|:)/.exec(l);return e&&e[1]||""}function Ow(l,e){l=l||10;const a=new Array(l),r=new Array(l);let i=0,o=0,u;return e=e!==void 0?e:1e3,function(f){const g=Date.now(),m=r[o];u||(u=g),a[i]=f,r[i]=g;let b=o,v=0;for(;b!==i;)v+=a[b++],b=b%l;if(i=(i+1)%l,i===o&&(o=(o+1)%l),g-u<e)return;const E=m&&g-m;return E?Math.round(v*1e3/E):void 0}}function Lw(l,e){let a=0,r=1e3/e,i,o;const u=(g,m=Date.now())=>{a=m,i=null,o&&(clearTimeout(o),o=null),l(...g)};return[(...g)=>{const m=Date.now(),b=m-a;b>=r?u(g,m):(i=g,o||(o=setTimeout(()=>{o=null,u(i)},r-b)))},()=>i&&u(i)]}const ql=(l,e,a=3)=>{let r=0;const i=Ow(50,250);return Lw(o=>{const u=o.loaded,d=o.lengthComputable?o.total:void 0,f=u-r,g=i(f),m=u<=d;r=u;const b={loaded:u,total:d,progress:d?u/d:void 0,bytes:f,rate:g||void 0,estimated:g&&d&&m?(d-u)/g:void 0,event:o,lengthComputable:d!=null,[e?"download":"upload"]:!0};l(b)},a)},ap=(l,e)=>{const a=l!=null;return[r=>e[0]({lengthComputable:a,total:l,loaded:r}),e[1]]},rp=l=>(...e)=>Z.asap(()=>l(...e)),Mw=mn.hasStandardBrowserEnv?((l,e)=>a=>(a=new URL(a,mn.origin),l.protocol===a.protocol&&l.host===a.host&&(e||l.port===a.port)))(new URL(mn.origin),mn.navigator&&/(msie|trident)/i.test(mn.navigator.userAgent)):()=>!0,$w=mn.hasStandardBrowserEnv?{write(l,e,a,r,i,o){const u=[l+"="+encodeURIComponent(e)];Z.isNumber(a)&&u.push("expires="+new Date(a).toGMTString()),Z.isString(r)&&u.push("path="+r),Z.isString(i)&&u.push("domain="+i),o===!0&&u.push("secure"),document.cookie=u.join("; ")},read(l){const e=document.cookie.match(new RegExp("(^|;\\s*)("+l+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove(l){this.write(l,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function Nw(l){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(l)}function Hw(l,e){return e?l.replace(/\/?\/$/,"")+"/"+e.replace(/^\/+/,""):l}function ip(l,e,a){let r=!Nw(e);return l&&(r||a==!1)?Hw(l,e):e}const sp=l=>l instanceof xn?{...l}:l;function di(l,e){e=e||{};const a={};function r(g,m,b,v){return Z.isPlainObject(g)&&Z.isPlainObject(m)?Z.merge.call({caseless:v},g,m):Z.isPlainObject(m)?Z.merge({},m):Z.isArray(m)?m.slice():m}function i(g,m,b,v){if(Z.isUndefined(m)){if(!Z.isUndefined(g))return r(void 0,g,b,v)}else return r(g,m,b,v)}function o(g,m){if(!Z.isUndefined(m))return r(void 0,m)}function u(g,m){if(Z.isUndefined(m)){if(!Z.isUndefined(g))return r(void 0,g)}else return r(void 0,m)}function d(g,m,b){if(b in e)return r(g,m);if(b in l)return r(void 0,g)}const f={url:o,method:o,data:o,baseURL:u,transformRequest:u,transformResponse:u,paramsSerializer:u,timeout:u,timeoutMessage:u,withCredentials:u,withXSRFToken:u,adapter:u,responseType:u,xsrfCookieName:u,xsrfHeaderName:u,onUploadProgress:u,onDownloadProgress:u,decompress:u,maxContentLength:u,maxBodyLength:u,beforeRedirect:u,transport:u,httpAgent:u,httpsAgent:u,cancelToken:u,socketPath:u,responseEncoding:u,validateStatus:d,headers:(g,m,b)=>i(sp(g),sp(m),b,!0)};return Z.forEach(Object.keys({...l,...e}),function(m){const b=f[m]||i,v=b(l[m],e[m],m);Z.isUndefined(v)&&b!==d||(a[m]=v)}),a}const op=l=>{const e=di({},l);let{data:a,withXSRFToken:r,xsrfHeaderName:i,xsrfCookieName:o,headers:u,auth:d}=e;if(e.headers=u=xn.from(u),e.url=Xg(ip(e.baseURL,e.url,e.allowAbsoluteUrls),l.params,l.paramsSerializer),d&&u.set("Authorization","Basic "+btoa((d.username||"")+":"+(d.password?unescape(encodeURIComponent(d.password)):""))),Z.isFormData(a)){if(mn.hasStandardBrowserEnv||mn.hasStandardBrowserWebWorkerEnv)u.setContentType(void 0);else if(Z.isFunction(a.getHeaders)){const f=a.getHeaders(),g=["content-type","content-length"];Object.entries(f).forEach(([m,b])=>{g.includes(m.toLowerCase())&&u.set(m,b)})}}if(mn.hasStandardBrowserEnv&&(r&&Z.isFunction(r)&&(r=r(e)),r||r!==!1&&Mw(e.url))) Line truncated
`+u.map(gp).join(` `+u.map(gp).join(`
`):" "+gp(u[0]):"as no adapter specified";throw new Ye("There is no suitable adapter to dispatch the request "+d,"ERR_NOT_SUPPORT")}return i},adapters:od};function ld(l){if(l.cancelToken&&l.cancelToken.throwIfRequested(),l.signal&&l.signal.aborted)throw new Fi(null,l)}function mp(l){return ld(l),l.headers=An.from(l.headers),l.data=sd.call(l,l.transformRequest),["post","put","patch"].indexOf(l.method)!==-1&&l.headers.setContentType("application/x-www-form-urlencoded",!1),pp.getAdapter(l.adapter||eo.adapter,l)(l).then(function(r){return ld(l),r.data=sd.call(l,l.transformResponse,r),r.headers=An.from(r.headers),r},function(r){return tp(r)||(ld(l),r&&r.response&&(r.response.data=sd.call(l,l.transformResponse,r.response),r.response.headers=An.from(r.response.headers))),Promise.reject(r)})}const yp="1.12.2",Gl={};["object","boolean","number","function","string","symbol"].forEach((l,e)=>{Gl[l]=function(r){return typeof r===l||"a"+(e<1?"n ":" ")+l}});const bp={};Gl.transitional=function(e,a,r){function i(o,u){return"[Axios v"+yp+"] Transitional option '"+o+"'"+u+(r?". "+r:"")}return(o,u,d)=>{if(e===!1)throw new Ye(i(u," has been removed"+(a?" in "+a:"")),Ye.ERR_DEPRECATED);return a&&!bp[u]&&(bp[u]=!0,console.warn(i(u," has been deprecated since v"+a+" and will be removed in the near future"))),e?e(o,u,d):!0}},Gl.spelling=function(e){return(a,r)=>(console.warn(`${r} is likely a misspelling of ${e}`),!0)};function Vw(l,e,a){if(typeof l!="object")throw new Ye("options must be an object",Ye.ERR_BAD_OPTION_VALUE);const r=Object.keys(l);let i=r.length;for(;i-- >0;){const o=r[i],u=e[o];if(u){const d=l[o],f=d===void 0||u(d,o,l);if(f!==!0)throw new Ye("option "+o+" must be "+f,Ye.ERR_BAD_OPTION_VALUE);continue}if(a!==!0)throw new Ye("Unknown option "+o,Ye.ERR_BAD_OPTION)}}const Vl={assertOptions:Vw,validators:Gl},Ma=Vl.validators;let fi=class{constructor(e){this.defaults=e||{},this.interceptors={request:new Qg,response:new Qg}}async request(e,a){try{return await this._request(e,a)}catch(r){if(r instanceof Error){let i={};Error.captureStackTrace?Error.captureStackTrace(i):i=new Error;const o=i.stack?i.stack.replace(/^.+\n/,""):"";try{r.stack?o&&!String(r.stack).endsWith(o.replace(/^.+\n.+\n/,""))&&(r.stack+=` `):" "+gp(u[0]):"as no adapter specified";throw new Ye("There is no suitable adapter to dispatch the request "+d,"ERR_NOT_SUPPORT")}return i},adapters:od};function ld(l){if(l.cancelToken&&l.cancelToken.throwIfRequested(),l.signal&&l.signal.aborted)throw new Fi(null,l)}function mp(l){return ld(l),l.headers=xn.from(l.headers),l.data=sd.call(l,l.transformRequest),["post","put","patch"].indexOf(l.method)!==-1&&l.headers.setContentType("application/x-www-form-urlencoded",!1),pp.getAdapter(l.adapter||eo.adapter,l)(l).then(function(r){return ld(l),r.data=sd.call(l,l.transformResponse,r),r.headers=xn.from(r.headers),r},function(r){return tp(r)||(ld(l),r&&r.response&&(r.response.data=sd.call(l,l.transformResponse,r.response),r.response.headers=xn.from(r.response.headers))),Promise.reject(r)})}const yp="1.12.2",Gl={};["object","boolean","number","function","string","symbol"].forEach((l,e)=>{Gl[l]=function(r){return typeof r===l||"a"+(e<1?"n ":" ")+l}});const bp={};Gl.transitional=function(e,a,r){function i(o,u){return"[Axios v"+yp+"] Transitional option '"+o+"'"+u+(r?". "+r:"")}return(o,u,d)=>{if(e===!1)throw new Ye(i(u," has been removed"+(a?" in "+a:"")),Ye.ERR_DEPRECATED);return a&&!bp[u]&&(bp[u]=!0,console.warn(i(u," has been deprecated since v"+a+" and will be removed in the near future"))),e?e(o,u,d):!0}},Gl.spelling=function(e){return(a,r)=>(console.warn(`${r} is likely a misspelling of ${e}`),!0)};function Fw(l,e,a){if(typeof l!="object")throw new Ye("options must be an object",Ye.ERR_BAD_OPTION_VALUE);const r=Object.keys(l);let i=r.length;for(;i-- >0;){const o=r[i],u=e[o];if(u){const d=l[o],f=d===void 0||u(d,o,l);if(f!==!0)throw new Ye("option "+o+" must be "+f,Ye.ERR_BAD_OPTION_VALUE);continue}if(a!==!0)throw new Ye("Unknown option "+o,Ye.ERR_BAD_OPTION)}}const Vl={assertOptions:Fw,validators:Gl},Ma=Vl.validators;let fi=class{constructor(e){this.defaults=e||{},this.interceptors={request:new Jg,response:new Jg}}async request(e,a){try{return await this._request(e,a)}catch(r){if(r instanceof Error){let i={};Error.captureStackTrace?Error.captureStackTrace(i):i=new Error;const o=i.stack?i.stack.replace(/^.+\n/,""):"";try{r.stack?o&&!String(r.stack).endsWith(o.replace(/^.+\n.+\n/,""))&&(r.stack+=`
`+o):r.stack=o}catch{}}throw r}}_request(e,a){typeof e=="string"?(a=a||{},a.url=e):a=e||{},a=di(this.defaults,a);const{transitional:r,paramsSerializer:i,headers:o}=a;r!==void 0&&Vl.assertOptions(r,{silentJSONParsing:Ma.transitional(Ma.boolean),forcedJSONParsing:Ma.transitional(Ma.boolean),clarifyTimeoutError:Ma.transitional(Ma.boolean)},!1),i!=null&&(Z.isFunction(i)?a.paramsSerializer={serialize:i}:Vl.assertOptions(i,{encode:Ma.function,serialize:Ma.function},!0)),a.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?a.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:a.allowAbsoluteUrls=!0),Vl.assertOptions(a,{baseUrl:Ma.spelling("baseURL"),withXsrfToken:Ma.spelling("withXSRFToken")},!0),a.method=(a.method||this.defaults.method||"get").toLowerCase();let u=o&&Z.merge(o.common,o[a.method]);o&&Z.forEach(["delete","get","head","post","put","patch","common"],S=>{delete o[S]}),a.headers=An.concat(u,o);const d=[];let f=!0;this.interceptors.request.forEach(function(A){typeof A.runWhen=="function"&&A.runWhen(a)===!1||(f=f&&A.synchronous,d.unshift(A.fulfilled,A.rejected))});const g=[];this.interceptors.response.forEach(function(A){g.push(A.fulfilled,A.rejected)});let m,b=0,v;if(!f){const S=[mp.bind(this),void 0];for(S.unshift(...d),S.push(...g),v=S.length,m=Promise.resolve(a);b<v;)m=m.then(S[b++],S[b++]);return m}v=d.length;let E=a;for(;b<v;){const S=d[b++],A=d[b++];try{E=S(E)}catch(T){A.call(this,T);break}}try{m=mp.call(this,E)}catch(S){return Promise.reject(S)}for(b=0,v=g.length;b<v;)m=m.then(g[b++],g[b++]);return m}getUri(e){e=di(this.defaults,e);const a=ip(e.baseURL,e.url,e.allowAbsoluteUrls);return Xg(a,e.params,e.paramsSerializer)}};Z.forEach(["delete","get","head","options"],function(e){fi.prototype[e]=function(a,r){return this.request(di(r||{},{method:e,url:a,data:(r||{}).data}))}}),Z.forEach(["post","put","patch"],function(e){function a(r){return function(o,u,d){return this.request(di(d||{},{method:e,headers:r?{"Content-Type":"multipart/form-data"}:{},url:o,data:u}))}}fi.prototype[e]=a(),fi.prototype[e+"Form"]=a(!0)});let Fw=class nS{constructor(e){if(typeof e!="function")throw new TypeError("executor must be a function.");let a;this.promise=new Promise(function(o){a=o});const r=this;this.promise.then(i=>{if(!r._listeners)return;let o=r._listeners.length;for(;o-- >0;)r._listeners[o](i);r._listeners=null}),this.promise.then=i=>{let o;const u=new Promise(d=>{r.subscribe(d),o=d}).then(i);return u.cancel=function(){r.unsubscribe(o)},u},e(function(o,u,d){r.reason||(r.reason=new Fi(o,u,d),a(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;const a=this._listeners.indexOf(e);a!==-1&&this._listeners.splice(a,1)}toAbortSignal(){const e=new AbortController,a=r=>{e.abort(r)};return this.subscribe(a),e.signal.unsubscribe=()=>this.unsubscribe(a),e.signal}static source(){let e;return{token:new nS(function(i){e=i}),cancel:e}}};function Kw(l){return function(a){return l.apply(null,a)}}function Ww(l){return Z.isObject(l)&&l.isAxiosError===!0}const cd={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(cd).forEach(([l,e])=>{cd[e]=l});function vp(l){const e=new fi(l),a=Ng(fi.prototype.request,e);return Z.extend(a,fi.prototype,e,{allOwnKeys:!0}),Z.extend(a,e,null,{allOwnKeys:!0}),a.create=function(i){return vp(di(l,i))},a}const jt=vp(eo);jt.Axios=fi,jt.CanceledError=Fi,jt.CancelToken=Fw,jt.isCancel=tp,jt.VERSION=yp,jt.toFormData=Ul,jt.AxiosError=Ye,jt.Cancel=jt.CanceledError,jt.all=function(e){return Promise.all(e)},jt.spread=Kw,jt.isAxiosError=Ww,jt.mergeConfig=di,jt.AxiosHeaders=An,jt.formToJSON=l=>Zg(Z.isHTMLForm(l)?new FormData(l):l),jt.getAdapter=pp.getAdapter,jt.HttpStatusCode=cd,jt.default=jt;const{Ax Line truncated `+o):r.stack=o}catch{}}throw r}}_request(e,a){typeof e=="string"?(a=a||{},a.url=e):a=e||{},a=di(this.defaults,a);const{transitional:r,paramsSerializer:i,headers:o}=a;r!==void 0&&Vl.assertOptions(r,{silentJSONParsing:Ma.transitional(Ma.boolean),forcedJSONParsing:Ma.transitional(Ma.boolean),clarifyTimeoutError:Ma.transitional(Ma.boolean)},!1),i!=null&&(Z.isFunction(i)?a.paramsSerializer={serialize:i}:Vl.assertOptions(i,{encode:Ma.function,serialize:Ma.function},!0)),a.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?a.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:a.allowAbsoluteUrls=!0),Vl.assertOptions(a,{baseUrl:Ma.spelling("baseURL"),withXsrfToken:Ma.spelling("withXSRFToken")},!0),a.method=(a.method||this.defaults.method||"get").toLowerCase();let u=o&&Z.merge(o.common,o[a.method]);o&&Z.forEach(["delete","get","head","post","put","patch","common"],S=>{delete o[S]}),a.headers=xn.concat(u,o);const d=[];let f=!0;this.interceptors.request.forEach(function(A){typeof A.runWhen=="function"&&A.runWhen(a)===!1||(f=f&&A.synchronous,d.unshift(A.fulfilled,A.rejected))});const g=[];this.interceptors.response.forEach(function(A){g.push(A.fulfilled,A.rejected)});let m,b=0,v;if(!f){const S=[mp.bind(this),void 0];for(S.unshift(...d),S.push(...g),v=S.length,m=Promise.resolve(a);b<v;)m=m.then(S[b++],S[b++]);return m}v=d.length;let E=a;for(;b<v;){const S=d[b++],A=d[b++];try{E=S(E)}catch(T){A.call(this,T);break}}try{m=mp.call(this,E)}catch(S){return Promise.reject(S)}for(b=0,v=g.length;b<v;)m=m.then(g[b++],g[b++]);return m}getUri(e){e=di(this.defaults,e);const a=ip(e.baseURL,e.url,e.allowAbsoluteUrls);return Xg(a,e.params,e.paramsSerializer)}};Z.forEach(["delete","get","head","options"],function(e){fi.prototype[e]=function(a,r){return this.request(di(r||{},{method:e,url:a,data:(r||{}).data}))}}),Z.forEach(["post","put","patch"],function(e){function a(r){return function(o,u,d){return this.request(di(d||{},{method:e,headers:r?{"Content-Type":"multipart/form-data"}:{},url:o,data:u}))}}fi.prototype[e]=a(),fi.prototype[e+"Form"]=a(!0)});let Kw=class aS{constructor(e){if(typeof e!="function")throw new TypeError("executor must be a function.");let a;this.promise=new Promise(function(o){a=o});const r=this;this.promise.then(i=>{if(!r._listeners)return;let o=r._listeners.length;for(;o-- >0;)r._listeners[o](i);r._listeners=null}),this.promise.then=i=>{let o;const u=new Promise(d=>{r.subscribe(d),o=d}).then(i);return u.cancel=function(){r.unsubscribe(o)},u},e(function(o,u,d){r.reason||(r.reason=new Fi(o,u,d),a(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;const a=this._listeners.indexOf(e);a!==-1&&this._listeners.splice(a,1)}toAbortSignal(){const e=new AbortController,a=r=>{e.abort(r)};return this.subscribe(a),e.signal.unsubscribe=()=>this.unsubscribe(a),e.signal}static source(){let e;return{token:new aS(function(i){e=i}),cancel:e}}};function Ww(l){return function(a){return l.apply(null,a)}}function Yw(l){return Z.isObject(l)&&l.isAxiosError===!0}const cd={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(cd).forEach(([l,e])=>{cd[e]=l});function vp(l){const e=new fi(l),a=Ng(fi.prototype.request,e);return Z.extend(a,fi.prototype,e,{allOwnKeys:!0}),Z.extend(a,e,null,{allOwnKeys:!0}),a.create=function(i){return vp(di(l,i))},a}const Ut=vp(eo);Ut.Axios=fi,Ut.CanceledError=Fi,Ut.CancelToken=Kw,Ut.isCancel=tp,Ut.VERSION=yp,Ut.toFormData=Ul,Ut.AxiosError=Ye,Ut.Cancel=Ut.CanceledError,Ut.all=function(e){return Promise.all(e)},Ut.spread=Ww,Ut.isAxiosError=Yw,Ut.mergeConfig=di,Ut.AxiosHeaders=xn,Ut.formToJSON=l=>Zg(Z.isHTMLForm(l)?new FormData(l):l),Ut.getAdapter=pp.getAdapter,Ut.HttpStatusCode=cd,Ut.default=Ut;const{Ax Line truncated
* @license React * @license React
* react-jsx-runtime.production.js * react-jsx-runtime.production.js
* *
@@ -51,7 +51,7 @@ Error generating stack: `+c.message+`
* *
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/var wp;function Zw(){if(wp)return ao;wp=1;var l=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function a(r,i,o){var u=null;if(o!==void 0&&(u=""+o),i.key!==void 0&&(u=""+i.key),"key"in i){o={};for(var d in i)d!=="key"&&(o[d]=i[d])}else o=i;return i=o.ref,{$$typeof:l,type:r,key:u,ref:i!==void 0?i:null,props:o}}return ao.Fragment=e,ao.jsx=a,ao.jsxs=a,ao}var Cp;function e0(){return Cp||(Cp=1,gd.exports=Zw()),gd.exports}var ct=e0();const t0=Ka({__proto__:null,default:Wa(ct)},[ct]),pd=dt("ParentContextProvider"),Ep=N.createContext(null);let Wl=null;function md(){Wl?(pd.log("[triggerModalParentUpdate] 모달 부모 컨텍스트 업데이트 트리거"),Wl()):pd.warn("[triggerModalParentUpdate] Provider가 아직 마운트되지 않음")}const _p=({children:l})=>{const[e,a]=N.useState(0),r=N.useRef(!0),i=N.useCallback(()=>{const u=window.__g7LayoutContextStack||[];return u[u.length-1]?.dataContext},[]);N.useEffect(()=>(r.current=!0,Wl=()=>{r.current&&(a(u=>u+1),pd.log("[ParentContextProvider] 버전 업데이트됨"))},()=>{r.current=!1,Wl=null}),[]);const o={version:e,getParentDataContext:i};return ct.jsx(Ep.Provider,{value:o,children:l})};function n0(){return N.useContext(Ep)}const z=dt("ActionDispatcher"),Ap=new Set(["navigate","navigateBack","navigateForward","replaceUrl","refresh","logout"]),a0=new Set(["redirect"]);function jn(){try{return window.G7Core?.devTools}catch{return}}class Mt extends Error{constructor(e,a,r){super(e),this.action=a,this.originalError=r,this.name="ActionError"}}const ns=class ns{constructor(e={},a,r){$(this,"bindingEngine");$(this,"translationEngine");$(this,"translationContext");$(this,"customHandlers",new Map);$(this,"defaultContext");$(this,"globalStateUpdater");$(this,"errorHandlingSetup",!1);$(this,"debounceTimers",new Map);$(this,"pendingDebounceFlushers",new Map);$(this,"debounceAccumulatedValues",new Map);$(this,"globalHeaders",[]);$(this,"namedActions",{});$(this,"previewMode",!1);$(this,"intervals",new Map);this.bindingEngine=new vn,this.translationEngine=a,this.translationContext=r,this.defaultContext=e,this.registerDefaultHandlers(),this.setupErrorHandling()}setGlobalHeaders(e){this.globalHeaders=e||[]}setNamedActions(e){this.namedActions=e||{};const a=jn();a?.isEnabled?.()&&a.setNamedActionDefinitions?.(this.namedActions),z.log("[setNamedActions] registered:",Object.keys(this.namedActions))}getNamedActions(){return this.namedActions}setPreviewMode(e){this.previewMode=e,z.log("Preview mode:",e?"enabled":"disabled")}isPreviewMode(){return this.previewMode}static getPreviewSuppressedHandlers(){return Ap}static getPreviewSuppressedLayoutFeatures(){return a0}resolveActionRef(e){if(!e.actionRef)return e;const a=this.namedActions[e.actionRef];if(!a)return z.warn(`[resolveActionRef] named action not found: "${e.actionRef}"`),e;const r=jn();r?.isEnabled?.()&&r.trackNamedActionRef?.({actionRefName:e.actionRef,resolvedHandler:a.handler,timestamp:Date.now()});const{actionRef:i,type:o,key:u,event:d,...f}=e,g={...a,...Object.fromEntries(Object.entries(f).filter(([,m])=>m!==void 0)),type:o??a.type};return u!==void 0&&(g.key=u),d!==void 0&&(g.event=d),g}matchesPattern(e,a){if(a==="*")return!0;const r=a.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${r}$`).test(e)}getMatchingGlobalHeaders(e,a){const r={};for(const i of this.globalHeaders)this.matchesPattern(e,i.pattern)&&Object.entries(i.headers).forEach(([o,u])=>{const d=Pi(u,a,{skipCache:!0});d!=null&&d!==""&&(r[o]=String(d))});return r}setupErrorHandling(){if(this.errorHandlingSetup)return;ma().setActionExecutor(async(a,r)=>{const i={type:"click",handler:a.handler,target:a.target,params:a.params,actions:a.actions},o={data:{...this.defaultContext.data,error:r.error}};return await this.dispatchAction(i,o)}),this.errorHandlingSetup=!0}registerDefaultHandlers(){this.registerHandler("refetchDataSource",async(a,r)=>{const i=a.params?.dataSourceId,o=a.params?.sync;if(!i){z.warn("refetchDataSource: dataSourceId is required");return}if(typeof window<"u"&&window.G7Core?.dataSource?.refetch){const u=window.G7Core?.state?.get?.()||{},d={...r.state?._global,...u},f=window.G7Core?.state?.getLocal?.()||{},g=r.data?._local||r.state||{},m={...f,...g},b=r.isolatedContext?.state;z.log("[refetchDataSource] localStateOverride:",m),await window.G7Core.dataSource.refetch(i,{...o?{sync:!0}:{},...d?{globalStateOverride:d}:{},...m?{localStateOverride:m}:{},...b?{isolatedStateOverride:b}:{}})}else z.warn("refetchDataSource: G7Core.dataSource.refetch is not available")}),this.registerHandler("appendDataSource",async(a,r)=>{const{dataSourceId:i,dataPath:o,newData:u}=a.params||{};if(!i){z.warn("appendDataSource: dataSourceId is required");return}if(u===void 0){z.warn("appendDataSource: newData is required");return}if(typeof window<"u"&&window.G7Core?.dataSource?.updateData){if(!Array.isArray(u)){z.warn("appendDataSource: newData must be an array, got:",typeof u,u);return}await window.G7Core.dataSource.updLine truncated */var wp;function e0(){if(wp)return ao;wp=1;var l=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function a(r,i,o){var u=null;if(o!==void 0&&(u=""+o),i.key!==void 0&&(u=""+i.key),"key"in i){o={};for(var d in i)d!=="key"&&(o[d]=i[d])}else o=i;return i=o.ref,{$$typeof:l,type:r,key:u,ref:i!==void 0?i:null,props:o}}return ao.Fragment=e,ao.jsx=a,ao.jsxs=a,ao}var Cp;function t0(){return Cp||(Cp=1,gd.exports=e0()),gd.exports}var ct=t0();const n0=Ka({__proto__:null,default:Wa(ct)},[ct]),pd=dt("ParentContextProvider"),Ep=N.createContext(null);let Wl=null;function md(){Wl?(pd.log("[triggerModalParentUpdate] 모달 부모 컨텍스트 업데이트 트리거"),Wl()):pd.warn("[triggerModalParentUpdate] Provider가 아직 마운트되지 않음")}const _p=({children:l})=>{const[e,a]=N.useState(0),r=N.useRef(!0),i=N.useCallback(()=>{const u=window.__g7LayoutContextStack||[];return u[u.length-1]?.dataContext},[]);N.useEffect(()=>(r.current=!0,Wl=()=>{r.current&&(a(u=>u+1),pd.log("[ParentContextProvider] 버전 업데이트됨"))},()=>{r.current=!1,Wl=null}),[]);const o={version:e,getParentDataContext:i};return ct.jsx(Ep.Provider,{value:o,children:l})};function a0(){return N.useContext(Ep)}const z=dt("ActionDispatcher"),Ap=new Set(["navigate","navigateBack","navigateForward","replaceUrl","refresh","logout"]),r0=new Set(["redirect"]);function jn(){try{return window.G7Core?.devTools}catch{return}}class Mt extends Error{constructor(e,a,r){super(e),this.action=a,this.originalError=r,this.name="ActionError"}}const ns=class ns{constructor(e={},a,r){$(this,"bindingEngine");$(this,"translationEngine");$(this,"translationContext");$(this,"customHandlers",new Map);$(this,"defaultContext");$(this,"globalStateUpdater");$(this,"errorHandlingSetup",!1);$(this,"debounceTimers",new Map);$(this,"pendingDebounceFlushers",new Map);$(this,"debounceAccumulatedValues",new Map);$(this,"globalHeaders",[]);$(this,"namedActions",{});$(this,"previewMode",!1);$(this,"intervals",new Map);this.bindingEngine=new Sn,this.translationEngine=a,this.translationContext=r,this.defaultContext=e,this.registerDefaultHandlers(),this.setupErrorHandling()}setGlobalHeaders(e){this.globalHeaders=e||[]}setNamedActions(e){this.namedActions=e||{};const a=jn();a?.isEnabled?.()&&a.setNamedActionDefinitions?.(this.namedActions),z.log("[setNamedActions] registered:",Object.keys(this.namedActions))}getNamedActions(){return this.namedActions}setPreviewMode(e){this.previewMode=e,z.log("Preview mode:",e?"enabled":"disabled")}isPreviewMode(){return this.previewMode}static getPreviewSuppressedHandlers(){return Ap}static getPreviewSuppressedLayoutFeatures(){return r0}resolveActionRef(e){if(!e.actionRef)return e;const a=this.namedActions[e.actionRef];if(!a)return z.warn(`[resolveActionRef] named action not found: "${e.actionRef}"`),e;const r=jn();r?.isEnabled?.()&&r.trackNamedActionRef?.({actionRefName:e.actionRef,resolvedHandler:a.handler,timestamp:Date.now()});const{actionRef:i,type:o,key:u,event:d,...f}=e,g={...a,...Object.fromEntries(Object.entries(f).filter(([,m])=>m!==void 0)),type:o??a.type};return u!==void 0&&(g.key=u),d!==void 0&&(g.event=d),g}matchesPattern(e,a){if(a==="*")return!0;const r=a.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${r}$`).test(e)}getMatchingGlobalHeaders(e,a){const r={};for(const i of this.globalHeaders)this.matchesPattern(e,i.pattern)&&Object.entries(i.headers).forEach(([o,u])=>{const d=Pi(u,a,{skipCache:!0});d!=null&&d!==""&&(r[o]=String(d))});return r}setupErrorHandling(){if(this.errorHandlingSetup)return;ma().setActionExecutor(async(a,r)=>{const i={type:"click",handler:a.handler,target:a.target,params:a.params,actions:a.actions},o={data:{...this.defaultContext.data,error:r.error}};return await this.dispatchAction(i,o)}),this.errorHandlingSetup=!0}registerDefaultHandlers(){this.registerHandler("refetchDataSource",async(a,r)=>{const i=a.params?.dataSourceId,o=a.params?.sync;if(!i){z.warn("refetchDataSource: dataSourceId is required");return}if(typeof window<"u"&&window.G7Core?.dataSource?.refetch){const u=window.G7Core?.state?.get?.()||{},d={...r.state?._global,...u},f=window.G7Core?.state?.getLocal?.()||{},g=r.data?._local||r.state||{},m={...f,...g},b=r.isolatedContext?.state;z.log("[refetchDataSource] localStateOverride:",m),await window.G7Core.dataSource.refetch(i,{...o?{sync:!0}:{},...d?{globalStateOverride:d}:{},...m?{localStateOverride:m}:{},...b?{isolatedStateOverride:b}:{}})}else z.warn("refetchDataSource: G7Core.dataSource.refetch is not available")}),this.registerHandler("appendDataSource",async(a,r)=>{const{dataSourceId:i,dataPath:o,newData:u}=a.params||{};if(!i){z.warn("appendDataSource: dataSourceId is required");return}if(u===void 0){z.warn("appendDataSource: newData is required");return}if(typeof window<"u"&&window.G7Core?.dataSource?.updateData){if(!Array.isArray(u)){z.warn("appendDataSource: newData must be an array, got:",typeof u,u);return}await window.G7Core.dataSource.updLine truncated
position: fixed; position: fixed;
inset: 0; inset: 0;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
@@ -84,11 +84,11 @@ Error generating stack: `+c.message+`
justify-content: center; justify-content: center;
color: #666; color: #666;
transition: background-color 0.2s; transition: background-color 0.2s;
`,i.onmouseenter=()=>{i.style.backgroundColor="rgba(0, 0, 0, 0.2)"},i.onmouseleave=()=>{i.style.backgroundColor="rgba(0, 0, 0, 0.1)"};const o=()=>{a.parentNode&&a.parentNode.removeChild(a)};i.onclick=o;const u=d=>{this.isImeComposing(d)||d.key==="Escape"&&(o(),document.removeEventListener("keydown",u))};return document.addEventListener("keydown",u),a.onclick=d=>{d.target===a&&o()},r.appendChild(i),a.appendChild(r),document.body.appendChild(a),{overlay:a,layer:r,closeLayer:o}}getNestedProperty(e,a){return a.split(".").reduce((r,i)=>r&&r[i]!==void 0?r[i]:void 0,e)}async handleSaveToLocalStorage(e,a){const{key:r,value:i}=e;if(!r)return z.error("saveToLocalStorage: key parameter is required"),!1;try{const o=typeof i=="string"?i:JSON.stringify(i);return localStorage.setItem(r,o),z.log(`saveToLocalStorage: saved ${r}`,i),!0}catch(o){return z.error("saveToLocalStorage: failed to save",{key:r,error:o}),!1}}async handleLoadFromLocalStorage(e,a){const{key:r,target:i,stateKey:o,defaultValue:u}=e;if(!r)return z.error("loadFromLocalStorage: key parameter is required"),u;try{const d=localStorage.getItem(r);if(d===null)return z.log(`loadFromLocalStorage: no value found for ${r}, using default`),o&&a.setState&&a.setState({[o]:u}),u;let f;try{f=JSON.parse(d)}catch{f=d}return z.log(`loadFromLocalStorage: loaded ${r}`,f),o&&a.setState&&a.setState({[o]:f}),f}catch(d){return z.error("loadFromLocalStorage: failed to load",{key:r,error:d}),u}}async handleCustomAction(e,a){const r=this.customHandlers.get(e.handler);if(!r){if(this.previewMode){z.warn(`[Preview] Unknown action handler "${e.handler}" — skipped (preview mode)`);return}throw new Mt(`Unknown action handler: ${e.handler}`,e)}return await r(e,a)}resolveParams(e,a){if(!e)return{};const r={};for(const[i,o]of Object.entries(e))i.includes("{{")&&z.warn(`[resolveParams] setState params의 키에 표현식이 포함되어 있습니다: "${i}". 키는 해석되지 않습니다. 배열 항목 수정은 .map()/.filter() 패턴을 사용하세요.`),typeof o=="string"&&o.includes("{{")?r[i]=this.evaluateExpression(o,a):typeof o=="string"?r[i]=o:Array.isArray(o)?r[i]=o.map(u=>typeof u=="string"&&u.includes("{{")?this.evaluateExpression(u,a):u):typeof o=="object"&&o!==null&&!Array.isArray(o)&&Object.getPrototypeOf(o)!==Object.prototype&&Object.getPrototypeOf(o)!==null?r[i]=o:typeof o=="object"&&o!==null?r[i]=this.resolveParams(o,a):r[i]=o;return r}resolveValue(e,a){return a?this.bindingEngine.resolveBindings(e,a,{skipCache:!0}):e}evaluateExpressions(e,a){let r={};for(const[i,o]of Object.entries(e))if(i==="..."){let u=o;typeof o=="string"&&o.includes("{{")&&(u=this.evaluateExpression(o,a)),u&&typeof u=="object"&&!Array.isArray(u)&&(r={...r,...u})}else typeof o=="string"&&o.includes("{{")?r[i]=this.evaluateExpression(o,a):typeof o=="object"&&o!==null&&!Array.isArray(o)?r[i]=this.evaluateExpressions(o,a):r[i]=o;return r}evaluateExpressionsIfNeeded(e,a){const r={};for(const[i,o]of Object.entries(e))typeof o=="string"&&o.includes("{{")?r[i]=this.evaluateExpression(o,a):r[i]=o;return r}evaluateExpression(e,a){if(!a)return e;const r=e.match(/^\{\{(.+)\}\}$/);if(!(r&&!r[1].includes("}}")&&!r[1].includes("{{"))){let d=a;if(e.includes("_global")){const g=window.G7Core?.state?.get()?._global;g&&(d={...a,_global:g})}if(e.includes("_computed")||e.includes("$computed")){const g=window.__g7ActionContext?.computedRef?.current;g&&Object.keys(g).length>0&&(d={...d,_computed:g,$computed:g})}return this.bindingEngine.resolveBindings(e,d,{skipCache:!0})}let o=r[1].trim();o=o.replace(/\$args\.(\d+)/g,"$args[$1]");let u=a;if(o.includes("_global")){const f=window.G7Core?.state?.get()?._global;f&&(u={...a,_global:f})}if(o.includes("_computed")||o.includes("$computed")){const f=window.__g7ActionContext?.computedRef?.current;f&&Object.keys(f).length>0&&(u={...u,_computed:f,$computed:f})}o.includes("_global.modules")&&(z.log("[evaluateExpression] expression:",o),z.log("[evaluateExpression] dataContext._global:",u._global),z.log("[evaluateExpression] dataContext._global?.modules:",u._global?.modules));try{const d=this.bindingEngine.evaluateExpression(o,u);return o.includes("_global.modules")&&z.log("[evaluateExpression] result:",d),typeof d=="string"&&d.startsWith("$t:")&&this.translationEngine&&this.translationContext?this.translationEngine.resolveTranslations(d,this.translationContext,a):d}catch(d){return z.error("Expression evaluation failed:",e,d),e}}setDefaultContext(e){this.defaultContext={...this.defaultContext,...e}}setGlobalStateUpdater(e){this.globalStateUpdater=e}getGlobalStateUpdater(){return this.globalStateUpdater}async dispatchAction(e,a){const r={...this.defaultContext,...a,data:{...this.defaultContext.data,...a?.data}};if(e.confirm){let i=this.resolveValue(e.confirm,r.data);if(this.translationEngine&&this.translationContext&&i.startsWith("$t:")&&(i=this.translationEngine.resolveTranslations(i,this.translationContext,r.data)),!confirm(i))return{success:!1}}try{return await this.executeActi Line truncated `,i.onmouseenter=()=>{i.style.backgroundColor="rgba(0, 0, 0, 0.2)"},i.onmouseleave=()=>{i.style.backgroundColor="rgba(0, 0, 0, 0.1)"};const o=()=>{a.parentNode&&a.parentNode.removeChild(a)};i.onclick=o;const u=d=>{this.isImeComposing(d)||d.key==="Escape"&&(o(),document.removeEventListener("keydown",u))};return document.addEventListener("keydown",u),a.onclick=d=>{d.target===a&&o()},r.appendChild(i),a.appendChild(r),document.body.appendChild(a),{overlay:a,layer:r,closeLayer:o}}getNestedProperty(e,a){return a.split(".").reduce((r,i)=>r&&r[i]!==void 0?r[i]:void 0,e)}async handleSaveToLocalStorage(e,a){const{key:r,value:i}=e;if(!r)return z.error("saveToLocalStorage: key parameter is required"),!1;try{const o=typeof i=="string"?i:JSON.stringify(i);return localStorage.setItem(r,o),z.log(`saveToLocalStorage: saved ${r}`,i),!0}catch(o){return z.error("saveToLocalStorage: failed to save",{key:r,error:o}),!1}}async handleLoadFromLocalStorage(e,a){const{key:r,target:i,stateKey:o,defaultValue:u}=e;if(!r)return z.error("loadFromLocalStorage: key parameter is required"),u;try{const d=localStorage.getItem(r);if(d===null)return z.log(`loadFromLocalStorage: no value found for ${r}, using default`),o&&a.setState&&a.setState({[o]:u}),u;let f;try{f=JSON.parse(d)}catch{f=d}return z.log(`loadFromLocalStorage: loaded ${r}`,f),o&&a.setState&&a.setState({[o]:f}),f}catch(d){return z.error("loadFromLocalStorage: failed to load",{key:r,error:d}),u}}async handleCustomAction(e,a){const r=this.customHandlers.get(e.handler);if(!r){if(this.previewMode){z.warn(`[Preview] Unknown action handler "${e.handler}" — skipped (preview mode)`);return}throw new Mt(`Unknown action handler: ${e.handler}`,e)}return await r(e,a)}resolveParams(e,a){if(!e)return{};const r={};for(const[i,o]of Object.entries(e))i.includes("{{")&&z.warn(`[resolveParams] setState params의 키에 표현식이 포함되어 있습니다: "${i}". 키는 해석되지 않습니다. 배열 항목 수정은 .map()/.filter() 패턴을 사용하세요.`),typeof o=="string"&&o.includes("{{")?r[i]=this.evaluateExpression(o,a):typeof o=="string"?r[i]=o:Array.isArray(o)?r[i]=o.map(u=>typeof u=="string"&&u.includes("{{")?this.evaluateExpression(u,a):u):typeof o=="object"&&o!==null&&!Array.isArray(o)&&Object.getPrototypeOf(o)!==Object.prototype&&Object.getPrototypeOf(o)!==null?r[i]=o:typeof o=="object"&&o!==null?r[i]=this.resolveParams(o,a):r[i]=o;return r}resolveValue(e,a){return a?this.bindingEngine.resolveBindings(e,a,{skipCache:!0}):e}evaluateExpressions(e,a){let r={};for(const[i,o]of Object.entries(e))if(i==="..."){let u=o;typeof o=="string"&&o.includes("{{")&&(u=this.evaluateExpression(o,a)),u&&typeof u=="object"&&!Array.isArray(u)&&(r={...r,...u})}else typeof o=="string"&&o.includes("{{")?r[i]=this.evaluateExpression(o,a):typeof o=="object"&&o!==null&&!Array.isArray(o)?r[i]=this.evaluateExpressions(o,a):r[i]=o;return r}evaluateExpressionsIfNeeded(e,a){const r={};for(const[i,o]of Object.entries(e))typeof o=="string"&&o.includes("{{")?r[i]=this.evaluateExpression(o,a):r[i]=o;return r}evaluateExpression(e,a){if(!a)return e;const r=e.match(/^\{\{(.+)\}\}$/);if(!(r&&!r[1].includes("}}")&&!r[1].includes("{{"))){let d=a;if(e.includes("_global")){const g=window.G7Core?.state?.get()?._global;g&&(d={...a,_global:g})}if(e.includes("_computed")||e.includes("$computed")){const g=window.__g7ActionContext?.computedRef?.current;g&&Object.keys(g).length>0&&(d={...d,_computed:g,$computed:g})}return this.bindingEngine.resolveBindings(e,d,{skipCache:!0})}let o=r[1].trim();o=o.replace(/\$args\.(\d+)/g,"$args[$1]");let u=a;if(o.includes("_global")){const f=window.G7Core?.state?.get()?._global;f&&(u={...a,_global:f})}if(o.includes("_computed")||o.includes("$computed")){const f=window.__g7ActionContext?.computedRef?.current;f&&Object.keys(f).length>0&&(u={...u,_computed:f,$computed:f})}o.includes("_global.modules")&&(z.log("[evaluateExpression] expression:",o),z.log("[evaluateExpression] dataContext._global:",u._global),z.log("[evaluateExpression] dataContext._global?.modules:",u._global?.modules));try{const d=this.bindingEngine.evaluateExpression(o,u);return o.includes("_global.modules")&&z.log("[evaluateExpression] result:",d),typeof d=="string"&&d.startsWith("$t:")&&this.translationEngine&&this.translationContext?this.translationEngine.resolveTranslations(d,this.translationContext,a):d}catch(d){return z.error("Expression evaluation failed:",e,d),e}}setDefaultContext(e){this.defaultContext={...this.defaultContext,...e}}setGlobalStateUpdater(e){this.globalStateUpdater=e}getGlobalStateUpdater(){return this.globalStateUpdater}async dispatchAction(e,a){const r={...this.defaultContext,...a,data:{...this.defaultContext.data,...a?.data}};if(e.confirm){let i=this.resolveValue(e.confirm,r.data);if(this.translationEngine&&this.translationContext&&i.startsWith("$t:")&&(i=this.translationEngine.resolveTranslations(i,this.translationContext,r.data)),!confirm(i))return{success:!1}}try{return await this.executeActi Line truncated
To pick up a draggable item, press the space bar. To pick up a draggable item, press the space bar.
While dragging, use the arrow keys to move the item. While dragging, use the arrow keys to move the item.
Press space again to drop the item in its new position, or press escape to cancel. Press space again to drop the item in its new position, or press escape to cancel.
`},L0={onDragStart(l){let{active:e}=l;return"Picked up draggable item "+e.id+"."},onDragOver(l){let{active:e,over:a}=l;return a?"Draggable item "+e.id+" was moved over droppable area "+a.id+".":"Draggable item "+e.id+" is no longer over a droppable area."},onDragEnd(l){let{active:e,over:a}=l;return a?"Draggable item "+e.id+" was dropped over droppable area "+a.id:"Draggable item "+e.id+" was dropped."},onDragCancel(l){let{active:e}=l;return"Dragging was cancelled. Draggable item "+e.id+" was dropped."}};function M0(l){let{announcements:e=L0,container:a,hiddenTextDescribedById:r,screenReaderInstructions:i=O0}=l;const{announce:o,announcement:u}=k0(),d=lo("DndLiveRegion"),[f,g]=N.useState(!1);if(N.useEffect(()=>{g(!0)},[]),R0(N.useMemo(()=>({onDragStart(b){let{active:v}=b;o(e.onDragStart({active:v}))},onDragMove(b){let{active:v,over:E}=b;e.onDragMove&&o(e.onDragMove({active:v,over:E}))},onDragOver(b){let{active:v,over:E}=b;o(e.onDragOver({active:v,over:E}))},onDragEnd(b){let{active:v,over:E}=b;o(e.onDragEnd({active:v,over:E}))},onDragCancel(b){let{active:v,over:E}=b;o(e.onDragCancel({active:v,over:E}))}}),[o,e])),!f)return null;const m=We.createElement(We.Fragment,null,We.createElement(x0,{id:r,value:i.draggable}),We.createElement(T0,{id:d,announcement:u}));return a?Ar.createPortal(m,a):m}var Jt;(function(l){l.DragStart="dragStart",l.DragMove="dragMove",l.DragEnd="dragEnd",l.DragCancel="dragCancel",l.DragOver="dragOver",l.RegisterDroppable="registerDroppable",l.SetDroppableDisabled="setDroppableDisabled",l.UnregisterDroppable="unregisterDroppable"})(Jt||(Jt={}));function ec(){}function jp(l,e){return N.useMemo(()=>({sensor:l,options:e??{}}),[l,e])}function $0(){for(var l=arguments.length,e=new Array(l),a=0;a<l;a++)e[a]=arguments[a];return N.useMemo(()=>[...e].filter(r=>r!=null),[...e])}const ya=Object.freeze({x:0,y:0});function Up(l,e){return Math.sqrt(Math.pow(l.x-e.x,2)+Math.pow(l.y-e.y,2))}function Bp(l,e){let{data:{value:a}}=l,{data:{value:r}}=e;return a-r}function N0(l,e){let{data:{value:a}}=l,{data:{value:r}}=e;return r-a}function qp(l){let{left:e,top:a,height:r,width:i}=l;return[{x:e,y:a},{x:e+i,y:a},{x:e,y:a+r},{x:e+i,y:a+r}]}function Pp(l,e){if(!l||l.length===0)return null;const[a]=l;return a[e]}function Gp(l,e,a){return e===void 0&&(e=l.left),a===void 0&&(a=l.top),{x:e+l.width*.5,y:a+l.height*.5}}const H0=l=>{let{collisionRect:e,droppableRects:a,droppableContainers:r}=l;const i=Gp(e,e.left,e.top),o=[];for(const u of r){const{id:d}=u,f=a.get(d);if(f){const g=Up(Gp(f),i);o.push({id:d,data:{droppableContainer:u,value:g}})}}return o.sort(Bp)},z0=l=>{let{collisionRect:e,droppableRects:a,droppableContainers:r}=l;const i=qp(e),o=[];for(const u of r){const{id:d}=u,f=a.get(d);if(f){const g=qp(f),m=i.reduce((v,E,S)=>v+Up(g[S],E),0),b=Number((m/4).toFixed(4));o.push({id:d,data:{droppableContainer:u,value:b}})}}return o.sort(Bp)};function I0(l,e){const a=Math.max(e.top,l.top),r=Math.max(e.left,l.left),i=Math.min(e.left+e.width,l.left+l.width),o=Math.min(e.top+e.height,l.top+l.height),u=i-r,d=o-a;if(r<i&&a<o){const f=e.width*e.height,g=l.width*l.height,m=u*d,b=m/(f+g-m);return Number(b.toFixed(4))}return 0}const j0=l=>{let{collisionRect:e,droppableRects:a,droppableContainers:r}=l;const i=[];for(const o of r){const{id:u}=o,d=a.get(u);if(d){const f=I0(d,e);f>0&&i.push({id:u,data:{droppableContainer:o,value:f}})}}return i.sort(N0)};function U0(l,e,a){return{...l,scaleX:e&&a?e.width/a.width:1,scaleY:e&&a?e.height/a.height:1}}function Vp(l,e){return l&&e?{x:l.left-e.left,y:l.top-e.top}:ya}function B0(l){return function(a){for(var r=arguments.length,i=new Array(r>1?r-1:0),o=1;o<r;o++)i[o-1]=arguments[o];return i.reduce((u,d)=>({...u,top:u.top+l*d.y,bottom:u.bottom+l*d.y,left:u.left+l*d.x,right:u.right+l*d.x}),{...a})}}const q0=B0(1);function P0(l){if(l.startsWith("matrix3d(")){const e=l.slice(9,-1).split(/, /);return{x:+e[12],y:+e[13],scaleX:+e[0],scaleY:+e[5]}}else if(l.startsWith("matrix(")){const e=l.slice(7,-1).split(/, /);return{x:+e[4],y:+e[5],scaleX:+e[0],scaleY:+e[3]}}return null}function G0(l,e,a){const r=P0(e);if(!r)return l;const{scaleX:i,scaleY:o,x:u,y:d}=r,f=l.left-u-(1-i)*parseFloat(a),g=l.top-d-(1-o)*parseFloat(a.slice(a.indexOf(" ")+1)),m=i?l.width/i:l.width,b=o?l.height/o:l.height;return{width:m,height:b,top:g,right:f+m,bottom:g+b,left:f}}const V0={ignoreTransform:!1};function Ji(l,e){e===void 0&&(e=V0);let a=l.getBoundingClientRect();if(e.ignoreTransform){const{transform:g,transformOrigin:m}=xn(l).getComputedStyle(l);g&&(a=G0(a,g,m))}const{top:r,left:i,width:o,height:u,bottom:d,right:f}=a;return{top:r,left:i,width:o,height:u,bottom:d,right:f}}function Fp(l){return Ji(l,{ignoreTransform:!0})}function F0(l){const e=l.innerWidth,a=l.innerHeight;return{top:0,left:0,right:e,bottom:a,width:e,height:a}}function K0(l,e){return e===void 0&&(e=xn(l).getComputedStyle(l)),e.position==="fixed"}function W0(l,e){e===void 0&&(e=xn(l).getComputedStyle(l));const a=/(auto|scroll|overlay)/;return["overflow","overflowX Line truncated `},M0={onDragStart(l){let{active:e}=l;return"Picked up draggable item "+e.id+"."},onDragOver(l){let{active:e,over:a}=l;return a?"Draggable item "+e.id+" was moved over droppable area "+a.id+".":"Draggable item "+e.id+" is no longer over a droppable area."},onDragEnd(l){let{active:e,over:a}=l;return a?"Draggable item "+e.id+" was dropped over droppable area "+a.id:"Draggable item "+e.id+" was dropped."},onDragCancel(l){let{active:e}=l;return"Dragging was cancelled. Draggable item "+e.id+" was dropped."}};function $0(l){let{announcements:e=M0,container:a,hiddenTextDescribedById:r,screenReaderInstructions:i=L0}=l;const{announce:o,announcement:u}=R0(),d=lo("DndLiveRegion"),[f,g]=N.useState(!1);if(N.useEffect(()=>{g(!0)},[]),D0(N.useMemo(()=>({onDragStart(b){let{active:v}=b;o(e.onDragStart({active:v}))},onDragMove(b){let{active:v,over:E}=b;e.onDragMove&&o(e.onDragMove({active:v,over:E}))},onDragOver(b){let{active:v,over:E}=b;o(e.onDragOver({active:v,over:E}))},onDragEnd(b){let{active:v,over:E}=b;o(e.onDragEnd({active:v,over:E}))},onDragCancel(b){let{active:v,over:E}=b;o(e.onDragCancel({active:v,over:E}))}}),[o,e])),!f)return null;const m=We.createElement(We.Fragment,null,We.createElement(T0,{id:r,value:i.draggable}),We.createElement(k0,{id:d,announcement:u}));return a?Ar.createPortal(m,a):m}var Zt;(function(l){l.DragStart="dragStart",l.DragMove="dragMove",l.DragEnd="dragEnd",l.DragCancel="dragCancel",l.DragOver="dragOver",l.RegisterDroppable="registerDroppable",l.SetDroppableDisabled="setDroppableDisabled",l.UnregisterDroppable="unregisterDroppable"})(Zt||(Zt={}));function ec(){}function jp(l,e){return N.useMemo(()=>({sensor:l,options:e??{}}),[l,e])}function N0(){for(var l=arguments.length,e=new Array(l),a=0;a<l;a++)e[a]=arguments[a];return N.useMemo(()=>[...e].filter(r=>r!=null),[...e])}const ya=Object.freeze({x:0,y:0});function Up(l,e){return Math.sqrt(Math.pow(l.x-e.x,2)+Math.pow(l.y-e.y,2))}function Bp(l,e){let{data:{value:a}}=l,{data:{value:r}}=e;return a-r}function H0(l,e){let{data:{value:a}}=l,{data:{value:r}}=e;return r-a}function qp(l){let{left:e,top:a,height:r,width:i}=l;return[{x:e,y:a},{x:e+i,y:a},{x:e,y:a+r},{x:e+i,y:a+r}]}function Pp(l,e){if(!l||l.length===0)return null;const[a]=l;return a[e]}function Gp(l,e,a){return e===void 0&&(e=l.left),a===void 0&&(a=l.top),{x:e+l.width*.5,y:a+l.height*.5}}const z0=l=>{let{collisionRect:e,droppableRects:a,droppableContainers:r}=l;const i=Gp(e,e.left,e.top),o=[];for(const u of r){const{id:d}=u,f=a.get(d);if(f){const g=Up(Gp(f),i);o.push({id:d,data:{droppableContainer:u,value:g}})}}return o.sort(Bp)},I0=l=>{let{collisionRect:e,droppableRects:a,droppableContainers:r}=l;const i=qp(e),o=[];for(const u of r){const{id:d}=u,f=a.get(d);if(f){const g=qp(f),m=i.reduce((v,E,S)=>v+Up(g[S],E),0),b=Number((m/4).toFixed(4));o.push({id:d,data:{droppableContainer:u,value:b}})}}return o.sort(Bp)};function j0(l,e){const a=Math.max(e.top,l.top),r=Math.max(e.left,l.left),i=Math.min(e.left+e.width,l.left+l.width),o=Math.min(e.top+e.height,l.top+l.height),u=i-r,d=o-a;if(r<i&&a<o){const f=e.width*e.height,g=l.width*l.height,m=u*d,b=m/(f+g-m);return Number(b.toFixed(4))}return 0}const U0=l=>{let{collisionRect:e,droppableRects:a,droppableContainers:r}=l;const i=[];for(const o of r){const{id:u}=o,d=a.get(u);if(d){const f=j0(d,e);f>0&&i.push({id:u,data:{droppableContainer:o,value:f}})}}return i.sort(H0)};function B0(l,e,a){return{...l,scaleX:e&&a?e.width/a.width:1,scaleY:e&&a?e.height/a.height:1}}function Vp(l,e){return l&&e?{x:l.left-e.left,y:l.top-e.top}:ya}function q0(l){return function(a){for(var r=arguments.length,i=new Array(r>1?r-1:0),o=1;o<r;o++)i[o-1]=arguments[o];return i.reduce((u,d)=>({...u,top:u.top+l*d.y,bottom:u.bottom+l*d.y,left:u.left+l*d.x,right:u.right+l*d.x}),{...a})}}const P0=q0(1);function G0(l){if(l.startsWith("matrix3d(")){const e=l.slice(9,-1).split(/, /);return{x:+e[12],y:+e[13],scaleX:+e[0],scaleY:+e[5]}}else if(l.startsWith("matrix(")){const e=l.slice(7,-1).split(/, /);return{x:+e[4],y:+e[5],scaleX:+e[0],scaleY:+e[3]}}return null}function V0(l,e,a){const r=G0(e);if(!r)return l;const{scaleX:i,scaleY:o,x:u,y:d}=r,f=l.left-u-(1-i)*parseFloat(a),g=l.top-d-(1-o)*parseFloat(a.slice(a.indexOf(" ")+1)),m=i?l.width/i:l.width,b=o?l.height/o:l.height;return{width:m,height:b,top:g,right:f+m,bottom:g+b,left:f}}const F0={ignoreTransform:!1};function Qi(l,e){e===void 0&&(e=F0);let a=l.getBoundingClientRect();if(e.ignoreTransform){const{transform:g,transformOrigin:m}=Tn(l).getComputedStyle(l);g&&(a=V0(a,g,m))}const{top:r,left:i,width:o,height:u,bottom:d,right:f}=a;return{top:r,left:i,width:o,height:u,bottom:d,right:f}}function Fp(l){return Qi(l,{ignoreTransform:!0})}function K0(l){const e=l.innerWidth,a=l.innerHeight;return{top:0,left:0,right:e,bottom:a,width:e,height:a}}function W0(l,e){return e===void 0&&(e=Tn(l).getComputedStyle(l)),e.position==="fixed"}function Y0(l,e){e===void 0&&(e=Tn(l).getComputedStyle(l));const a=/(auto|scroll|overlay)/;return["overflow","overflowX Line truncated
<div style="padding: 1rem; border: 2px dashed #ccc; background: #f9f9f9; text-align: center;"> <div style="padding: 1rem; border: 2px dashed #ccc; background: #f9f9f9; text-align: center;">
<p style="margin: 0; color: #666;">Component not found: <strong>${e}</strong></p> <p style="margin: 0; color: #666;">Component not found: <strong>${e}</strong></p>
</div> </div>
@@ -139,14 +139,14 @@ Error generating stack: `+c.message+`
" "
>페이지 새로고침</button> >페이지 새로고침</button>
</div> </div>
`,Un.error("Error state rendered:",i,r)}getCurrentLayout(){return this.currentLayout}clear(){this.currentLayout=null,this.layoutCache.clear(),Un.log("Layout data and cache cleared")}}const vE=dt("TranslationContext"),Bd=N.createContext(null),uc=({children:l,translationEngine:e,translationContext:a})=>{const r=N.useMemo(()=>(o,u)=>{if(u){const d="|"+Object.entries(u).map(([f,g])=>`${f}=${g}`).join("|");return e.translate(o,a,d)}return e.translate(o,a)},[e,a]),i=N.useMemo(()=>({translationEngine:e,translationContext:a,t:r}),[e,a,r]);return ct.jsx(Bd.Provider,{value:i,children:l})},vm=()=>{const l=N.useContext(Bd);return l||(vE.warn("TranslationProvider 외부에서 호출되었습니다. 키를 그대로 반환합니다."),{t:e=>e,translationEngine:null,translationContext:null})},kr=dt("SlotContext"),SE={registerToSlot:()=>{kr.warn("SlotContext not available: registerToSlot called outside SlotProvider")},unregisterFromSlot:()=>{kr.warn("SlotContext not available: unregisterFromSlot called outside SlotProvider")},getSlotComponents:()=>[],subscribeToSlot:()=>()=>{},clearAllSlots:()=>{},isEnabled:!1},wE=N.createContext(SE),qd=({children:l})=>{const e=N.useRef(new Map),a=N.useRef(new Map),r=N.useCallback(m=>{const b=a.current.get(m);b&&b.forEach(v=>{try{v()}catch(E){kr.error(`Slot subscriber error (slotId: ${m}):`,E)}})},[]),i=N.useCallback((m,b,v)=>{if(!m||!b){kr.warn("registerToSlot: slotId and componentId are required");return}e.current.has(m)||e.current.set(m,new Map);const E=e.current.get(m),S=E.get(b);S&&S.registrationKey===v.registrationKey||(E.set(b,v),kr.log(`Component registered to slot: ${b} -> ${m} (order: ${v.order})`),r(m))},[r]),o=N.useCallback((m,b)=>{const v=e.current.get(m);v&&v.has(b)&&(v.delete(b),kr.log(`Component unregistered from slot: ${b} <- ${m}`),v.size===0&&e.current.delete(m),r(m))},[r]),u=N.useCallback(m=>{const b=e.current.get(m);return b?Array.from(b.values()).sort((v,E)=>v.order-E.order):[]},[]),d=N.useCallback((m,b)=>{a.current.has(m)||a.current.set(m,new Set);const v=a.current.get(m);return v.add(b),()=>{v.delete(b),v.size===0&&a.current.delete(m)}},[]),f=N.useCallback(()=>{e.current.forEach((m,b)=>{r(b)}),e.current.clear(),a.current.clear(),kr.log("All slots cleared")},[r]),g=N.useMemo(()=>({registerToSlot:i,unregisterFromSlot:o,getSlotComponents:u,subscribeToSlot:d,clearAllSlots:f,isEnabled:!0}),[i,o,u,d,f]);return N.useLayoutEffect(()=>{typeof window<"u"&&(window.__slotContextValue=g,kr.log("SlotContext exposed to window.__slotContextValue"))},[g]),ct.jsx(wE.Provider,{value:g,children:l})};class Pd{constructor(){this.notificationCreatedEvent=".Illuminate\\Notifications\\Events\\BroadcastNotificationCreated"}listenForWhisper(e,a){return this.listen(".client-"+e,a)}notification(e){return this.listen(this.notificationCreatedEvent,e)}stopListeningForNotification(e){return this.stopListening(this.notificationCreatedEvent,e)}stopListeningForWhisper(e,a){return this.stopListening(".client-"+e,a)}}class Sm{constructor(e){this.namespace=e}format(e){return[".","\\"].includes(e.charAt(0))?e.substring(1):(this.namespace&&(e=this.namespace+"."+e),e.replace(/\./g,"\\"))}setNamespace(e){this.namespace=e}}function CE(l){try{new l}catch(e){if(e instanceof Error&&e.message.includes("is not a constructor"))return!1}return!0}class Gd extends Pd{constructor(e,a,r){super(),this.name=a,this.pusher=e,this.options=r,this.eventFormatter=new Sm(this.options.namespace),this.subscribe()}subscribe(){this.subscription=this.pusher.subscribe(this.name)}unsubscribe(){this.pusher.unsubscribe(this.name)}listen(e,a){return this.on(this.eventFormatter.format(e),a),this}listenToAll(e){return this.subscription.bind_global((a,r)=>{if(a.startsWith("pusher:"))return;let i=String(this.options.namespace??"").replace(/\./g,"\\"),o=a.startsWith(i)?a.substring(i.length+1):"."+a;e(o,r)}),this}stopListening(e,a){return a?this.subscription.unbind(this.eventFormatter.format(e),a):this.subscription.unbind(this.eventFormatter.format(e)),this}stopListeningToAll(e){return e?this.subscription.unbind_global(e):this.subscription.unbind_global(),this}subscribed(e){return this.on("pusher:subscription_succeeded",()=>{e()}),this}error(e){return this.on("pusher:subscription_error",a=>{e(a)}),this}on(e,a){return this.subscription.bind(e,a),this}}class wm extends Gd{whisper(e,a){return this.pusher.channels.channels[this.name].trigger(`client-${e}`,a),this}}class EE extends Gd{whisper(e,a){return this.pusher.channels.channels[this.name].trigger(`client-${e}`,a),this}}class _E extends wm{here(e){return this.on("pusher:subscription_succeeded",a=>{e(Object.keys(a.members).map(r=>a.members[r]))}),this}joining(e){return this.on("pusher:member_added",a=>{e(a.info)}),this}whisper(e,a){return this.pusher.channels.channels[this.name].trigger(`client-${e}`,a),this}leaving(e){return this.on("pusher:member_removed",a=>{e(a.info)}),this}}class Cm extends Pd{constructor(e,a,r){super(),this.events={},this.listeners={},this.name=a,this.socket=e,this.op Line truncated `,Un.error("Error state rendered:",i,r)}getCurrentLayout(){return this.currentLayout}clear(){this.currentLayout=null,this.layoutCache.clear(),Un.log("Layout data and cache cleared")}}const SE=dt("TranslationContext"),Bd=N.createContext(null),uc=({children:l,translationEngine:e,translationContext:a})=>{const r=N.useMemo(()=>(o,u)=>{if(u){const d="|"+Object.entries(u).map(([f,g])=>`${f}=${g}`).join("|");return e.translate(o,a,d)}return e.translate(o,a)},[e,a]),i=N.useMemo(()=>({translationEngine:e,translationContext:a,t:r}),[e,a,r]);return ct.jsx(Bd.Provider,{value:i,children:l})},vm=()=>{const l=N.useContext(Bd);return l||(SE.warn("TranslationProvider 외부에서 호출되었습니다. 키를 그대로 반환합니다."),{t:e=>e,translationEngine:null,translationContext:null})},kr=dt("SlotContext"),wE={registerToSlot:()=>{kr.warn("SlotContext not available: registerToSlot called outside SlotProvider")},unregisterFromSlot:()=>{kr.warn("SlotContext not available: unregisterFromSlot called outside SlotProvider")},getSlotComponents:()=>[],subscribeToSlot:()=>()=>{},clearAllSlots:()=>{},isEnabled:!1},CE=N.createContext(wE),qd=({children:l})=>{const e=N.useRef(new Map),a=N.useRef(new Map),r=N.useCallback(m=>{const b=a.current.get(m);b&&b.forEach(v=>{try{v()}catch(E){kr.error(`Slot subscriber error (slotId: ${m}):`,E)}})},[]),i=N.useCallback((m,b,v)=>{if(!m||!b){kr.warn("registerToSlot: slotId and componentId are required");return}e.current.has(m)||e.current.set(m,new Map);const E=e.current.get(m),S=E.get(b);S&&S.registrationKey===v.registrationKey||(E.set(b,v),kr.log(`Component registered to slot: ${b} -> ${m} (order: ${v.order})`),r(m))},[r]),o=N.useCallback((m,b)=>{const v=e.current.get(m);v&&v.has(b)&&(v.delete(b),kr.log(`Component unregistered from slot: ${b} <- ${m}`),v.size===0&&e.current.delete(m),r(m))},[r]),u=N.useCallback(m=>{const b=e.current.get(m);return b?Array.from(b.values()).sort((v,E)=>v.order-E.order):[]},[]),d=N.useCallback((m,b)=>{a.current.has(m)||a.current.set(m,new Set);const v=a.current.get(m);return v.add(b),()=>{v.delete(b),v.size===0&&a.current.delete(m)}},[]),f=N.useCallback(()=>{e.current.forEach((m,b)=>{r(b)}),e.current.clear(),a.current.clear(),kr.log("All slots cleared")},[r]),g=N.useMemo(()=>({registerToSlot:i,unregisterFromSlot:o,getSlotComponents:u,subscribeToSlot:d,clearAllSlots:f,isEnabled:!0}),[i,o,u,d,f]);return N.useLayoutEffect(()=>{typeof window<"u"&&(window.__slotContextValue=g,kr.log("SlotContext exposed to window.__slotContextValue"))},[g]),ct.jsx(CE.Provider,{value:g,children:l})};class Pd{constructor(){this.notificationCreatedEvent=".Illuminate\\Notifications\\Events\\BroadcastNotificationCreated"}listenForWhisper(e,a){return this.listen(".client-"+e,a)}notification(e){return this.listen(this.notificationCreatedEvent,e)}stopListeningForNotification(e){return this.stopListening(this.notificationCreatedEvent,e)}stopListeningForWhisper(e,a){return this.stopListening(".client-"+e,a)}}class Sm{constructor(e){this.namespace=e}format(e){return[".","\\"].includes(e.charAt(0))?e.substring(1):(this.namespace&&(e=this.namespace+"."+e),e.replace(/\./g,"\\"))}setNamespace(e){this.namespace=e}}function EE(l){try{new l}catch(e){if(e instanceof Error&&e.message.includes("is not a constructor"))return!1}return!0}class Gd extends Pd{constructor(e,a,r){super(),this.name=a,this.pusher=e,this.options=r,this.eventFormatter=new Sm(this.options.namespace),this.subscribe()}subscribe(){this.subscription=this.pusher.subscribe(this.name)}unsubscribe(){this.pusher.unsubscribe(this.name)}listen(e,a){return this.on(this.eventFormatter.format(e),a),this}listenToAll(e){return this.subscription.bind_global((a,r)=>{if(a.startsWith("pusher:"))return;let i=String(this.options.namespace??"").replace(/\./g,"\\"),o=a.startsWith(i)?a.substring(i.length+1):"."+a;e(o,r)}),this}stopListening(e,a){return a?this.subscription.unbind(this.eventFormatter.format(e),a):this.subscription.unbind(this.eventFormatter.format(e)),this}stopListeningToAll(e){return e?this.subscription.unbind_global(e):this.subscription.unbind_global(),this}subscribed(e){return this.on("pusher:subscription_succeeded",()=>{e()}),this}error(e){return this.on("pusher:subscription_error",a=>{e(a)}),this}on(e,a){return this.subscription.bind(e,a),this}}class wm extends Gd{whisper(e,a){return this.pusher.channels.channels[this.name].trigger(`client-${e}`,a),this}}class _E extends Gd{whisper(e,a){return this.pusher.channels.channels[this.name].trigger(`client-${e}`,a),this}}class AE extends wm{here(e){return this.on("pusher:subscription_succeeded",a=>{e(Object.keys(a.members).map(r=>a.members[r]))}),this}joining(e){return this.on("pusher:member_added",a=>{e(a.info)}),this}whisper(e,a){return this.pusher.channels.channels[this.name].trigger(`client-${e}`,a),this}leaving(e){return this.on("pusher:member_removed",a=>{e(a.info)}),this}}class Cm extends Pd{constructor(e,a,r){super(),this.events={},this.listeners={},this.name=a,this.socket=e,this.op Line truncated
* Pusher JavaScript Library v8.4.0 * Pusher JavaScript Library v8.4.0
* https://pusher.com/ * https://pusher.com/
* *
* Copyright 2020, Pusher * Copyright 2020, Pusher
* Released under the MIT licence. * Released under the MIT licence.
*/var Tm;function DE(){return Tm||(Tm=1,(function(l,e){(function(r,i){l.exports=i()})(window,function(){return(function(a){var r={};function i(o){if(r[o])return r[o].exports;var u=r[o]={i:o,l:!1,exports:{}};return a[o].call(u.exports,u,u.exports,i),u.l=!0,u.exports}return i.m=a,i.c=r,i.d=function(o,u,d){i.o(o,u)||Object.defineProperty(o,u,{enumerable:!0,get:d})},i.r=function(o){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})},i.t=function(o,u){if(u&1&&(o=i(o)),u&8||u&4&&typeof o=="object"&&o&&o.__esModule)return o;var d=Object.create(null);if(i.r(d),Object.defineProperty(d,"default",{enumerable:!0,value:o}),u&2&&typeof o!="string")for(var f in o)i.d(d,f,function(g){return o[g]}.bind(null,f));return d},i.n=function(o){var u=o&&o.__esModule?function(){return o.default}:function(){return o};return i.d(u,"a",u),u},i.o=function(o,u){return Object.prototype.hasOwnProperty.call(o,u)},i.p="",i(i.s=2)})([(function(a,r,i){var o=this&&this.__extends||(function(){var A=function(T,D){return A=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(M,O){M.__proto__=O}||function(M,O){for(var L in O)O.hasOwnProperty(L)&&(M[L]=O[L])},A(T,D)};return function(T,D){A(T,D);function M(){this.constructor=T}T.prototype=D===null?Object.create(D):(M.prototype=D.prototype,new M)}})();Object.defineProperty(r,"__esModule",{value:!0});var u=256,d=(function(){function A(T){T===void 0&&(T="="),this._paddingCharacter=T}return A.prototype.encodedLength=function(T){return this._paddingCharacter?(T+2)/3*4|0:(T*8+5)/6|0},A.prototype.encode=function(T){for(var D="",M=0;M<T.length-2;M+=3){var O=T[M]<<16|T[M+1]<<8|T[M+2];D+=this._encodeByte(O>>>18&63),D+=this._encodeByte(O>>>12&63),D+=this._encodeByte(O>>>6&63),D+=this._encodeByte(O>>>0&63)}var L=T.length-M;if(L>0){var O=T[M]<<16|(L===2?T[M+1]<<8:0);D+=this._encodeByte(O>>>18&63),D+=this._encodeByte(O>>>12&63),L===2?D+=this._encodeByte(O>>>6&63):D+=this._paddingCharacter||"",D+=this._paddingCharacter||""}return D},A.prototype.maxDecodedLength=function(T){return this._paddingCharacter?T/4*3|0:(T*6+7)/8|0},A.prototype.decodedLength=function(T){return this.maxDecodedLength(T.length-this._getPaddingLength(T))},A.prototype.decode=function(T){if(T.length===0)return new Uint8Array(0);for(var D=this._getPaddingLength(T),M=T.length-D,O=new Uint8Array(this.maxDecodedLength(M)),L=0,P=0,U=0,B=0,Y=0,ge=0,Ae=0;P<M-4;P+=4)B=this._decodeChar(T.charCodeAt(P+0)),Y=this._decodeChar(T.charCodeAt(P+1)),ge=this._decodeChar(T.charCodeAt(P+2)),Ae=this._decodeChar(T.charCodeAt(P+3)),O[L++]=B<<2|Y>>>4,O[L++]=Y<<4|ge>>>2,O[L++]=ge<<6|Ae,U|=B&u,U|=Y&u,U|=ge&u,U|=Ae&u;if(P<M-1&&(B=this._decodeChar(T.charCodeAt(P)),Y=this._decodeChar(T.charCodeAt(P+1)),O[L++]=B<<2|Y>>>4,U|=B&u,U|=Y&u),P<M-2&&(ge=this._decodeChar(T.charCodeAt(P+2)),O[L++]=Y<<4|ge>>>2,U|=ge&u),P<M-3&&(Ae=this._decodeChar(T.charCodeAt(P+3)),O[L++]=ge<<6|Ae,U|=Ae&u),U!==0)throw new Error("Base64Coder: incorrect characters for decoding");return O},A.prototype._encodeByte=function(T){var D=T;return D+=65,D+=25-T>>>8&6,D+=51-T>>>8&-75,D+=61-T>>>8&-15,D+=62-T>>>8&3,String.fromCharCode(D)},A.prototype._decodeChar=function(T){var D=u;return D+=(42-T&T-44)>>>8&-u+T-43+62,D+=(46-T&T-48)>>>8&-u+T-47+63,D+=(47-T&T-58)>>>8&-u+T-48+52,D+=(64-T&T-91)>>>8&-u+T-65+0,D+=(96-T&T-123)>>>8&-u+T-97+26,D},A.prototype._getPaddingLength=function(T){var D=0;if(this._paddingCharacter){for(var M=T.length-1;M>=0&&T[M]===this._paddingCharacter;M--)D++;if(T.length<4||D>2)throw new Error("Base64Coder: incorrect padding")}return D},A})();r.Coder=d;var f=new d;function g(A){return f.encode(A)}r.encode=g;function m(A){return f.decode(A)}r.decode=m;var b=(function(A){o(T,A);function T(){return A!==null&&A.apply(this,arguments)||this}return T.prototype._encodeByte=function(D){var M=D;return M+=65,M+=25-D>>>8&6,M+=51-D>>>8&-75,M+=61-D>>>8&-13,M+=62-D>>>8&49,String.fromCharCode(M)},T.prototype._decodeChar=function(D){var M=u;return M+=(44-D&D-46)>>>8&-u+D-45+62,M+=(94-D&D-96)>>>8&-u+D-95+63,M+=(47-D&D-58)>>>8&-u+D-48+52,M+=(64-D&D-91)>>>8&-u+D-65+0,M+=(96-D&D-123)>>>8&-u+D-97+26,M},T})(d);r.URLSafeCoder=b;var v=new b;function E(A){return v.encode(A)}r.encodeURLSafe=E;function S(A){return v.decode(A)}r.decodeURLSafe=S,r.encodedLength=function(A){return f.encodedLength(A)},r.maxDecodedLength=function(A){return f.maxDecodedLength(A)},r.decodedLength=function(A){return f.decodedLength(A)}}),(function(a,r,i){Object.defineProperty(r,"__esModule",{value:!0});var o="utf8: invalid string",u="utf8: invalid source encoding";function d(m){for(var b=new Uint8Array(f(m)),v=0,E=0;E<m.length;E++){var S=m.charCodeAt(E);S<128?b[v++]=S:S<2048?(b[v++]=192|S>>6,b[v++]=128|S&63):S<55296?(b[v++]=224|S>>12,b[v++]=128|S>>6&63,b[v++]=128|S&63):(E++,S=(S&1023)<<10,S|=m.charCodeAt(E)&1023,S+=65536,b[v++]=240|S>>18,b[v++]=128|S>>12&63,b[v++]=128|S>>6&63,b[v++]=128|S&63)}return b}r.encode=d;function f(m){for(var b=0,v=0Line truncated */var Tm;function OE(){return Tm||(Tm=1,(function(l,e){(function(r,i){l.exports=i()})(window,function(){return(function(a){var r={};function i(o){if(r[o])return r[o].exports;var u=r[o]={i:o,l:!1,exports:{}};return a[o].call(u.exports,u,u.exports,i),u.l=!0,u.exports}return i.m=a,i.c=r,i.d=function(o,u,d){i.o(o,u)||Object.defineProperty(o,u,{enumerable:!0,get:d})},i.r=function(o){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})},i.t=function(o,u){if(u&1&&(o=i(o)),u&8||u&4&&typeof o=="object"&&o&&o.__esModule)return o;var d=Object.create(null);if(i.r(d),Object.defineProperty(d,"default",{enumerable:!0,value:o}),u&2&&typeof o!="string")for(var f in o)i.d(d,f,function(g){return o[g]}.bind(null,f));return d},i.n=function(o){var u=o&&o.__esModule?function(){return o.default}:function(){return o};return i.d(u,"a",u),u},i.o=function(o,u){return Object.prototype.hasOwnProperty.call(o,u)},i.p="",i(i.s=2)})([(function(a,r,i){var o=this&&this.__extends||(function(){var A=function(T,D){return A=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(M,O){M.__proto__=O}||function(M,O){for(var L in O)O.hasOwnProperty(L)&&(M[L]=O[L])},A(T,D)};return function(T,D){A(T,D);function M(){this.constructor=T}T.prototype=D===null?Object.create(D):(M.prototype=D.prototype,new M)}})();Object.defineProperty(r,"__esModule",{value:!0});var u=256,d=(function(){function A(T){T===void 0&&(T="="),this._paddingCharacter=T}return A.prototype.encodedLength=function(T){return this._paddingCharacter?(T+2)/3*4|0:(T*8+5)/6|0},A.prototype.encode=function(T){for(var D="",M=0;M<T.length-2;M+=3){var O=T[M]<<16|T[M+1]<<8|T[M+2];D+=this._encodeByte(O>>>18&63),D+=this._encodeByte(O>>>12&63),D+=this._encodeByte(O>>>6&63),D+=this._encodeByte(O>>>0&63)}var L=T.length-M;if(L>0){var O=T[M]<<16|(L===2?T[M+1]<<8:0);D+=this._encodeByte(O>>>18&63),D+=this._encodeByte(O>>>12&63),L===2?D+=this._encodeByte(O>>>6&63):D+=this._paddingCharacter||"",D+=this._paddingCharacter||""}return D},A.prototype.maxDecodedLength=function(T){return this._paddingCharacter?T/4*3|0:(T*6+7)/8|0},A.prototype.decodedLength=function(T){return this.maxDecodedLength(T.length-this._getPaddingLength(T))},A.prototype.decode=function(T){if(T.length===0)return new Uint8Array(0);for(var D=this._getPaddingLength(T),M=T.length-D,O=new Uint8Array(this.maxDecodedLength(M)),L=0,P=0,U=0,B=0,Y=0,ge=0,Ae=0;P<M-4;P+=4)B=this._decodeChar(T.charCodeAt(P+0)),Y=this._decodeChar(T.charCodeAt(P+1)),ge=this._decodeChar(T.charCodeAt(P+2)),Ae=this._decodeChar(T.charCodeAt(P+3)),O[L++]=B<<2|Y>>>4,O[L++]=Y<<4|ge>>>2,O[L++]=ge<<6|Ae,U|=B&u,U|=Y&u,U|=ge&u,U|=Ae&u;if(P<M-1&&(B=this._decodeChar(T.charCodeAt(P)),Y=this._decodeChar(T.charCodeAt(P+1)),O[L++]=B<<2|Y>>>4,U|=B&u,U|=Y&u),P<M-2&&(ge=this._decodeChar(T.charCodeAt(P+2)),O[L++]=Y<<4|ge>>>2,U|=ge&u),P<M-3&&(Ae=this._decodeChar(T.charCodeAt(P+3)),O[L++]=ge<<6|Ae,U|=Ae&u),U!==0)throw new Error("Base64Coder: incorrect characters for decoding");return O},A.prototype._encodeByte=function(T){var D=T;return D+=65,D+=25-T>>>8&6,D+=51-T>>>8&-75,D+=61-T>>>8&-15,D+=62-T>>>8&3,String.fromCharCode(D)},A.prototype._decodeChar=function(T){var D=u;return D+=(42-T&T-44)>>>8&-u+T-43+62,D+=(46-T&T-48)>>>8&-u+T-47+63,D+=(47-T&T-58)>>>8&-u+T-48+52,D+=(64-T&T-91)>>>8&-u+T-65+0,D+=(96-T&T-123)>>>8&-u+T-97+26,D},A.prototype._getPaddingLength=function(T){var D=0;if(this._paddingCharacter){for(var M=T.length-1;M>=0&&T[M]===this._paddingCharacter;M--)D++;if(T.length<4||D>2)throw new Error("Base64Coder: incorrect padding")}return D},A})();r.Coder=d;var f=new d;function g(A){return f.encode(A)}r.encode=g;function m(A){return f.decode(A)}r.decode=m;var b=(function(A){o(T,A);function T(){return A!==null&&A.apply(this,arguments)||this}return T.prototype._encodeByte=function(D){var M=D;return M+=65,M+=25-D>>>8&6,M+=51-D>>>8&-75,M+=61-D>>>8&-13,M+=62-D>>>8&49,String.fromCharCode(M)},T.prototype._decodeChar=function(D){var M=u;return M+=(44-D&D-46)>>>8&-u+D-45+62,M+=(94-D&D-96)>>>8&-u+D-95+63,M+=(47-D&D-58)>>>8&-u+D-48+52,M+=(64-D&D-91)>>>8&-u+D-65+0,M+=(96-D&D-123)>>>8&-u+D-97+26,M},T})(d);r.URLSafeCoder=b;var v=new b;function E(A){return v.encode(A)}r.encodeURLSafe=E;function S(A){return v.decode(A)}r.decodeURLSafe=S,r.encodedLength=function(A){return f.encodedLength(A)},r.maxDecodedLength=function(A){return f.maxDecodedLength(A)},r.decodedLength=function(A){return f.decodedLength(A)}}),(function(a,r,i){Object.defineProperty(r,"__esModule",{value:!0});var o="utf8: invalid string",u="utf8: invalid source encoding";function d(m){for(var b=new Uint8Array(f(m)),v=0,E=0;E<m.length;E++){var S=m.charCodeAt(E);S<128?b[v++]=S:S<2048?(b[v++]=192|S>>6,b[v++]=128|S&63):S<55296?(b[v++]=224|S>>12,b[v++]=128|S>>6&63,b[v++]=128|S&63):(E++,S=(S&1023)<<10,S|=m.charCodeAt(E)&1023,S+=65536,b[v++]=240|S>>18,b[v++]=128|S>>12&63,b[v++]=128|S>>6&63,b[v++]=128|S&63)}return b}r.encode=d;function f(m){for(var b=0,v=0Line truncated
`);return R!==-1?(this.position+=R+1,C.slice(0,R)):null}isBufferTooLong(y){return this.position===y.length&&y.length>$r}}var os;(function(_){_[_.CONNECTING=0]="CONNECTING",_[_.OPEN=1]="OPEN",_[_.CLOSED=3]="CLOSED"})(os||(os={}));var Ba=os,Oo=1;class nf{constructor(y,C){this.hooks=y,this.session=cs(1e3)+"/"+Nr(8),this.location=af(C),this.readyState=Ba.CONNECTING,this.openStream()}send(y){return this.sendRaw(JSON.stringify([y]))}ping(){this.hooks.sendHeartbeat(this)}close(y,C){this.onClose(y,C,!0)}sendRaw(y){if(this.readyState===Ba.OPEN)try{return Ge.createSocketRequest("POST",aa(ls(this.location,this.session))).start(y),!0}catch{return!1}else return!1}reconnect(){this.closeStream(),this.openStream()}onClose(y,C,R){this.closeStream(),this.readyState=Ba.CLOSED,this.onclose&&this.onclose({code:y,reason:C,wasClean:R})}onChunk(y){if(y.status===200){this.readyState===Ba.OPEN&&this.onActivity();var C,R=y.data.slice(0,1);switch(R){case"o":C=JSON.parse(y.data.slice(1)||"{}"),this.onOpen(C);break;case"a":C=JSON.parse(y.data.slice(1)||"[]");for(var H=0;H<C.length;H++)this.onEvent(C[H]);break;case"m":C=JSON.parse(y.data.slice(1)||"null"),this.onEvent(C);break;case"h":this.hooks.onHeartbeat(this);break;case"c":C=JSON.parse(y.data.slice(1)||"[]"),this.onClose(C[0],C[1],!0);break}}}onOpen(y){this.readyState===Ba.CONNECTING?(y&&y.hostname&&(this.location.base=Lo(this.location.base,y.hostname)),this.readyState=Ba.OPEN,this.onopen&&this.onopen()):this.onClose(1006,"Server lost session",!0)}onEvent(y){this.readyState===Ba.OPEN&&this.onmessage&&this.onmessage({data:y})}onActivity(){this.onactivity&&this.onactivity()}onError(y){this.onerror&&this.onerror(y)}openStream(){this.stream=Ge.createSocketRequest("POST",aa(this.hooks.getReceiveURL(this.location,this.session))),this.stream.bind("chunk",y=>{this.onChunk(y)}),this.stream.bind("finished",y=>{this.hooks.onFinished(this,y)}),this.stream.bind("buffer_too_long",()=>{this.reconnect()});try{this.stream.start()}catch(y){te.defer(()=>{this.onError(y),this.onClose(1006,"Could not start streaming",!1)})}}closeStream(){this.stream&&(this.stream.unbind_all(),this.stream.close(),this.stream=null)}}function af(_){var y=/([^\?]*)\/*(\??.*)/.exec(_);return{base:y[1],queryString:y[2]}}function ls(_,y){return _.base+"/"+y+"/xhr_send"}function aa(_){var y=_.indexOf("?")===-1?"?":"&";return _+y+"t="+ +new Date+"&n="+Oo++}function Lo(_,y){var C=/(https?:\/\/)([^\/:]+)((\/|:)?.*)/.exec(_);return C[1]+y+C[3]}function cs(_){return Ge.randomInt(_)}function Nr(_){for(var y=[],C=0;C<_;C++)y.push(cs(32).toString(32));return y.join("")}var Hr=nf,_c={getReceiveURL:function(_,y){return _.base+"/"+y+"/xhr_streaming"+_.queryString},onHeartbeat:function(_){_.sendRaw("[]")},sendHeartbeat:function(_){_.sendRaw("[]")},onFinished:function(_,y){_.onClose(1006,"Connection interrupted ("+y+")",!1)}},Mo=_c,Ac={getReceiveURL:function(_,y){return _.base+"/"+y+"/xhr"+_.queryString},onHeartbeat:function(){},sendHeartbeat:function(_){_.sendRaw("[]")},onFinished:function(_,y){y===200?_.reconnect():_.onClose(1006,"Connection interrupted ("+y+")",!1)}},vi=Ac,Ta={getRequest:function(_){var y=Ge.getXHRAPI(),C=new y;return C.onreadystatechange=C.onprogress=function(){switch(C.readyState){case 3:C.responseText&&C.responseText.length>0&&_.onChunk(C.status,C.responseText);break;case 4:C.responseText&&C.responseText.length>0&&_.onChunk(C.status,C.responseText),_.emit("finished",C.status),_.close();break}},C},abortRequest:function(_){_.onreadystatechange=null,_.abort()}},$o=Ta,Si={createStreamingSocket(_){return this.createSocket(Mo,_)},createPollingSocket(_){return this.createSocket(vi,_)},createSocket(_,y){return new Hr(_,y)},createXHR(_,y){return this.createRequest($o,_,y)},createRequest(_,y,C){return new tf(_,y,C)}},ka=Si;ka.createXDR=function(_,y){return this.createRequest(Ec,_,y)};var No=ka,us={nextAuthCallbackID:1,auth_callbacks:{},ScriptReceivers:u,DependenciesReceivers:m,getDefaultStrategy:Do,Transports:Ft,transportConnectionInitializer:Mr,HTTPFactory:No,TimelineTransport:tr,getXHRAPI(){return window.XMLHttpRequest},getWebSocketAPI(){return window.WebSocket||window.MozWebSocket},setup(_){window.Pusher=_;var y=()=>{this.onDocumentBody(_.ready)};window.JSON?y():b.load("json2",{},y)},getDocument(){return document},getProtocol(){return this.getDocument().location.protocol},getAuthorizers(){return{ajax:Ae,jsonp:Gn}},onDocumentBody(_){document.body?_():setTimeout(()=>{this.onDocumentBody(_)},0)},createJSONPRequest(_,y){return new mn(_,y)},createScriptRequest(_){return new en(_)},getLocalStorage(){try{return window.localStorage}catch{return}},createXHR(){return this.getXHRAPI()?this.createXMLHttpRequest():this.createMicrosoftXHR()},createXMLHttpRequest(){var _=this.getXHRAPI();return new _},createMicrosoftXHR(){return new ActiveXObject("Microsoft.XMLHTTP")},getNetwork(){return Dn},createWebSocket(_){var y=this.getWebSocketAPI();return new y(_)},createSocketRequest(_,y){if(this.isXHRSupported())return this.HTTPFactory.createXHR(_ Line truncated `);return R!==-1?(this.position+=R+1,C.slice(0,R)):null}isBufferTooLong(y){return this.position===y.length&&y.length>$r}}var os;(function(_){_[_.CONNECTING=0]="CONNECTING",_[_.OPEN=1]="OPEN",_[_.CLOSED=3]="CLOSED"})(os||(os={}));var Ba=os,Oo=1;class nf{constructor(y,C){this.hooks=y,this.session=cs(1e3)+"/"+Nr(8),this.location=af(C),this.readyState=Ba.CONNECTING,this.openStream()}send(y){return this.sendRaw(JSON.stringify([y]))}ping(){this.hooks.sendHeartbeat(this)}close(y,C){this.onClose(y,C,!0)}sendRaw(y){if(this.readyState===Ba.OPEN)try{return Ge.createSocketRequest("POST",aa(ls(this.location,this.session))).start(y),!0}catch{return!1}else return!1}reconnect(){this.closeStream(),this.openStream()}onClose(y,C,R){this.closeStream(),this.readyState=Ba.CLOSED,this.onclose&&this.onclose({code:y,reason:C,wasClean:R})}onChunk(y){if(y.status===200){this.readyState===Ba.OPEN&&this.onActivity();var C,R=y.data.slice(0,1);switch(R){case"o":C=JSON.parse(y.data.slice(1)||"{}"),this.onOpen(C);break;case"a":C=JSON.parse(y.data.slice(1)||"[]");for(var H=0;H<C.length;H++)this.onEvent(C[H]);break;case"m":C=JSON.parse(y.data.slice(1)||"null"),this.onEvent(C);break;case"h":this.hooks.onHeartbeat(this);break;case"c":C=JSON.parse(y.data.slice(1)||"[]"),this.onClose(C[0],C[1],!0);break}}}onOpen(y){this.readyState===Ba.CONNECTING?(y&&y.hostname&&(this.location.base=Lo(this.location.base,y.hostname)),this.readyState=Ba.OPEN,this.onopen&&this.onopen()):this.onClose(1006,"Server lost session",!0)}onEvent(y){this.readyState===Ba.OPEN&&this.onmessage&&this.onmessage({data:y})}onActivity(){this.onactivity&&this.onactivity()}onError(y){this.onerror&&this.onerror(y)}openStream(){this.stream=Ge.createSocketRequest("POST",aa(this.hooks.getReceiveURL(this.location,this.session))),this.stream.bind("chunk",y=>{this.onChunk(y)}),this.stream.bind("finished",y=>{this.hooks.onFinished(this,y)}),this.stream.bind("buffer_too_long",()=>{this.reconnect()});try{this.stream.start()}catch(y){te.defer(()=>{this.onError(y),this.onClose(1006,"Could not start streaming",!1)})}}closeStream(){this.stream&&(this.stream.unbind_all(),this.stream.close(),this.stream=null)}}function af(_){var y=/([^\?]*)\/*(\??.*)/.exec(_);return{base:y[1],queryString:y[2]}}function ls(_,y){return _.base+"/"+y+"/xhr_send"}function aa(_){var y=_.indexOf("?")===-1?"?":"&";return _+y+"t="+ +new Date+"&n="+Oo++}function Lo(_,y){var C=/(https?:\/\/)([^\/:]+)((\/|:)?.*)/.exec(_);return C[1]+y+C[3]}function cs(_){return Ge.randomInt(_)}function Nr(_){for(var y=[],C=0;C<_;C++)y.push(cs(32).toString(32));return y.join("")}var Hr=nf,_c={getReceiveURL:function(_,y){return _.base+"/"+y+"/xhr_streaming"+_.queryString},onHeartbeat:function(_){_.sendRaw("[]")},sendHeartbeat:function(_){_.sendRaw("[]")},onFinished:function(_,y){_.onClose(1006,"Connection interrupted ("+y+")",!1)}},Mo=_c,Ac={getReceiveURL:function(_,y){return _.base+"/"+y+"/xhr"+_.queryString},onHeartbeat:function(){},sendHeartbeat:function(_){_.sendRaw("[]")},onFinished:function(_,y){y===200?_.reconnect():_.onClose(1006,"Connection interrupted ("+y+")",!1)}},vi=Ac,Ta={getRequest:function(_){var y=Ge.getXHRAPI(),C=new y;return C.onreadystatechange=C.onprogress=function(){switch(C.readyState){case 3:C.responseText&&C.responseText.length>0&&_.onChunk(C.status,C.responseText);break;case 4:C.responseText&&C.responseText.length>0&&_.onChunk(C.status,C.responseText),_.emit("finished",C.status),_.close();break}},C},abortRequest:function(_){_.onreadystatechange=null,_.abort()}},$o=Ta,Si={createStreamingSocket(_){return this.createSocket(Mo,_)},createPollingSocket(_){return this.createSocket(vi,_)},createSocket(_,y){return new Hr(_,y)},createXHR(_,y){return this.createRequest($o,_,y)},createRequest(_,y,C){return new tf(_,y,C)}},ka=Si;ka.createXDR=function(_,y){return this.createRequest(Ec,_,y)};var No=ka,us={nextAuthCallbackID:1,auth_callbacks:{},ScriptReceivers:u,DependenciesReceivers:m,getDefaultStrategy:Do,Transports:Kt,transportConnectionInitializer:Mr,HTTPFactory:No,TimelineTransport:tr,getXHRAPI(){return window.XMLHttpRequest},getWebSocketAPI(){return window.WebSocket||window.MozWebSocket},setup(_){window.Pusher=_;var y=()=>{this.onDocumentBody(_.ready)};window.JSON?y():b.load("json2",{},y)},getDocument(){return document},getProtocol(){return this.getDocument().location.protocol},getAuthorizers(){return{ajax:Ae,jsonp:Gn}},onDocumentBody(_){document.body?_():setTimeout(()=>{this.onDocumentBody(_)},0)},createJSONPRequest(_,y){return new yn(_,y)},createScriptRequest(_){return new tn(_)},getLocalStorage(){try{return window.localStorage}catch{return}},createXHR(){return this.getXHRAPI()?this.createXMLHttpRequest():this.createMicrosoftXHR()},createXMLHttpRequest(){var _=this.getXHRAPI();return new _},createMicrosoftXHR(){return new ActiveXObject("Microsoft.XMLHTTP")},getNetwork(){return Dn},createWebSocket(_){var y=this.getWebSocketAPI();return new y(_)},createSocketRequest(_,y){if(this.isXHRSupported())return this.HTTPFactory.createXHR(_ Line truncated
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -267,7 +267,7 @@ Error generating stack: `+c.message+`
`:""} `:""}
</div> </div>
</div> </div>
`}static renderFromError(e,a,r,i=!1,o,u,d){let f,g;if(a.userMessageKey.startsWith("$t:"))if(u&&o)try{f=u.translate(a.userMessageKey,o)}catch{f=a.userMessageKey.replace("$t:","")}else f=a.userMessageKey.replace("$t:","");else f=a.userMessageKey;if(d){const m=d;m.details?.apiMessage?g=m.details.apiMessage:m.response?.data?.message&&(g=m.response.data.message)}this.render(e,{title:r,message:f,detailMessage:g,icon:a.icon,showStack:a.showStack,stackTrace:a.stack,showReloadButton:a.recoverable,debug:i})}static escapeHtml(e){if(!e)return"";const a=document.createElement("div");return a.textContent=e,a.innerHTML}}const Zi=dt("Router");class jE{constructor(e){$(this,"routes",[]);$(this,"templateIdentifier");$(this,"eventHandlers",new Map);$(this,"pendingNavigation",null);$(this,"isNavigating",!1);$(this,"handlePopState",()=>{this.navigateToCurrentPath()});this.templateIdentifier=e,this.initPopstateListener()}initPopstateListener(){window.addEventListener("popstate",this.handlePopState)}on(e,a){this.eventHandlers.has(e)||this.eventHandlers.set(e,[]),this.eventHandlers.get(e).push(a)}async emit(e,...a){const r=this.eventHandlers.get(e);r&&await Promise.all(r.map(i=>i(...a)))}async loadRoutes(e){try{const a=e!==void 0&&e>0?`?v=${e}`:"",r=await fetch(`/api/templates/${this.templateIdentifier}/routes.json${a}`);if(!r.ok)throw new Error(`Failed to load routes: ${r.statusText}`);const i=await r.json();if(!i.success)throw new Error("Failed to load routes from API");if(i.data&&Array.isArray(i.data.routes))this.routes=i.data.routes,Zi.log(`Loaded ${this.routes.length} routes${e?` (v=${e})`:""}`);else throw new Error("Invalid routes data format")}catch(a){throw Zi.error("Error loading routes:",a),a}}setRoutes(e){this.routes=e,Zi.log(`Set ${this.routes.length} routes`)}match(e){for(const a of this.routes){const r=this.matchPattern(a.path,e);if(r!==null)return{route:a,params:r}}return null}matchPattern(e,a){const r=[];let i=e.replace(/:([^/]+)/g,(f,g)=>(r.push(g),"([^/]+)"));i.startsWith("*/")&&(i="(?:/[^/]+)?"+i.slice(1)),i=i.replace(/\//g,"\\/");const o=new RegExp(`^${i}$`),u=a.match(o);if(!u)return null;const d={};return r.forEach((f,g)=>{d[f]=u[g+1]}),d}getRoutes(){return[...this.routes]}getAuthType(e,a){return e.auth_type?e.auth_type:a.startsWith("/admin")?"admin":"user"}async navigateToCurrentPath(){const e=window.location.pathname,a=window.location.search,r=this.match(e);if(!r){Zi.warn(`No route matched for path: ${e}`),this.emit("routeNotFound",e);return}if(r.route.redirect){Zi.log(`Redirecting from ${e} to ${r.route.redirect}`),this.navigate(r.route.redirect);return}if(r.route.auth_required){const u=this.getAuthType(r.route,e),d=ga.getInstance();let f=d.isAuthenticated()&&d.getAuthType()===u;if(f||(f=await d.checkAuth(u)),!f){const g=d.getLoginRedirectUrl(u,e+a);Zi.log(`Not authenticated, redirecting to: ${g}`),window.location.href=g;return}}const i=new URLSearchParams(a),o={};for(const u of i.keys()){if(u in o)continue;const d=i.getAll(u);d.length>1?o[u]=d:d.length===1&&(u.endsWith("[]")?o[u]=d:o[u]=d[0])}await this.emit("routeChange",{path:e,layout:r.route.layout,endpoint:r.route.endpoint,params:{...r.route.params||{},...r.params},query:o,auth_required:r.route.auth_required,auth_type:r.route.auth_type,meta:r.route.meta})}navigate(e){if(this.isNavigating){this.pendingNavigation=e;return}this.executeNavigation(e)}async executeNavigation(e){this.isNavigating=!0,this.pendingNavigation=null;try{window.history.pushState({},"",e),await this.navigateToCurrentPath()}finally{if(this.isNavigating=!1,this.pendingNavigation){const a=this.pendingNavigation;this.executeNavigation(a)}}}}const UE=/^\/admin\/layout-editor\/([^/?#]+)\/?$/;function Lm(l){const e=UE.exec(l);return e?{templateIdentifier:e[1]}:null}const Nt=dt("ErrorPageHandler");class BE{constructor(e){$(this,"templateId");$(this,"layoutLoader");$(this,"locale");$(this,"debug");$(this,"renderFunction");$(this,"dataSourceManager");$(this,"globalState");$(this,"errorConfig",null);$(this,"configLoaded",!1);this.templateId=e.templateId,this.layoutLoader=e.layoutLoader,this.locale=e.locale,this.debug=e.debug,this.renderFunction=e.renderFunction,this.dataSourceManager=e.dataSourceManager,this.globalState=e.globalState||{}}async loadConfig(){if(this.configLoaded)return this.errorConfig;try{const e=await fetch(`/api/templates/${this.templateId}/config.json`);if(!e.ok)return this.debug&&Nt.warn("Failed to load template config:",e.statusText),this.configLoaded=!0,null;const a=await e.json();if(!a.success||!a.data)return this.debug&&Nt.warn("Invalid template config response"),this.configLoaded=!0,null;const r=a.data;return!r.error_config||!r.error_config.layouts?(this.debug&&Nt.warn("No error_config found in template.json"),this.configLoaded=!0,null):(this.errorConfig=r.error_config,this.configLoaded=!0,this.debug&&Nt.log("Error config loaded:",this.errorConfig),this.errorConfig)}catch(e){return Nt.error("Failed to load error config:",e),this.configLoaded=!0,null}}async rend Line truncated `}static renderFromError(e,a,r,i=!1,o,u,d){let f,g;if(a.userMessageKey.startsWith("$t:"))if(u&&o)try{f=u.translate(a.userMessageKey,o)}catch{f=a.userMessageKey.replace("$t:","")}else f=a.userMessageKey.replace("$t:","");else f=a.userMessageKey;if(d){const m=d;m.details?.apiMessage?g=m.details.apiMessage:m.response?.data?.message&&(g=m.response.data.message)}this.render(e,{title:r,message:f,detailMessage:g,icon:a.icon,showStack:a.showStack,stackTrace:a.stack,showReloadButton:a.recoverable,debug:i})}static escapeHtml(e){if(!e)return"";const a=document.createElement("div");return a.textContent=e,a.innerHTML}}const Zi=dt("Router");class UE{constructor(e){$(this,"routes",[]);$(this,"templateIdentifier");$(this,"eventHandlers",new Map);$(this,"pendingNavigation",null);$(this,"isNavigating",!1);$(this,"handlePopState",()=>{this.navigateToCurrentPath()});this.templateIdentifier=e,this.initPopstateListener()}initPopstateListener(){window.addEventListener("popstate",this.handlePopState)}on(e,a){this.eventHandlers.has(e)||this.eventHandlers.set(e,[]),this.eventHandlers.get(e).push(a)}async emit(e,...a){const r=this.eventHandlers.get(e);r&&await Promise.all(r.map(i=>i(...a)))}async loadRoutes(e){try{const a=e!==void 0&&e>0?`?v=${e}`:"",r=await fetch(`/api/templates/${this.templateIdentifier}/routes.json${a}`);if(!r.ok)throw new Error(`Failed to load routes: ${r.statusText}`);const i=await r.json();if(!i.success)throw new Error("Failed to load routes from API");if(i.data&&Array.isArray(i.data.routes))this.routes=i.data.routes,Zi.log(`Loaded ${this.routes.length} routes${e?` (v=${e})`:""}`);else throw new Error("Invalid routes data format")}catch(a){throw Zi.error("Error loading routes:",a),a}}setRoutes(e){this.routes=e,Zi.log(`Set ${this.routes.length} routes`)}match(e){for(const a of this.routes){const r=this.matchPattern(a.path,e);if(r!==null)return{route:a,params:r}}return null}matchPattern(e,a){const r=[];let i=e.replace(/:([^/]+)/g,(f,g)=>(r.push(g),"([^/]+)"));i.startsWith("*/")&&(i="(?:/[^/]+)?"+i.slice(1)),i=i.replace(/\//g,"\\/");const o=new RegExp(`^${i}$`),u=a.match(o);if(!u)return null;const d={};return r.forEach((f,g)=>{d[f]=u[g+1]}),d}getRoutes(){return[...this.routes]}getAuthType(e,a){return e.auth_type?e.auth_type:a.startsWith("/admin")?"admin":"user"}async navigateToCurrentPath(){const e=window.location.pathname,a=window.location.search,r=this.match(e);if(!r){Zi.warn(`No route matched for path: ${e}`),this.emit("routeNotFound",e);return}if(r.route.redirect){Zi.log(`Redirecting from ${e} to ${r.route.redirect}`),this.navigate(r.route.redirect);return}if(r.route.auth_required){const u=this.getAuthType(r.route,e),d=ga.getInstance();let f=d.isAuthenticated()&&d.getAuthType()===u;if(f||(f=await d.checkAuth(u)),!f){const g=d.getLoginRedirectUrl(u,e+a);Zi.log(`Not authenticated, redirecting to: ${g}`),window.location.href=g;return}}const i=new URLSearchParams(a),o={};for(const u of i.keys()){if(u in o)continue;const d=i.getAll(u);d.length>1?o[u]=d:d.length===1&&(u.endsWith("[]")?o[u]=d:o[u]=d[0])}await this.emit("routeChange",{path:e,layout:r.route.layout,endpoint:r.route.endpoint,params:{...r.route.params||{},...r.params},query:o,auth_required:r.route.auth_required,auth_type:r.route.auth_type,meta:r.route.meta})}navigate(e){if(this.isNavigating){this.pendingNavigation=e;return}this.executeNavigation(e)}async executeNavigation(e){this.isNavigating=!0,this.pendingNavigation=null;try{window.history.pushState({},"",e),await this.navigateToCurrentPath()}finally{if(this.isNavigating=!1,this.pendingNavigation){const a=this.pendingNavigation;this.executeNavigation(a)}}}}const BE=/^\/admin\/layout-editor\/([^/?#]+)\/?$/;function Lm(l){const e=BE.exec(l);return e?{templateIdentifier:e[1]}:null}const Nt=dt("ErrorPageHandler");class qE{constructor(e){$(this,"templateId");$(this,"layoutLoader");$(this,"locale");$(this,"debug");$(this,"renderFunction");$(this,"dataSourceManager");$(this,"globalState");$(this,"errorConfig",null);$(this,"configLoaded",!1);this.templateId=e.templateId,this.layoutLoader=e.layoutLoader,this.locale=e.locale,this.debug=e.debug,this.renderFunction=e.renderFunction,this.dataSourceManager=e.dataSourceManager,this.globalState=e.globalState||{}}async loadConfig(){if(this.configLoaded)return this.errorConfig;try{const e=await fetch(`/api/templates/${this.templateId}/config.json`);if(!e.ok)return this.debug&&Nt.warn("Failed to load template config:",e.statusText),this.configLoaded=!0,null;const a=await e.json();if(!a.success||!a.data)return this.debug&&Nt.warn("Invalid template config response"),this.configLoaded=!0,null;const r=a.data;return!r.error_config||!r.error_config.layouts?(this.debug&&Nt.warn("No error_config found in template.json"),this.configLoaded=!0,null):(this.errorConfig=r.error_config,this.configLoaded=!0,this.debug&&Nt.log("Error config loaded:",this.errorConfig),this.errorConfig)}catch(e){return Nt.error("Failed to load error config:",e),this.configLoaded=!0,null}}async rend Line truncated
with(ctx) { with(ctx) {
try { try {
return Boolean(${r}); return Boolean(${r});
@@ -275,7 +275,7 @@ Error generating stack: `+c.message+`
return false; return false;
} }
} }
`)(a)}return!!e}catch(r){return j.warn(`Failed to evaluate script condition: ${e}`,r),!1}}showInitError(e){const a=Om(e);Kd.renderFromError("app",a,"초기화 실패",this.config.debug,{templateId:this.config.templateId,locale:this.config.locale},void 0,e)}showTransitionOverlay(e,a){const r=typeof e=="boolean"?{enabled:e,style:"opaque",target:void 0,skeleton:void 0,spinner:void 0}:{enabled:e.enabled,style:e.style||"opaque",target:e.target,skeleton:e.skeleton,spinner:e.spinner,fallback_target:e.fallback_target};if(!r.enabled)return;if(this.hideTransitionOverlay(),r.style==="skeleton"&&r.skeleton?.component&&r.target&&a){this.renderSkeletonOverlay(r.target,r.skeleton,a,r.fallback_target);return}if(r.style==="spinner"&&r.target){this.renderSpinnerOverlay(r.target,r.spinner,r.fallback_target);return}const i=document.documentElement.classList.contains("dark");let o,u="";switch(r.style){case"blur":o=i?"rgba(17,24,39,0.3)":"rgba(255,255,255,0.3)",u="backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);";break;case"fade":o=i?"rgba(17,24,39,0.8)":"rgba(255,255,255,0.8)";break;case"skeleton":o=i?"rgb(17,24,39)":"rgb(249,250,251)";break;case"opaque":default:o=i?"rgb(17,24,39)":"rgb(249,250,251)";break}if(r.target){const d=`#${CSS.escape(r.target)}`,f=document.createElement("style");f.id="g7-transition-overlay",f.textContent=`${d}{position:relative;z-index:0;}${d}::after{content:'';position:absolute;inset:0;background:${o};${u}z-index:2147483647;pointer-events:none;}`,document.head.appendChild(f),this.transitionOverlayEl=f}else{const d=document.createElement("div");d.id="g7-transition-overlay",d.setAttribute("aria-hidden","true"),d.style.position="fixed",d.style.inset="0",d.style.zIndex="9999",d.style.pointerEvents="none",d.style.background=o;for(const f of u.split(";")){const g=f.indexOf(":");g!==-1&&d.style.setProperty(f.slice(0,g).trim(),f.slice(g+1).trim())}document.body.appendChild(d),this.transitionOverlayEl=d}}hideTransitionOverlay(){this.transitionOverlayEl&&(this.transitionOverlayEl.remove(),this.transitionOverlayEl=null),this.hideSkeletonOverlay()}renderSkeletonOverlay(e,a,r,i){const u=fa.getInstance().getComponent(a.component);if(!u){j.log(`Skeleton component "${a.component}" not found in registry, falling back to opaque overlay`),this.showTransitionOverlay({enabled:!0,style:"opaque",target:e});return}let d=document.getElementById(e),f="target";if(!d&&i&&(d=document.getElementById(i),f="fallback"),d||(d=document.getElementById("app"),f="fullpage"),!d){j.log(`Skeleton overlay: no target found (target="#${e}", fallback="${i||"none"}"), falling back to opaque overlay`),this.showTransitionOverlay({enabled:!0,style:"opaque",target:e});return}this.hideSkeletonOverlay();const m=document.documentElement.classList.contains("dark")?"rgb(17,24,39)":"rgb(249,250,251)",b=f==="fullpage"?"app":f==="fallback"?i:e,v=`#${CSS.escape(b)}`,E=document.createElement("style");E.id="g7-skeleton-overlay-style",E.textContent=`${v}{position:relative;z-index:0;}${v}::after{content:'';position:absolute;inset:0;background:${m};z-index:2147483646;pointer-events:none;}`,document.head.appendChild(E),this.transitionOverlayEl=E;const S=document.createElement("div");if(S.id="g7-skeleton-overlay",S.setAttribute("role","status"),S.setAttribute("aria-busy","true"),S.setAttribute("aria-label","Loading..."),f==="fullpage")S.style.cssText=["position:fixed","inset:0","z-index:20","overflow:hidden","pointer-events:none",`background:${m}`].join(";")+";";else{const O=d.getBoundingClientRect(),L=window.scrollX||document.documentElement.scrollLeft,P=window.scrollY||document.documentElement.scrollTop;S.style.cssText=["position:absolute",`top:${O.top+P}px`,`left:${O.left+L}px`,`width:${O.width}px`,`height:${O.height}px`,"z-index:20","overflow:hidden","pointer-events:none",`background:${m}`].join(";")+";"}document.body.appendChild(S),this.skeletonOverlayContainer=S;const A=r.components||[];let T;if(f==="fullpage")T=A;else{const O=f==="fallback"?i:e;T=this.findComponentChildrenById(A,O)}const D=Pu.createRoot(S);this.skeletonOverlayRoot=D,Ar.flushSync(()=>{D.render(We.createElement(u,{components:T,options:{animation:a.animation||"pulse",iteration_count:a.iteration_count||5}}))});const M=f==="fullpage"?"fullpage (#app)":f==="fallback"?`fallback (#${i})`:`target (#${e})`;j.log(`Skeleton overlay rendered [${M}] with "${a.component}" (${T.length} components)`)}findComponentChildrenById(e,a){const r=i=>{for(const o of i){if(o.id===a)return o.children||[];if(o.children&&Array.isArray(o.children)){const u=r(o.children);if(u!==null)return u}}return null};return r(e)||e}renderSpinnerOverlay(e,a,r){let i=document.getElementById(e),o="target";if(!i&&r&&(i=document.getElementById(r),o="fallback"),i||(i=document.getElementById("app"),o="fullpage"),!i){j.log(`Spinner overlay: no target found (target="#${e}", fallback="${r||"none"}"), falling back to opaque overlay`),this.showTransitionOverlay({enabled:!0,style:"opaque",target:e});return}this.hideSkele Line truncated `)(a)}return!!e}catch(r){return j.warn(`Failed to evaluate script condition: ${e}`,r),!1}}showInitError(e){const a=Om(e);Kd.renderFromError("app",a,"초기화 실패",this.config.debug,{templateId:this.config.templateId,locale:this.config.locale},void 0,e)}showTransitionOverlay(e,a){const r=typeof e=="boolean"?{enabled:e,style:"opaque",target:void 0,skeleton:void 0,spinner:void 0}:{enabled:e.enabled,style:e.style||"opaque",target:e.target,skeleton:e.skeleton,spinner:e.spinner,fallback_target:e.fallback_target};if(!r.enabled)return;if(this.hideTransitionOverlay(),r.style==="skeleton"&&r.skeleton?.component&&r.target&&a){this.renderSkeletonOverlay(r.target,r.skeleton,a,r.fallback_target);return}if(r.style==="spinner"&&r.target){this.renderSpinnerOverlay(r.target,r.spinner,r.fallback_target);return}const i=document.documentElement.classList.contains("dark");let o,u="";switch(r.style){case"blur":o=i?"rgba(17,24,39,0.3)":"rgba(255,255,255,0.3)",u="backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);";break;case"fade":o=i?"rgba(17,24,39,0.8)":"rgba(255,255,255,0.8)";break;case"skeleton":o=i?"rgb(17,24,39)":"rgb(249,250,251)";break;case"opaque":default:o=i?"rgb(17,24,39)":"rgb(249,250,251)";break}if(r.target){const d=`#${CSS.escape(r.target)}`,f=document.createElement("style");f.id="g7-transition-overlay",f.textContent=`${d}{position:relative;z-index:0;}${d}::after{content:'';position:absolute;inset:0;background:${o};${u}z-index:2147483647;pointer-events:none;}`,document.head.appendChild(f),this.transitionOverlayEl=f}else{const d=document.createElement("div");d.id="g7-transition-overlay",d.setAttribute("aria-hidden","true"),d.style.position="fixed",d.style.inset="0",d.style.zIndex="9999",d.style.pointerEvents="none",d.style.background=o;for(const f of u.split(";")){const g=f.indexOf(":");g!==-1&&d.style.setProperty(f.slice(0,g).trim(),f.slice(g+1).trim())}document.body.appendChild(d),this.transitionOverlayEl=d}}hideTransitionOverlay(){this.transitionOverlayEl&&(this.transitionOverlayEl.remove(),this.transitionOverlayEl=null),this.hideSkeletonOverlay()}renderSkeletonOverlay(e,a,r,i){const u=fa.getInstance().getComponent(a.component);if(!u){j.log(`Skeleton component "${a.component}" not found in registry, falling back to opaque overlay`),this.showTransitionOverlay({enabled:!0,style:"opaque",target:e});return}let d=document.getElementById(e),f="target";if(!d&&i&&(d=document.getElementById(i),f="fallback"),d||(d=document.getElementById("app"),f="fullpage"),!d){j.log(`Skeleton overlay: no target found (target="#${e}", fallback="${i||"none"}"), falling back to opaque overlay`),this.showTransitionOverlay({enabled:!0,style:"opaque",target:e});return}this.hideSkeletonOverlay();const m=document.documentElement.classList.contains("dark")?"rgb(17,24,39)":"rgb(249,250,251)",b=f==="fullpage"?"app":f==="fallback"?i:e,v=`#${CSS.escape(b)}`,E=document.createElement("style");E.id="g7-skeleton-overlay-style",E.textContent=`${v}{position:relative;z-index:0;}${v}::after{content:'';position:absolute;inset:0;background:${m};z-index:2147483646;pointer-events:none;}`,document.head.appendChild(E),this.transitionOverlayEl=E;const S=document.createElement("div");if(S.id="g7-skeleton-overlay",S.setAttribute("role","status"),S.setAttribute("aria-busy","true"),S.setAttribute("aria-label","Loading..."),f==="fullpage")S.style.cssText=["position:fixed","inset:0","z-index:20","overflow:hidden","pointer-events:none",`background:${m}`].join(";")+";";else{const O=d.getBoundingClientRect(),L=window.scrollX||document.documentElement.scrollLeft,P=window.scrollY||document.documentElement.scrollTop;S.style.cssText=["position:absolute",`top:${O.top+P}px`,`left:${O.left+L}px`,`width:${O.width}px`,`height:${O.height}px`,"z-index:20","overflow:hidden","pointer-events:none",`background:${m}`].join(";")+";"}document.body.appendChild(S),this.skeletonOverlayContainer=S;const A=r.components||[];let T;if(f==="fullpage")T=A;else{const O=f==="fallback"?i:e;T=this.findComponentChildrenById(A,O)}const D=Pu.createRoot(S);this.skeletonOverlayRoot=D,Ar.flushSync(()=>{D.render(We.createElement(u,{components:T,options:{animation:a.animation||"pulse",iteration_count:a.iteration_count||5}}))});const M=f==="fullpage"?"fullpage (#app)":f==="fallback"?`fallback (#${i})`:`target (#${e})`;j.log(`Skeleton overlay rendered [${M}] with "${a.component}" (${T.length} components)`)}findComponentChildrenById(e,a){const r=i=>{for(const o of i){if(o.id===a)return o.children||[];if(o.children&&Array.isArray(o.children)){const u=r(o.children);if(u!==null)return u}}return null};return r(e)||e}renderSpinnerOverlay(e,a,r){let i=document.getElementById(e),o="target";if(!i&&r&&(i=document.getElementById(r),o="fallback"),i||(i=document.getElementById("app"),o="fullpage"),!i){j.log(`Spinner overlay: no target found (target="#${e}", fallback="${r||"none"}"), falling back to opaque overlay`),this.showTransitionOverlay({enabled:!0,style:"opaque",target:e});return}this.hideSkele Line truncated
with(ctx) { with(ctx) {
try { try {
return ${e}; return ${e};
@@ -283,5 +283,5 @@ Error generating stack: `+c.message+`
return undefined; return undefined;
} }
} }
`)(a)}catch(r){j.warn(`Expression evaluation failed: ${e}`,r);return}}async executeInitActions(e,a={}){const{getActionDispatcher:r}=await Promise.resolve().then(()=>Ia),i=r();if(!i){j.warn("ActionDispatcher not available for init_actions");return}j.log("Executing init_actions:",e.map(d=>d.handler)),j.log("Init actions dataContext:",a),j.log("Init actions dataContext._global:",a._global);const o=e.map(d=>d.handler).filter(d=>d.includes("."));o.length>0&&await this.waitForHandlers(i,o);let u={...a};for(const d of e)try{const f={type:"click",handler:d.handler,target:d.target,params:d.params,resultTo:d.resultTo,onSuccess:d.onSuccess,onError:d.onError,if:d.if,conditions:d.conditions,auth_mode:d.auth_mode,auth_required:d.auth_required},g=i.createHandler(f,u),m=new Event("init");await g(m),j.log(`Init action executed: ${d.handler}`);const b=this.globalState;u={...u,_global:{...b},_local:b._local||u._local||{}},j.log(`Data context refreshed after ${d.handler}:`,{cartKey:u._global?.cartKey})}catch(f){j.error(`Failed to execute init action: ${d.handler}`,f)}}async waitForHandlers(e,a,r=5e3){const i=Date.now(),o=50,u=()=>a.every(d=>e.customHandlers?.has(d));if(u()){j.log("All module handlers already registered");return}return j.log("Waiting for module handlers:",a),new Promise(d=>{const f=()=>{if(u()){j.log("All module handlers now registered"),d();return}if(Date.now()-i>=r){const g=a.filter(m=>!e.customHandlers?.has(m));j.warn("Timeout waiting for handlers:",g),d();return}setTimeout(f,o)};f()})}};$(Ea,"LOCALE_STORAGE_KEY","g7_locale"),$(Ea,"CACHE_VERSION_STORAGE_KEY","g7_cache_version");let mo=Ea;function Xd(l){const e=new mo(l);return l.websocket&&(hc.configure(l.websocket),j.log("WebSocket 설정 완료")),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{e.init(),window.__templateApp=e}):(e.init(),window.__templateApp=e),e}typeof window<"u"&&(window.G7Core=window.G7Core||{},window.G7Core.initTemplateApp=Xd,window.G7Core.dataSource={refetch:async(l,e)=>{const a=window.__templateApp;if(!a){j.warn("TemplateApp not initialized (G7Core.dataSource.refetch)");return}return a.refetchDataSource(l,e)},get:l=>{const e=window.__templateApp;if(!e){j.warn("TemplateApp not initialized (G7Core.dataSource.get)");return}return e.getDataSource(l)}});function FE(l={}){const{checked:e,value:a,name:r,type:i="checkbox"}=l,u=a!==void 0?a:i==="checkbox"||i==="radio"?e??!1:String(e??""),d={checked:e??!1,value:u,name:r??"",type:i};return{target:d,currentTarget:d,preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new Event("change"),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:"change",isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{}}}function KE(l={}){const{button:e=0,clientX:a=0,clientY:r=0}=l;return{button:e,clientX:a,clientY:r,preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new MouseEvent("click"),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:"click",isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{},target:document.createElement("div"),currentTarget:document.createElement("div")}}function WE(){return{preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new Event("submit"),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:"submit",isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{},target:document.createElement("form"),currentTarget:document.createElement("form")}}function YE(l,e="keydown"){return{key:l,code:l.length===1?`Key${l.toUpperCase()}`:l,preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new KeyboardEvent(e,{key:l}),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:e,isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{},target:document.createElement("div"),currentTarget:document.createElement("div"),altKey:!1,ctrlKey:!1,metaKey:!1,shiftKey:!1,repeat:!1}}const XE={justify:/^justify-(start|end|center|between|around|evenly)$/,items:/^items-(start|end|center|baseline|stretch)$/,content:/^content-(start|end|center|between|around|evenly|stretch)$/,self:/^self-(auto|start|end|center|stretch|baseline)$/,flex:/^flex-(row|row-reverse|col|col-reverse|wrap|wrap-reverse|nowrap|1|auto|initial|none)$/,grow:/^(grow|grow-0)$/,shrink:/^(shrink|shrink-0)$/,basis:/^basis-/,order:/^(order-|-)order-/,gap:/^gap(-x|-y)?-/,gridCols:/^grid-cols-/,gridRows:/^grid-rows-/,colSpan:/^col-(span-|start-|end-)/,rowSpan:/^row-(span-|start-|end-)/,display:/^(block|inline-block|inline|flex|inline-flex|table|inline-table|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row-group|table-row|flow-root|grid|inline-grid|contents|list-item|hidden)$/,position:/^(static|fixed|absolute|relative|sticky)$/,inset:/^(inset|top|right|bottom|le Line truncated `)(a)}catch(r){j.warn(`Expression evaluation failed: ${e}`,r);return}}async executeInitActions(e,a={}){const{getActionDispatcher:r}=await Promise.resolve().then(()=>Ia),i=r();if(!i){j.warn("ActionDispatcher not available for init_actions");return}j.log("Executing init_actions:",e.map(d=>d.handler)),j.log("Init actions dataContext:",a),j.log("Init actions dataContext._global:",a._global);const o=e.map(d=>d.handler).filter(d=>d.includes("."));o.length>0&&await this.waitForHandlers(i,o);let u={...a};for(const d of e)try{const f={type:"click",handler:d.handler,target:d.target,params:d.params,resultTo:d.resultTo,onSuccess:d.onSuccess,onError:d.onError,if:d.if,conditions:d.conditions,auth_mode:d.auth_mode,auth_required:d.auth_required},g=i.createHandler(f,u),m=new Event("init");await g(m),j.log(`Init action executed: ${d.handler}`);const b=this.globalState;u={...u,_global:{...b},_local:b._local||u._local||{}},j.log(`Data context refreshed after ${d.handler}:`,{cartKey:u._global?.cartKey})}catch(f){j.error(`Failed to execute init action: ${d.handler}`,f)}}async waitForHandlers(e,a,r=5e3){const i=Date.now(),o=50,u=()=>a.every(d=>e.customHandlers?.has(d));if(u()){j.log("All module handlers already registered");return}return j.log("Waiting for module handlers:",a),new Promise(d=>{const f=()=>{if(u()){j.log("All module handlers now registered"),d();return}if(Date.now()-i>=r){const g=a.filter(m=>!e.customHandlers?.has(m));j.warn("Timeout waiting for handlers:",g),d();return}setTimeout(f,o)};f()})}};$(Ea,"LOCALE_STORAGE_KEY","g7_locale"),$(Ea,"CACHE_VERSION_STORAGE_KEY","g7_cache_version");let mo=Ea;function Xd(l){const e=new mo(l);return l.websocket&&(hc.configure(l.websocket),j.log("WebSocket 설정 완료")),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{e.init(),window.__templateApp=e}):(e.init(),window.__templateApp=e),e}typeof window<"u"&&(window.G7Core=window.G7Core||{},window.G7Core.initTemplateApp=Xd,window.G7Core.dataSource={refetch:async(l,e)=>{const a=window.__templateApp;if(!a){j.warn("TemplateApp not initialized (G7Core.dataSource.refetch)");return}return a.refetchDataSource(l,e)},get:l=>{const e=window.__templateApp;if(!e){j.warn("TemplateApp not initialized (G7Core.dataSource.get)");return}return e.getDataSource(l)}});function KE(l={}){const{checked:e,value:a,name:r,type:i="checkbox"}=l,u=a!==void 0?a:i==="checkbox"||i==="radio"?e??!1:String(e??""),d={checked:e??!1,value:u,name:r??"",type:i};return{target:d,currentTarget:d,preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new Event("change"),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:"change",isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{}}}function WE(l={}){const{button:e=0,clientX:a=0,clientY:r=0}=l;return{button:e,clientX:a,clientY:r,preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new MouseEvent("click"),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:"click",isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{},target:document.createElement("div"),currentTarget:document.createElement("div")}}function YE(){return{preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new Event("submit"),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:"submit",isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{},target:document.createElement("form"),currentTarget:document.createElement("form")}}function XE(l,e="keydown"){return{key:l,code:l.length===1?`Key${l.toUpperCase()}`:l,preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:new KeyboardEvent(e,{key:l}),bubbles:!0,cancelable:!0,defaultPrevented:!1,eventPhase:Event.AT_TARGET,isTrusted:!1,timeStamp:Date.now(),type:e,isDefaultPrevented:()=>!1,isPropagationStopped:()=>!1,persist:()=>{},target:document.createElement("div"),currentTarget:document.createElement("div"),altKey:!1,ctrlKey:!1,metaKey:!1,shiftKey:!1,repeat:!1}}const JE={justify:/^justify-(start|end|center|between|around|evenly)$/,items:/^items-(start|end|center|baseline|stretch)$/,content:/^content-(start|end|center|between|around|evenly|stretch)$/,self:/^self-(auto|start|end|center|stretch|baseline)$/,flex:/^flex-(row|row-reverse|col|col-reverse|wrap|wrap-reverse|nowrap|1|auto|initial|none)$/,grow:/^(grow|grow-0)$/,shrink:/^(shrink|shrink-0)$/,basis:/^basis-/,order:/^(order-|-)order-/,gap:/^gap(-x|-y)?-/,gridCols:/^grid-cols-/,gridRows:/^grid-rows-/,colSpan:/^col-(span-|start-|end-)/,rowSpan:/^row-(span-|start-|end-)/,display:/^(block|inline-block|inline|flex|inline-flex|table|inline-table|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row-group|table-row|flow-root|grid|inline-grid|contents|list-item|hidden)$/,position:/^(static|fixed|absolute|relative|sticky)$/,inset:/^(inset|top|right|bottom|le Line truncated
//# sourceMappingURL=template-engine.min.js.map //# sourceMappingURL=template-engine.min.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"template-engine.min.js","sources":["../../../node_modules/react/cjs/react.production.js","../../../node_modules/react/index.js","../../../node_modules/scheduler/cjs/scheduler.production.js","../../../node_modules/scheduler/index.js","../../../node_modules/react-dom/cjs/react-dom.production.js","../../../node_modules/react-dom/index.js","../../../node_modules/react-dom/cjs/react-dom-client.production.js","../../../node_modules/react-dom/client.js","../../../resources/js/core/utils/Logger.ts","../../../resources/js/core/template-engine/ComponentRegistry.ts","../../../resources/js/core/template-engine/TranslationEngine.ts","../../../resources/js/core/template-engine/PipeRegistry.ts","../../../resources/js/core/template-engine/rawMarkers.ts","../../../resources/js/core/template-engine/DataBindingEngine.ts","../../../resources/js/core/template-engine/ResponsiveManager.ts","../../../resources/js/core/template-engine/helpers/ConditionEvaluator.ts","../../../resources/js/core/template-engine/helpers/RenderHelpers.ts","../../../node_modules/axios/lib/helpers/bind.js","../../../node_modules/axios/lib/utils.js","../../../node_modules/axios/lib/core/AxiosError.js","../../../node_modules/axios/lib/helpers/null.js","../../../node_modules/axios/lib/helpers/toFormData.js","../../../node_modules/axios/lib/helpers/AxiosURLSearchParams.js","../../../node_modules/axios/lib/helpers/buildURL.js","../../../node_modules/axios/lib/core/InterceptorManager.js","../../../node_modules/axios/lib/defaults/transitional.js","../../../node_modules/axios/lib/platform/browser/index.js","../../../node_modules/axios/lib/platform/browser/classes/URLSearchParams.js","../../../node_modules/axios/lib/platform/browser/classes/FormData.js","../../../node_modules/axios/lib/platform/browser/classes/Blob.js","../../../node_modules/axios/lib/platform/common/utils.js","../../../node_modules/axios/lib/platform/index.js","../../../node_modules/axios/lib/helpers/toURLEncodedForm.js","../../../node_modules/axios/lib/helpers/formDataToJSON.js","../../../node_modules/axios/lib/defaults/index.js","../../../node_modules/axios/lib/helpers/parseHeaders.js","../../../node_modules/axios/lib/core/AxiosHeaders.js","../../../node_modules/axios/lib/core/transformData.js","../../../node_modules/axios/lib/cancel/isCancel.js","../../../node_modules/axios/lib/cancel/CanceledError.js","../../../node_modules/axios/lib/core/settle.js","../../../node_modules/axios/lib/helpers/parseProtocol.js","../../../node_modules/axios/lib/helpers/speedometer.js","../../../node_modules/axios/lib/helpers/throttle.js","../../../node_modules/axios/lib/helpers/progressEventReducer.js","../../../node_modules/axios/lib/helpers/isURLSameOrigin.js","../../../node_modules/axios/lib/helpers/cookies.js","../../../node_modules/axios/lib/helpers/isAbsoluteURL.js","../../../node_modules/axios/lib/helpers/combineURLs.js","../../../node_modules/axios/lib/core/buildFullPath.js","../../../node_modules/axios/lib/core/mergeConfig.js","../../../node_modules/axios/lib/helpers/resolveConfig.js","../../../node_modules/axios/lib/adapters/xhr.js","../../../node_modules/axios/lib/helpers/composeSignals.js","../../../node_modules/axios/lib/helpers/trackStream.js","../../../node_modules/axios/lib/adapters/fetch.js","../../../node_modules/axios/lib/adapters/adapters.js","../../../node_modules/axios/lib/core/dispatchRequest.js","../../../node_modules/axios/lib/env/data.js","../../../node_modules/axios/lib/helpers/validator.js","../../../node_modules/axios/lib/core/Axios.js","../../../node_modules/axios/lib/cancel/CancelToken.js","../../../node_modules/axios/lib/helpers/spread.js","../../../node_modules/axios/lib/helpers/isAxiosError.js","../../../node_modules/axios/lib/helpers/HttpStatusCode.js","../../../node_modules/axios/lib/axios.js","../../../node_modules/axios/index.js","../../../resources/js/core/identity/types.ts","../../../resources/js/core/identity/IdentityGuardInterceptor.ts","../../../resources/js/core/api/ApiClient.ts","../../../resources/js/core/auth/AuthManager.ts","../../../resources/js/core/types/ErrorHandling.ts","../../../resources/js/core/error/ErrorHandlingResolver.ts","../../../node_modules/react/cjs/react-jsx-runtime.production.js","../../../node_modules/react/jsx-runtime.js","../../../resources/js/core/template-engine/ParentContextProvider.tsx","../../../resources/js/core/template-engine/ActionDispatcher.ts","../../../resources/js/core/template-engine/TransitionManager.ts","../../../resources/js/core/template-engine/TransitionContext.tsx","../../../resources/js/core/template-engine/ResponsiveContext.tsx","../../../resources/js/core/hooks/useControllableState.ts","../../../resources/js/core/template-engine/FormContext.tsx","../../../resources/js/core/template-engine/IsolatedStateContext.tsx","../../../node_modules/@dnd-kit/utilities/dist/utilities.esm.js","../../../node_modules/@dnd-kit/accessibility/dist/accessibility.esm.js","../../../node_modules/@dnd-kit/core/dist/core.esm.jLine truncated {"version":3,"file":"template-engine.min.js","sources":["../../../node_modules/react/cjs/react.production.js","../../../node_modules/react/index.js","../../../node_modules/scheduler/cjs/scheduler.production.js","../../../node_modules/scheduler/index.js","../../../node_modules/react-dom/cjs/react-dom.production.js","../../../node_modules/react-dom/index.js","../../../node_modules/react-dom/cjs/react-dom-client.production.js","../../../node_modules/react-dom/client.js","../../../resources/js/core/utils/Logger.ts","../../../resources/js/core/template-engine/ComponentRegistry.ts","../../../resources/js/core/template-engine/TranslationEngine.ts","../../../resources/js/core/template-engine/PipeRegistry.ts","../../../resources/js/core/template-engine/rawMarkers.ts","../../../resources/js/core/template-engine/DataBindingEngine.ts","../../../resources/js/core/template-engine/ResponsiveManager.ts","../../../resources/js/core/template-engine/helpers/ConditionEvaluator.ts","../../../resources/js/core/template-engine/helpers/RenderHelpers.ts","../../../node_modules/axios/lib/helpers/bind.js","../../../node_modules/axios/lib/utils.js","../../../node_modules/axios/lib/core/AxiosError.js","../../../node_modules/axios/lib/helpers/null.js","../../../node_modules/axios/lib/helpers/toFormData.js","../../../node_modules/axios/lib/helpers/AxiosURLSearchParams.js","../../../node_modules/axios/lib/helpers/buildURL.js","../../../node_modules/axios/lib/core/InterceptorManager.js","../../../node_modules/axios/lib/defaults/transitional.js","../../../node_modules/axios/lib/platform/browser/index.js","../../../node_modules/axios/lib/platform/browser/classes/URLSearchParams.js","../../../node_modules/axios/lib/platform/browser/classes/FormData.js","../../../node_modules/axios/lib/platform/browser/classes/Blob.js","../../../node_modules/axios/lib/platform/common/utils.js","../../../node_modules/axios/lib/platform/index.js","../../../node_modules/axios/lib/helpers/toURLEncodedForm.js","../../../node_modules/axios/lib/helpers/formDataToJSON.js","../../../node_modules/axios/lib/defaults/index.js","../../../node_modules/axios/lib/helpers/parseHeaders.js","../../../node_modules/axios/lib/core/AxiosHeaders.js","../../../node_modules/axios/lib/core/transformData.js","../../../node_modules/axios/lib/cancel/isCancel.js","../../../node_modules/axios/lib/cancel/CanceledError.js","../../../node_modules/axios/lib/core/settle.js","../../../node_modules/axios/lib/helpers/parseProtocol.js","../../../node_modules/axios/lib/helpers/speedometer.js","../../../node_modules/axios/lib/helpers/throttle.js","../../../node_modules/axios/lib/helpers/progressEventReducer.js","../../../node_modules/axios/lib/helpers/isURLSameOrigin.js","../../../node_modules/axios/lib/helpers/cookies.js","../../../node_modules/axios/lib/helpers/isAbsoluteURL.js","../../../node_modules/axios/lib/helpers/combineURLs.js","../../../node_modules/axios/lib/core/buildFullPath.js","../../../node_modules/axios/lib/core/mergeConfig.js","../../../node_modules/axios/lib/helpers/resolveConfig.js","../../../node_modules/axios/lib/adapters/xhr.js","../../../node_modules/axios/lib/helpers/composeSignals.js","../../../node_modules/axios/lib/helpers/trackStream.js","../../../node_modules/axios/lib/adapters/fetch.js","../../../node_modules/axios/lib/adapters/adapters.js","../../../node_modules/axios/lib/core/dispatchRequest.js","../../../node_modules/axios/lib/env/data.js","../../../node_modules/axios/lib/helpers/validator.js","../../../node_modules/axios/lib/core/Axios.js","../../../node_modules/axios/lib/cancel/CancelToken.js","../../../node_modules/axios/lib/helpers/spread.js","../../../node_modules/axios/lib/helpers/isAxiosError.js","../../../node_modules/axios/lib/helpers/HttpStatusCode.js","../../../node_modules/axios/lib/axios.js","../../../node_modules/axios/index.js","../../../resources/js/core/identity/types.ts","../../../resources/js/core/identity/IdentityGuardInterceptor.ts","../../../resources/js/core/api/ApiClient.ts","../../../resources/js/core/auth/AuthManager.ts","../../../resources/js/core/types/ErrorHandling.ts","../../../resources/js/core/error/ErrorHandlingResolver.ts","../../../node_modules/react/cjs/react-jsx-runtime.production.js","../../../node_modules/react/jsx-runtime.js","../../../resources/js/core/template-engine/ParentContextProvider.tsx","../../../resources/js/core/template-engine/ActionDispatcher.ts","../../../resources/js/core/template-engine/TransitionManager.ts","../../../resources/js/core/template-engine/TransitionContext.tsx","../../../resources/js/core/template-engine/ResponsiveContext.tsx","../../../resources/js/core/hooks/useControllableState.ts","../../../resources/js/core/template-engine/FormContext.tsx","../../../resources/js/core/template-engine/IsolatedStateContext.tsx","../../../node_modules/@dnd-kit/utilities/dist/utilities.esm.js","../../../node_modules/@dnd-kit/accessibility/dist/accessibility.esm.js","../../../node_modules/@dnd-kit/core/dist/core.esm.jLine truncated
+43 -20
View File
@@ -26,7 +26,7 @@ import { getErrorHandlingResolver } from './error';
import type { ErrorHandlingMap } from './types/ErrorHandling'; import type { ErrorHandlingMap } from './types/ErrorHandling';
import { createLogger, Logger } from './utils/Logger'; import { createLogger, Logger } from './utils/Logger';
import { webSocketManager } from './websocket/WebSocketManager'; import { webSocketManager } from './websocket/WebSocketManager';
import { getModuleAssetLoader, parseModuleAssetsFromConfig, parsePluginAssetsFromConfig } from './modules'; import { getModuleAssetLoader, parseModuleAssetsFromConfig, parsePluginAssetsFromConfig, parseBundleUrlsFromConfig } from './modules';
import { SystemBannerManager } from './template-engine/SystemBannerManager'; import { SystemBannerManager } from './template-engine/SystemBannerManager';
/** /**
* DevTools 추적 - G7DevToolsCore.getInstance() 직접 호출 대신 G7Core.devTools를 사용합니다. * DevTools 추적 - G7DevToolsCore.getInstance() 직접 호출 대신 G7Core.devTools를 사용합니다.
@@ -722,41 +722,64 @@ export class TemplateApp {
} }
/** /**
* 모듈/플러그인 에셋 로드 * 모듈/플러그인 에셋 로드 (서버측 병합 번들)
* *
* window.G7Config.moduleAssets 및 pluginAssets에서 에셋 정보를 읽어 * window.G7Config.bundleUrls 에서 병합 번들 URL 을 읽어 모듈 번들 →
* 동적으로 JS/CSS를 로드합니다. * 플러그인 번들 순으로 로드한다. 각 번들은 활성 확장 IIFE 를 priority 순으로
* 이어붙인 단일 파일이며, 로드 즉시 각 IIFE 가 자가등록(핸들러/리스너)을
* 실행한다. 개별 로딩(loadActiveExtensionAssets)과 실행 계약은 동일하다.
* *
* 모듈 JS는 IIFE 형태로 빌드되어 로드 즉시 initModule()이 실행되고, * 모듈 → 플러그인 순서를 유지하는 이유: gdpr preblocker 등 인터셉터가
* ActionDispatcher에 핸들러가 등록됩니다. * 플러그인 번들 내 priority 최상단으로 오되 모듈보다는 뒤에 실행된다
* (2번들 구조). bundleUrls 가 없으면(구버전 blade) 개별 로딩으로 폴백한다.
*
* @since engine-v1.52.0 (서버측 번들 로딩으로 전환)
*/ */
private async loadExtensionAssets(): Promise<void> { private async loadExtensionAssets(): Promise<void> {
try { try {
const moduleAssetLoader = getModuleAssetLoader(); const moduleAssetLoader = getModuleAssetLoader();
const bundleUrls = parseBundleUrlsFromConfig();
// 모듈 에셋 로드 // bundleUrls 부재 시 개별 로딩 폴백 (회귀 안전)
const moduleAssets = parseModuleAssetsFromConfig(); if (!bundleUrls) {
if (moduleAssets.length > 0) { await this.loadExtensionAssetsIndividually();
logger.log('Loading module assets:', moduleAssets.map(m => m.identifier)); return;
await moduleAssetLoader.loadActiveExtensionAssets(moduleAssets);
} }
// 플러그인 에셋 로드 // 모듈 번들 → 플러그인 번들 순서 (gdpr 는 플러그인 번들 내 최상단)
const pluginAssets = parsePluginAssetsFromConfig(); await moduleAssetLoader.loadBundle('module', bundleUrls.moduleJs, bundleUrls.moduleCss);
if (pluginAssets.length > 0) { await moduleAssetLoader.loadBundle('plugin', bundleUrls.pluginJs, bundleUrls.pluginCss);
logger.log('Loading plugin assets:', pluginAssets.map(p => p.identifier));
await moduleAssetLoader.loadActiveExtensionAssets(pluginAssets);
}
if (moduleAssets.length > 0 || pluginAssets.length > 0) { logger.log('Extension bundle assets loaded successfully');
logger.log('Extension assets loaded successfully');
}
} catch (error) { } catch (error) {
// 에셋 로드 실패는 경고만 출력하고 앱 계속 진행 // 에셋 로드 실패는 경고만 출력하고 앱 계속 진행
logger.warn('Failed to load extension assets:', error); logger.warn('Failed to load extension assets:', error);
} }
} }
/**
* 개별 확장 에셋 로드 (bundleUrls 부재 시 폴백)
*
* window.G7Config.moduleAssets/pluginAssets 에서 확장별 개별 URL 을 읽어
* priority 순으로 각각 로드한다. 서버측 번들이 준비되지 않은 구버전 blade
* 환경 회귀 안전용.
*/
private async loadExtensionAssetsIndividually(): Promise<void> {
const moduleAssetLoader = getModuleAssetLoader();
const moduleAssets = parseModuleAssetsFromConfig();
if (moduleAssets.length > 0) {
logger.log('Loading module assets (individual fallback):', moduleAssets.map(m => m.identifier));
await moduleAssetLoader.loadActiveExtensionAssets(moduleAssets);
}
const pluginAssets = parsePluginAssetsFromConfig();
if (pluginAssets.length > 0) {
logger.log('Loading plugin assets (individual fallback):', pluginAssets.map(p => p.identifier));
await moduleAssetLoader.loadActiveExtensionAssets(pluginAssets);
}
}
/** /**
* 라우트 변경 핸들러 * 라우트 변경 핸들러
*/ */
@@ -96,6 +96,121 @@ export class ModuleAssetLoader {
logger.log('All module assets loaded successfully'); logger.log('All module assets loaded successfully');
} }
/**
* 서버측에서 병합된 확장 번들(JS/CSS)을 로드합니다.
*
* 활성 모듈/플러그인 IIFE 를 priority 순으로 이어붙인 단일 파일을 하나의
* `<script async=false>` 로, CSS 는 하나의 `<link>` 로 append 한다. 개별
* 로딩과 달리 확장 수와 무관하게 요청 1(+1)건으로 끝난다. `<script async=false>`
* 는 번들 내부 물리 순서로 실행되므로 병합 시 priority 정렬이 곧 실행 순서다.
*
* 중복 append 가드 — 같은 key(module/plugin) 는 최초 1회만 로드한다.
*
* @param key 번들 구분 키 (예: 'module' | 'plugin')
* @param jsUrl 병합 JS URL (없으면 스킵)
* @param cssUrl 병합 CSS URL (없으면 스킵)
* @since engine-v1.52.0
*/
async loadBundle(key: string, jsUrl?: string | null, cssUrl?: string | null): Promise<void> {
const promises: Promise<void>[] = [];
if (cssUrl) {
promises.push(this.loadBundleCss(key, cssUrl));
}
if (jsUrl) {
promises.push(this.loadBundleJs(key, jsUrl));
}
if (promises.length === 0) {
logger.log(`No bundle assets to load for: ${key}`);
return;
}
await Promise.all(promises);
}
/**
* 병합 CSS 번들을 단일 `<link>` 로 로드합니다(중복 가드).
*
* @param key 번들 구분 키
* @param url 병합 CSS URL
*/
private async loadBundleCss(key: string, url: string): Promise<void> {
const elementId = `ext-bundle-css-${key}`;
if (document.getElementById(elementId)) {
logger.log(`Bundle CSS already loaded: ${key}`);
return;
}
return new Promise<void>((resolve) => {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
link.id = elementId;
link.onload = () => {
logger.log(`Bundle CSS loaded: ${key}`);
this.registerLoadedAsset(`bundle-${key}`, { type: 'css', element: link });
resolve();
};
link.onerror = () => {
logger.warn(`Failed to load bundle CSS: ${key} (${url})`);
resolve();
};
document.head.appendChild(link);
});
}
/**
* 병합 JS 번들을 단일 `<script async=false>` 로 로드합니다(중복 가드).
*
* @param key 번들 구분 키
* @param url 병합 JS URL
*/
private async loadBundleJs(key: string, url: string): Promise<void> {
const elementId = `ext-bundle-js-${key}`;
if (document.getElementById(elementId)) {
logger.log(`Bundle JS already loaded: ${key}`);
return;
}
const existingPromise = this.loadingPromises.get(elementId);
if (existingPromise) {
logger.log(`Bundle JS already loading: ${key}`);
return existingPromise;
}
const loadPromise = new Promise<void>((resolve) => {
const script = document.createElement('script');
script.src = url;
script.id = elementId;
script.async = false; // 번들 내부 물리 순서로 실행 보장
script.onload = () => {
logger.log(`Bundle JS loaded: ${key}`);
this.registerLoadedAsset(`bundle-${key}`, { type: 'js', element: script });
this.loadingPromises.delete(elementId);
resolve();
};
script.onerror = () => {
logger.warn(`Failed to load bundle JS: ${key} (${url})`);
this.loadingPromises.delete(elementId);
resolve();
};
document.head.appendChild(script);
});
this.loadingPromises.set(elementId, loadPromise);
return loadPromise;
}
/** /**
* CSS 파일을 동적으로 로드합니다. * CSS 파일을 동적으로 로드합니다.
* *
@@ -306,6 +421,42 @@ export function parseModuleAssetsFromConfig(): ModuleAsset[] {
return moduleAssets; return moduleAssets;
} }
/**
* 확장 병합 번들 URL 정보 인터페이스
*/
export interface ExtensionBundleUrls {
/** 모듈 병합 JS 번들 URL */
moduleJs?: string | null;
/** 모듈 병합 CSS 번들 URL */
moduleCss?: string | null;
/** 플러그인 병합 JS 번들 URL */
pluginJs?: string | null;
/** 플러그인 병합 CSS 번들 URL */
pluginCss?: string | null;
}
/**
* window.G7Config.bundleUrls 에서 병합 번들 URL 을 파싱합니다.
*
* 활성 global 에셋이 없는 타입은 서버가 null 을 내려주므로, 프론트는 해당
* 번들 로드를 스킵한다. bundleUrls 자체가 없으면(구버전 blade 등) null 반환.
*
* @returns 번들 URL 객체 또는 null
* @since engine-v1.52.0
*/
export function parseBundleUrlsFromConfig(): ExtensionBundleUrls | null {
if (typeof window === 'undefined') {
return null;
}
const g7Config = (window as any).G7Config;
if (!g7Config?.bundleUrls) {
return null;
}
return g7Config.bundleUrls as ExtensionBundleUrls;
}
/** /**
* 플러그인 에셋을 파싱합니다. * 플러그인 에셋을 파싱합니다.
* *
@@ -18,7 +18,7 @@ describe('ModuleAssetLoader', () => {
afterEach(() => { afterEach(() => {
vi.restoreAllMocks(); vi.restoreAllMocks();
document.head.querySelectorAll('[id^="module-js-"],[id^="module-css-"]') document.head.querySelectorAll('[id^="module-js-"],[id^="module-css-"],[id^="ext-bundle-js-"],[id^="ext-bundle-css-"]')
.forEach(el => el.remove()); .forEach(el => el.remove());
}); });
@@ -165,4 +165,110 @@ describe('ModuleAssetLoader', () => {
await expect(loader.loadActiveExtensionAssets([])).resolves.toBeUndefined(); await expect(loader.loadActiveExtensionAssets([])).resolves.toBeUndefined();
}); });
}); });
describe('loadBundle (서버측 병합 번들)', () => {
it('단일 script + 단일 link 를 1개씩만 append 한다', async () => {
const scriptAppends: string[] = [];
const linkAppends: string[] = [];
const appendSpy = vi.spyOn(document.head, 'appendChild').mockImplementation(((node: any) => {
if (node.tagName === 'SCRIPT') {
scriptAppends.push(node.id);
queueMicrotask(() => node.onload?.());
} else if (node.tagName === 'LINK') {
linkAppends.push(node.id);
queueMicrotask(() => node.onload?.());
}
return node;
}) as any);
await loader.loadBundle('module', '/api/modules/bundle.js?v=1', '/api/modules/bundle.css?v=1');
expect(scriptAppends).toEqual(['ext-bundle-js-module']);
expect(linkAppends).toEqual(['ext-bundle-css-module']);
appendSpy.mockRestore();
});
it('번들 script 는 async=false 여야 한다 (내부 순서 실행 보장)', async () => {
const created: HTMLScriptElement[] = [];
const appendSpy = vi.spyOn(document.head, 'appendChild').mockImplementation(((node: any) => {
if (node.tagName === 'SCRIPT') {
created.push(node);
queueMicrotask(() => node.onload?.());
}
return node;
}) as any);
await loader.loadBundle('plugin', '/api/plugins/bundle.js?v=1', null);
expect(created).toHaveLength(1);
expect(created[0].async).toBe(false);
appendSpy.mockRestore();
});
it('같은 key 를 중복 로드하지 않는다 (중복 가드)', async () => {
let scriptCount = 0;
// 실제 DOM 에 삽입해 element id 가 등록되어야 getElementById 중복 가드가 동작
const appendSpy = vi.spyOn(document.head, 'appendChild').mockImplementation(((node: any) => {
if (node.tagName === 'SCRIPT') {
scriptCount++;
queueMicrotask(() => node.onload?.());
}
// jsdom 실제 삽입 (id 등록 → 두 번째 호출 시 getElementById 가 찾아 중복 방지)
Node.prototype.appendChild.call(document.head, node);
return node;
}) as any);
await loader.loadBundle('module', '/api/modules/bundle.js?v=1', null);
await loader.loadBundle('module', '/api/modules/bundle.js?v=1', null);
expect(scriptCount).toBe(1);
appendSpy.mockRestore();
});
it('jsUrl/cssUrl 모두 null 이면 no-op', async () => {
const appendSpy = vi.spyOn(document.head, 'appendChild');
await expect(loader.loadBundle('module', null, null)).resolves.toBeUndefined();
expect(appendSpy).not.toHaveBeenCalled();
appendSpy.mockRestore();
});
});
describe('concat 자가등록 (IIFE 병합 계약)', () => {
it(';\\n 로 이어붙인 2개 IIFE 가 모두 실행되어 레지스트리에 자가등록된다', () => {
// 모의 IIFE 2개 — ecommerce IIFE 처럼 세미콜론 없이 끝나도 `\n;\n` 구분자로 ASI 경계 보호
const registry: Record<string, unknown> = {};
(globalThis as any).__G7TestRegistry = registry;
const iifeA = `(function(){"use strict";globalThis.__G7TestRegistry["mod-a"]={handler:"mod-a.doThing"}})()`;
// 세미콜론 없이 끝나는 IIFE (sourceMappingURL 주석 strip 후 형태)
const iifeB = `(function(){"use strict";globalThis.__G7TestRegistry["mod-b"]={handler:"mod-b.doThing"}})()`;
const bundle = [iifeA, iifeB].join('\n;\n');
// 번들 실행 (단일 <script> 실행 시뮬레이션)
// eslint-disable-next-line no-new-func
new Function(bundle)();
expect(registry['mod-a']).toEqual({ handler: 'mod-a.doThing' });
expect(registry['mod-b']).toEqual({ handler: 'mod-b.doThing' });
// 핸들러 네임스페이스 격리 — 각 확장 prefix
expect((registry['mod-a'] as any).handler).toContain('mod-a.');
expect((registry['mod-b'] as any).handler).toContain('mod-b.');
delete (globalThis as any).__G7TestRegistry;
});
it('구분자 없이 이어붙이면 ASI 경계가 깨진다 (구분자 필요성 회귀 가드)', () => {
// 세미콜론 없이 끝나는 IIFE 뒤에 즉시 다음 IIFE 를 붙이면 파싱 에러
const iifeA = `(function(){return 1})()`;
const iifeB = `(function(){return 2})()`;
// 구분자 없는 병합 → `()()(function...` 형태로 호출 연쇄 파싱 (런타임 에러)
expect(() => new Function(iifeA + '\n' + iifeB)()).toThrow();
// 구분자 있는 병합 → 정상
expect(() => new Function(iifeA + '\n;\n' + iifeB)()).not.toThrow();
});
});
}); });
+2 -1
View File
@@ -7,6 +7,7 @@ export {
getModuleAssetLoader, getModuleAssetLoader,
parseModuleAssetsFromConfig, parseModuleAssetsFromConfig,
parsePluginAssetsFromConfig, parsePluginAssetsFromConfig,
parseBundleUrlsFromConfig,
} from './ModuleAssetLoader'; } from './ModuleAssetLoader';
export type { ModuleAsset, ExternalScript } from './ModuleAssetLoader'; export type { ModuleAsset, ExternalScript, ExtensionBundleUrls } from './ModuleAssetLoader';
@@ -5,6 +5,19 @@
> >
> 형식: [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/) > 형식: [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/)
## [engine-v1.52.0] - 2026-07-04
### Added
#### 확장 프론트엔드 에셋 서버측 번들 로딩
- `TemplateApp.loadExtensionAssets()` — 활성 모듈/플러그인 에셋을 확장별 개별 로딩에서 **서버측 병합 번들 로딩**으로 전환한다. `window.G7Config.bundleUrls`(blade 주입)를 읽어 `ModuleAssetLoader.loadBundle('module', ...)` → `loadBundle('plugin', ...)` 순으로 종류별 1개 번들만 로드한다. 확장 IIFE 자가등록 계약(핸들러/리스너/preblocker)은 priority 순 물리 병합으로 실행 순서가 보존되어 그대로 동작한다. `bundleUrls` 부재 시(구버전 blade) 기존 개별 로딩(`loadExtensionAssetsIndividually`)으로 폴백한다.
- `ModuleAssetLoader.loadBundle(key, jsUrl?, cssUrl?)`(신규) — 병합 번들을 단일 `<script async=false>` + 단일 `<link>` 로 append 하고 key(module/plugin)별 중복 로드를 가드한다. `<script async=false>` 로 번들 내부 물리 순서(=priority 정렬)가 곧 실행 순서다.
- `ModuleAssetLoader.parseBundleUrlsFromConfig()` + `ExtensionBundleUrls` 타입(신규) — `G7Config.bundleUrls` 파서. 활성 global 에셋이 없는 타입은 서버가 null 을 내려주어 프론트가 로드를 스킵한다.
- 기존 `loadActiveExtensionAssets`/`parse{Module,Plugin}AssetsFromConfig` 는 폴백 경로로 유지(dead-but-tested).
> 코어 측 번들 병합 서비스(`ExtensionBundleService`)·서빙 엔드포인트·캐시 정책은 루트 CHANGELOG [7.0.1] 및 `docs/extension/module-assets.md` "서버측 번들 병합" 참조.
## [engine-v1.51.0] - 2026-07-03 ## [engine-v1.51.0] - 2026-07-03
### Changed ### Changed
+1
View File
@@ -39,6 +39,7 @@
modules: @json($moduleSettings ?? []), modules: @json($moduleSettings ?? []),
moduleAssets: @json($moduleAssets ?? []), moduleAssets: @json($moduleAssets ?? []),
pluginAssets: @json($pluginAssets ?? []), pluginAssets: @json($pluginAssets ?? []),
bundleUrls: @json($bundleUrls ?? null),
activeModules: @json($activeModulesMeta ?? []), activeModules: @json($activeModulesMeta ?? []),
activePlugins: @json($activePluginsMeta ?? []), activePlugins: @json($activePluginsMeta ?? []),
appConfig: @json($appConfig ?? []), appConfig: @json($appConfig ?? []),
+1
View File
@@ -39,6 +39,7 @@
modules: @json($moduleSettings ?? []), modules: @json($moduleSettings ?? []),
moduleAssets: @json($moduleAssets ?? []), moduleAssets: @json($moduleAssets ?? []),
pluginAssets: @json($pluginAssets ?? []), pluginAssets: @json($pluginAssets ?? []),
bundleUrls: @json($bundleUrls ?? null),
activeModules: @json($activeModulesMeta ?? []), activeModules: @json($activeModulesMeta ?? []),
activePlugins: @json($activePluginsMeta ?? []), activePlugins: @json($activePluginsMeta ?? []),
appConfig: @json($appConfig ?? []), appConfig: @json($appConfig ?? []),
+4
View File
@@ -870,6 +870,10 @@ if (isset($_GET['ajax_action'])) {
<span>레이아웃 미리보기 정리</span> <span>레이아웃 미리보기 정리</span>
<span class="text-[10px] opacity-60">(layout-previews:cleanup)</span> <span class="text-[10px] opacity-60">(layout-previews:cleanup)</span>
</button> </button>
<button onclick="runCommand('ext-bundles:cleanup')" class="inline-flex items-center gap-1.5 px-3 py-2 bg-amber-600 hover:bg-amber-700 text-white text-xs font-medium rounded transition-colors">
<span>확장 번들 정리</span>
<span class="text-[10px] opacity-60">(ext-bundles:cleanup)</span>
</button>
<button onclick="runCommand('geoip:update')" class="inline-flex items-center gap-1.5 px-3 py-2 bg-blue-600 hover:bg-blue-700 text-white text-xs font-medium rounded transition-colors"> <button onclick="runCommand('geoip:update')" class="inline-flex items-center gap-1.5 px-3 py-2 bg-blue-600 hover:bg-blue-700 text-white text-xs font-medium rounded transition-colors">
<span>GeoIP DB 갱신</span> <span>GeoIP DB 갱신</span>
<span class="text-[10px] opacity-60">(geoip:update)</span> <span class="text-[10px] opacity-60">(geoip:update)</span>
+12
View File
@@ -125,6 +125,12 @@ Route::group([], function () {
// 모듈 에셋 서빙 API // 모듈 에셋 서빙 API
Route::prefix('modules')->group(function () { Route::prefix('modules')->group(function () {
// 활성 모듈 프론트엔드 IIFE/CSS 병합 번들 (개별 assets 라우트보다 위에 명시 등록)
Route::get('bundle.js', [PublicModuleController::class, 'serveBundleJs'])
->name('api.public.modules.bundle.js');
Route::get('bundle.css', [PublicModuleController::class, 'serveBundleCss'])
->name('api.public.modules.bundle.css');
Route::get('assets/{identifier}/{path}', [PublicModuleController::class, 'serveAsset']) Route::get('assets/{identifier}/{path}', [PublicModuleController::class, 'serveAsset'])
->where('path', '.*') ->where('path', '.*')
->name('api.public.modules.assets'); ->name('api.public.modules.assets');
@@ -140,6 +146,12 @@ Route::group([], function () {
// 플러그인 에셋 서빙 API // 플러그인 에셋 서빙 API
Route::prefix('plugins')->group(function () { Route::prefix('plugins')->group(function () {
// 활성 플러그인 프론트엔드 IIFE/CSS 병합 번들 (개별 assets 라우트보다 위에 명시 등록)
Route::get('bundle.js', [PublicPluginController::class, 'serveBundleJs'])
->name('api.public.plugins.bundle.js');
Route::get('bundle.css', [PublicPluginController::class, 'serveBundleCss'])
->name('api.public.plugins.bundle.css');
Route::get('assets/{identifier}/{path}', [PublicPluginController::class, 'serveAsset']) Route::get('assets/{identifier}/{path}', [PublicPluginController::class, 'serveAsset'])
->where('path', '.*') ->where('path', '.*')
->name('api.public.plugins.assets'); ->name('api.public.plugins.assets');
@@ -0,0 +1,119 @@
<?php
namespace Tests\Feature\Api\Public;
use App\Services\ExtensionBundleService;
use Illuminate\Support\Facades\File;
use Mockery;
use Tests\TestCase;
/**
* 확장 프론트엔드 병합 번들 서빙 엔드포인트 Feature 테스트
*
* /api/{modules,plugins}/bundle.{js,css} 의 응답 계약(Content-Type, ETag,
* 304 Not Modified, 빈 번들 처리)을 검증한다. ExtensionBundleService 를
* 컨테이너에 mock 바인딩해 활성 확장 조합에 의존하지 않고 컨트롤러 결선을 검증한다.
*/
class ExtensionBundleServingTest extends TestCase
{
private string $fixtureDir;
protected function setUp(): void
{
parent::setUp();
$this->fixtureDir = storage_path('framework/testing/ext-bundle-serving');
File::ensureDirectoryExists($this->fixtureDir);
}
protected function tearDown(): void
{
if (is_dir($this->fixtureDir)) {
foreach (glob($this->fixtureDir.'/*') as $f) {
@unlink($f);
}
@rmdir($this->fixtureDir);
}
Mockery::close();
parent::tearDown();
}
/**
* ExtensionBundleService 를 지정 경로를 반환하도록 mock 바인딩한다.
*/
private function bindBundleService(string $returnPath): void
{
$mock = Mockery::mock(ExtensionBundleService::class);
$mock->shouldReceive('getCurrentVersion')->andReturn(777);
$mock->shouldReceive('getBundleFilePath')->andReturn($returnPath);
$this->app->instance(ExtensionBundleService::class, $mock);
}
public function test_module_bundle_js_serves_merged_file_with_etag(): void
{
$path = $this->fixtureDir.'/module.777.js';
File::put($path, "(function(){window.A=1})()\n;\n(function(){window.B=2})()");
$this->bindBundleService($path);
$response = $this->get('/api/modules/bundle.js?v=777');
$response->assertOk();
$this->assertStringStartsWith('text/javascript', $response->headers->get('Content-Type'));
$response->assertHeader('ETag');
$this->assertStringContainsString('window.A=1', $response->streamedContent() ?? $response->getContent());
$this->assertStringContainsString("\n;\n", $response->streamedContent() ?? $response->getContent());
}
public function test_bundle_returns_304_on_matching_etag(): void
{
$path = $this->fixtureDir.'/plugin.777.js';
File::put($path, '(function(){})()');
$this->bindBundleService($path);
$first = $this->get('/api/plugins/bundle.js?v=777');
$first->assertOk();
$etag = $first->headers->get('ETag');
$this->assertNotNull($etag);
$second = $this->get('/api/plugins/bundle.js?v=777', ['If-None-Match' => $etag]);
$second->assertStatus(304);
}
public function test_empty_bundle_returns_empty_ok_response(): void
{
// 활성 global 에셋이 없으면 서비스가 빈 경로 반환 → 컨트롤러 빈 200
$this->bindBundleService('');
$response = $this->get('/api/modules/bundle.js?v=777');
$response->assertOk();
$this->assertStringStartsWith('text/javascript', $response->headers->get('Content-Type'));
// 빈 번들은 일반 Response(스트림 아님) — getContent 로 빈 본문 확인
$this->assertSame('', $response->getContent());
}
public function test_module_bundle_css_serves_with_css_content_type(): void
{
$path = $this->fixtureDir.'/module.777.css';
File::put($path, '.a{color:red}');
$this->bindBundleService($path);
$response = $this->get('/api/modules/bundle.css?v=777');
$response->assertOk();
$this->assertStringStartsWith('text/css', $response->headers->get('Content-Type'));
}
public function test_bundle_routes_do_not_collide_with_asset_route(): void
{
// bundle.js 는 assets/{identifier}/{path} 로 매칭되면 안 됨 (정적 세그먼트 우선)
$path = $this->fixtureDir.'/module.777.js';
File::put($path, '(function(){window.BUNDLE=1})()');
$this->bindBundleService($path);
$response = $this->get('/api/modules/bundle.js?v=777');
$response->assertOk();
// 개별 에셋 서빙(serveAsset)이 아니라 번들 서빙(serveBundleJs)이 응답
$this->assertStringContainsString('window.BUNDLE=1', $response->streamedContent() ?? $response->getContent());
}
}
@@ -0,0 +1,78 @@
/**
* E2E: 확장 프론트엔드 병합 번들 로딩 회귀 검증
*
* @scenario extension-bundle-loading
* @effects bundle_js_requested_once_per_type, individual_iife_requests_absent,
* gdpr_interceptor_still_active, extension_handlers_registered
*
* 배경: 활성 모듈/플러그인 IIFE 를 서버측에서 종류별 1개 번들로 병합 서빙한다.
* 실제 페이지 로드 시 (1) 개별 `*.iife.js` 요청이 사라지고 `bundle.js` 로 대체되는지,
* (2) gdpr preblocker 가 여전히 유효한지(병합 후 race 회귀 없음), (3) 확장 자가등록
* (핸들러/레지스트리)이 정상 동작하는지 실측한다.
*/
import { test, expect } from '@playwright/test';
test.describe('확장 병합 번들 로딩', () => {
test('@smoke 홈페이지 로드 시 개별 iife 대신 병합 번들이 요청된다', async ({ page }) => {
const requestedUrls: string[] = [];
page.on('request', (req) => {
requestedUrls.push(req.url());
});
await page.goto('/');
await page.waitForLoadState('networkidle', { timeout: 30_000 });
const moduleBundle = requestedUrls.filter((u) => /\/api\/modules\/bundle\.js/.test(u));
const pluginBundle = requestedUrls.filter((u) => /\/api\/plugins\/bundle\.js/.test(u));
// 활성 확장이 있으면 번들이 요청되고, 종류별로 1건씩만 나가야 한다
const individualIife = requestedUrls.filter((u) => /\/api\/(modules|plugins)\/assets\/.*\.iife\.js/.test(u));
// 개별 iife 직접 요청은 0건 (번들로 대체)
expect(individualIife, `개별 iife 요청이 남아있음: ${individualIife.join(', ')}`).toHaveLength(0);
// 번들이 요청됐다면 종류별 최대 1건 (중복 가드)
expect(moduleBundle.length, '모듈 번들 중복 요청').toBeLessThanOrEqual(1);
expect(pluginBundle.length, '플러그인 번들 중복 요청').toBeLessThanOrEqual(1);
});
test('@smoke 병합 번들 응답이 정상(200/304)이고 same-origin 이다', async ({ page }) => {
const bundleResponses: { url: string; status: number }[] = [];
page.on('response', (res) => {
if (/\/api\/(modules|plugins)\/bundle\.(js|css)/.test(res.url())) {
bundleResponses.push({ url: res.url(), status: res.status() });
}
});
await page.goto('/');
await page.waitForLoadState('networkidle', { timeout: 30_000 });
for (const r of bundleResponses) {
expect([200, 304], `번들 응답 비정상: ${r.url} → ${r.status}`).toContain(r.status);
// same-origin (/api/...) — CDN/외부 origin 금지 (gdpr preblocker 자기차단 방지)
const origin = new URL(page.url()).origin;
expect(r.url.startsWith(origin), `번들 URL 이 same-origin 아님: ${r.url}`).toBe(true);
}
});
test('@smoke 확장 병합 로드 후 페이지가 정상 렌더된다 (자가등록 계약)', async ({ page }) => {
const consoleErrors: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') {
consoleErrors.push(msg.text());
}
});
await page.goto('/');
await page.waitForLoadState('networkidle', { timeout: 30_000 });
// 홈 네비게이션이 렌더되면 템플릿 엔진 + 확장 자가등록이 정상 작동한 것
await expect(page.getByTestId('nav-home')).toBeVisible({ timeout: 15_000 });
// 번들 파싱 에러(ASI 경계 붕괴)가 있으면 "Unexpected token" 등 콘솔 에러가 뜬다
const parseErrors = consoleErrors.filter((e) =>
/Unexpected token|SyntaxError|is not defined|Unknown action handler/i.test(e),
);
expect(parseErrors, `번들 실행 관련 콘솔 에러: ${parseErrors.join(' | ')}`).toHaveLength(0);
});
});
@@ -0,0 +1,307 @@
<?php
namespace Tests\Unit\Services;
use App\Extension\ModuleManager;
use App\Extension\PluginManager;
use App\Services\ExtensionBundleService;
use Illuminate\Support\Facades\File;
use Mockery;
use Tests\TestCase;
/**
* ExtensionBundleService 단위 테스트
*
* 활성 확장 IIFE/CSS 의 priority 정렬, `\n;\n` 구분자 병합, sourceMappingURL
* 처리, 확장별 fault tolerance, 캐시 파일 생성/정리를 검증한다.
*/
class ExtensionBundleServiceTest extends TestCase
{
private string $fixtureDir;
private ModuleManager $moduleManager;
private PluginManager $pluginManager;
protected function setUp(): void
{
parent::setUp();
$this->fixtureDir = storage_path('framework/testing/ext-bundle-fixtures');
File::ensureDirectoryExists($this->fixtureDir);
$this->moduleManager = Mockery::mock(ModuleManager::class);
$this->pluginManager = Mockery::mock(PluginManager::class);
// 번들 캐시 디렉토리 초기화 (테스트 격리)
$bundleDir = storage_path('app/ext-bundles');
if (is_dir($bundleDir)) {
foreach (glob($bundleDir.'/*.{js,css}', GLOB_BRACE) as $f) {
@unlink($f);
}
}
}
protected function tearDown(): void
{
if (is_dir($this->fixtureDir)) {
foreach (glob($this->fixtureDir.'/*') as $f) {
@unlink($f);
}
@rmdir($this->fixtureDir);
}
$bundleDir = storage_path('app/ext-bundles');
if (is_dir($bundleDir)) {
foreach (glob($bundleDir.'/*.{js,css}', GLOB_BRACE) as $f) {
@unlink($f);
}
}
Mockery::close();
parent::tearDown();
}
/**
* 지정 내용으로 fixture 에셋 파일을 만들고 절대 경로를 반환한다.
*/
private function writeFixture(string $name, string $content): string
{
$path = $this->fixtureDir.'/'.$name;
File::put($path, $content);
return $path;
}
/**
* hasAssets/getAssetLoadingConfig/getBuiltAssetAbsolutePaths/getIdentifier 를
* 노출하는 가짜 확장 인스턴스를 만든다.
*/
private function fakeExtension(string $identifier, int $priority, ?string $jsPath, ?string $cssPath, string $strategy = 'global'): object
{
$ext = Mockery::mock();
$ext->shouldReceive('hasAssets')->andReturn(true);
$ext->shouldReceive('getIdentifier')->andReturn($identifier);
$ext->shouldReceive('getAssetLoadingConfig')->andReturn([
'strategy' => $strategy,
'priority' => $priority,
'dependencies' => [],
]);
$paths = [];
if ($jsPath !== null) {
$paths['js'] = $jsPath;
}
if ($cssPath !== null) {
$paths['css'] = $cssPath;
}
$ext->shouldReceive('getBuiltAssetAbsolutePaths')->andReturn($paths);
return $ext;
}
private function service(): ExtensionBundleService
{
return new ExtensionBundleService($this->moduleManager, $this->pluginManager);
}
public function test_orders_global_assets_by_priority_ascending(): void
{
$a = $this->writeFixture('a.js', '(function(){})()');
$b = $this->writeFixture('b.js', '(function(){})()');
$c = $this->writeFixture('c.js', '(function(){})()');
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-c' => $this->fakeExtension('ext-c', 30, $c, null),
'ext-a' => $this->fakeExtension('ext-a', 10, $a, null),
'ext-b' => $this->fakeExtension('ext-b', 20, $b, null),
]);
$ordered = $this->service()->getOrderedGlobalAssetPaths('module');
$this->assertSame(['ext-a', 'ext-b', 'ext-c'], array_keys($ordered));
}
public function test_skips_non_global_strategy(): void
{
$g = $this->writeFixture('g.js', '(function(){})()');
$l = $this->writeFixture('l.js', '(function(){})()');
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-global' => $this->fakeExtension('ext-global', 100, $g, null, 'global'),
'ext-layout' => $this->fakeExtension('ext-layout', 100, $l, null, 'layout'),
]);
$ordered = $this->service()->getOrderedGlobalAssetPaths('module');
$this->assertArrayHasKey('ext-global', $ordered);
$this->assertArrayNotHasKey('ext-layout', $ordered);
}
public function test_js_bundle_joins_iife_with_semicolon_newline_separator(): void
{
// 세미콜론 없이 끝나는 IIFE 2개 (ecommerce 형태)
$a = $this->writeFixture('a.js', '(function(){window.A=1})()');
$b = $this->writeFixture('b.js', '(function(){window.B=2})()');
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-a' => $this->fakeExtension('ext-a', 10, $a, null),
'ext-b' => $this->fakeExtension('ext-b', 20, $b, null),
]);
$js = $this->service()->buildJsBundle('module');
// 두 IIFE 가 모두 포함되고 `\n;\n` 구분자로 구분
$this->assertStringContainsString('window.A=1', $js);
$this->assertStringContainsString('window.B=2', $js);
$this->assertStringContainsString("\n;\n", $js);
// priority 순서 (a 가 b 보다 먼저)
$this->assertLessThan(strpos($js, 'window.B=2'), strpos($js, 'window.A=1'));
}
public function test_prod_strips_source_mapping_url(): void
{
$this->app['env'] = 'production';
app()->detectEnvironment(fn () => 'production');
$a = $this->writeFixture('a.js', "(function(){})()\n//# sourceMappingURL=a.js.map");
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-a' => $this->fakeExtension('ext-a', 10, $a, null),
]);
$js = $this->service()->buildJsBundle('module');
$this->assertStringNotContainsString('sourceMappingURL', $js);
}
public function test_dev_rewrites_source_mapping_url_to_asset_serving_path(): void
{
// 기본 testing 환경 = 비프로덕션 → dev rewrite 경로
$a = $this->writeFixture('a.js', "(function(){})()\n//# sourceMappingURL=a.js.map");
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-a' => $this->fakeExtension('ext-a', 10, $a, null),
]);
$js = $this->service()->buildJsBundle('module');
$this->assertStringContainsString('sourceMappingURL=/api/modules/assets/ext-a/dist/js/a.js.map', $js);
}
public function test_per_extension_fault_tolerance_skips_missing_file(): void
{
$good = $this->writeFixture('good.js', '(function(){window.GOOD=1})()');
$missing = $this->fixtureDir.'/does-not-exist.js';
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-missing' => $this->fakeExtension('ext-missing', 10, $missing, null),
'ext-good' => $this->fakeExtension('ext-good', 20, $good, null),
]);
$js = $this->service()->buildJsBundle('module');
// 없는 파일은 skip, 정상 확장은 여전히 포함 (번들 전체 붕괴 안 함)
$this->assertStringContainsString('window.GOOD=1', $js);
}
public function test_css_with_relative_url_is_excluded(): void
{
$safe = $this->writeFixture('safe.css', '.a{color:red}');
$relative = $this->writeFixture('rel.css', '.b{background:url(./img/x.png)}');
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-safe' => $this->fakeExtension('ext-safe', 10, null, $safe),
'ext-rel' => $this->fakeExtension('ext-rel', 20, null, $relative),
]);
$css = $this->service()->buildCssBundle('module');
$this->assertStringContainsString('.a{color:red}', $css);
$this->assertStringNotContainsString('url(./img/x.png)', $css);
}
public function test_empty_bundle_returns_empty_path(): void
{
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([]);
$path = $this->service()->getBundleFilePath('module', 'js', 12345);
$this->assertSame('', $path);
}
public function test_prod_writes_versioned_cache_file_and_reuses_it(): void
{
$this->app['env'] = 'production';
app()->detectEnvironment(fn () => 'production');
$a = $this->writeFixture('a.js', '(function(){window.A=1})()');
// getActiveModules 는 두 번 호출될 수 있으므로 안정적으로 반환
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([
'ext-a' => $this->fakeExtension('ext-a', 10, $a, null),
]);
$svc = $this->service();
$path1 = $svc->getBundleFilePath('module', 'js', 999);
$this->assertNotSame('', $path1);
$this->assertFileExists($path1);
$this->assertStringContainsString('module.999.js', $path1);
// 같은 version 재요청 → 동일 파일 (캐시 히트)
$path2 = $svc->getBundleFilePath('module', 'js', 999);
$this->assertSame($path1, $path2);
}
public function test_cleanup_removes_stale_version_bundles_only(): void
{
$bundleDir = storage_path('app/ext-bundles');
File::ensureDirectoryExists($bundleDir);
File::put($bundleDir.'/module.100.js', 'old');
File::put($bundleDir.'/module.200.js', 'current');
File::put($bundleDir.'/plugin.100.css', 'old');
$this->moduleManager->shouldReceive('getActiveModules')->andReturn([]);
$deleted = $this->service()->cleanupStaleBundles(200);
// version 200 외 파일만 삭제 (module.100.js, plugin.100.css = 2건)
$this->assertSame(2, $deleted);
$this->assertFileExists($bundleDir.'/module.200.js');
$this->assertFileDoesNotExist($bundleDir.'/module.100.js');
$this->assertFileDoesNotExist($bundleDir.'/plugin.100.css');
}
public function test_clear_bundles_by_type(): void
{
$bundleDir = storage_path('app/ext-bundles');
File::ensureDirectoryExists($bundleDir);
File::put($bundleDir.'/module.100.js', 'm');
File::put($bundleDir.'/plugin.100.js', 'p');
$deleted = $this->service()->clearBundles('module');
$this->assertSame(1, $deleted);
$this->assertFileDoesNotExist($bundleDir.'/module.100.js');
$this->assertFileExists($bundleDir.'/plugin.100.js');
}
public function test_plugin_bundle_orders_by_priority_gdpr_first_when_lowest(): void
{
// gdpr 가 priority 50 으로 최상단(제약 1 회귀 가드) — 이름 하드코딩 아닌 선언 결과
$gdpr = $this->writeFixture('gdpr.js', '(function(){window.GDPR=1})()');
$other = $this->writeFixture('other.js', '(function(){window.OTHER=1})()');
$this->pluginManager->shouldReceive('getActivePlugins')->andReturn([
'sirsoft-other' => $this->fakeExtension('sirsoft-other', 100, $other, null),
'sirsoft-gdpr' => $this->fakeExtension('sirsoft-gdpr', 50, $gdpr, null),
]);
$ordered = $this->service()->getOrderedGlobalAssetPaths('plugin');
$this->assertSame('sirsoft-gdpr', array_key_first($ordered));
$js = $this->service()->buildJsBundle('plugin');
$this->assertLessThan(strpos($js, 'window.OTHER=1'), strpos($js, 'window.GDPR=1'));
}
}
@@ -0,0 +1,71 @@
# audit:allow test-scenario-coverage reason: 서버측 확장 번들 병합 도입 회귀 가드. 입력 axis(활성 조합·환경·에셋 종류)의 cross-product 는 test_files 의 Unit/Feature 가 cover 하고, effects 는 병합 계약(순서/구분자/소스맵/캐시/폴백)과 브라우저 실측(요청수/gdpr race)을 enumerate.
feature: 확장(모듈/플러그인) 프론트엔드 IIFE/CSS 서버측 번들 병합
description: |
활성 모듈/플러그인의 global 전략 프론트엔드 에셋을 타입별로 하나의 번들로
서버에서 병합해 서빙, 확장 수에 비례하던 HTTP 요청을 종류별 1건으로 줄인다.
각 확장 IIFE 자가등록 계약은 유지(priority 순 물리 병합 = 실행 순서).
핵심 동작:
- ExtensionBundleService 가 getOrderedGlobalAssetPaths(uasort priority) →
buildJsBundle(`\n;\n` join, sourceMappingURL 처리) → getBundleFilePath(캐시)
- PublicModule/PluginController::serveBundle{Js,Css} → fileResponse(ETag/304)
- blade bundleUrls → ModuleAssetLoader.loadBundle(module) → loadBundle(plugin)
- 확장 캐시 버전 bump 시 새 파일명 자동 무효화, ext-bundles:cleanup GC
- bundleUrls 부재 시 개별 로딩 폴백(회귀 안전)
axes:
ext_type: [module, plugin]
asset_kind: [js, css, both]
active_combo: [none, one, multiple]
strategy: [global, layout, lazy]
environment: [production, non_production]
version_state: [first_request, cache_hit, version_bumped]
source_map_state: [present, absent]
css_url_state: [no_url, absolute_url, relative_url]
file_state: [all_present, one_missing]
priority_order: [ascending, gdpr_lowest]
bundle_urls_present: [present, absent_fallback]
exclusions:
- { strategy: layout, active_combo: none, reason: "layout/lazy 전략은 번들 대상 아님 — 개별 레이아웃 처리" }
- { active_combo: none, version_state: cache_hit, reason: "활성 에셋 0건이면 캐시 파일을 만들지 않음 (빈 경로)" }
effects:
- ordered_by_priority_ascending_only_no_name_hardcode
- non_global_strategy_excluded_from_bundle
- js_iife_joined_with_semicolon_newline_separator
- prod_strips_source_mapping_url
- dev_rewrites_source_mapping_url_to_asset_serving_path
- per_extension_fault_tolerance_skips_missing_file_keeps_rest
- css_with_relative_url_excluded_from_bundle
- empty_bundle_returns_empty_path_and_empty_ok_response
- prod_writes_versioned_cache_file_and_reuses_on_same_version
- non_production_rebuilds_every_request_no_disk_cache
- cleanup_removes_stale_version_bundles_only
- clear_bundles_by_type_scopes_to_prefix
- plugin_bundle_gdpr_first_when_priority_lowest
- bundle_endpoint_serves_with_etag_and_304
- bundle_url_same_origin_only
- loadbundle_single_script_single_link_append
- loadbundle_dedup_guard_no_double_load
- loadbundle_null_urls_noop
- concat_iife_self_registration_preserved
- missing_bundle_urls_falls_back_to_individual_loading
- individual_iife_requests_absent_in_browser
- gdpr_interceptor_still_active_after_merge
- extension_handlers_registered_no_console_error
test_files:
- tests/Unit/Services/ExtensionBundleServiceTest.php
- tests/Feature/Api/Public/ExtensionBundleServingTest.php
- resources/js/core/modules/__tests__/ModuleAssetLoader.test.ts
- tests/Playwright/specs/extension-bundle-loading.spec.ts
validation:
audit_rules:
- extension-bundle-url-same-origin
- extension-bundle-concat-separator
- extension-bundle-asset-path-getter
- clears-template-caches-no-file-delete