forked from baron/baron-sso
[WIP]모바일 로그인창 테스트 강화중
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -37,6 +37,7 @@ Map<String, dynamic> _normalizeFlatTranslations(Map<String, String> flatMap) =>
|
|||||||
|
|
||||||
bool _isUserfrontTranslationKey(String key) {
|
bool _isUserfrontTranslationKey(String key) {
|
||||||
return key.startsWith('domain.') ||
|
return key.startsWith('domain.') ||
|
||||||
|
key.startsWith('err.userfront.') ||
|
||||||
key.startsWith('msg.userfront.') ||
|
key.startsWith('msg.userfront.') ||
|
||||||
key.startsWith('ui.userfront.') ||
|
key.startsWith('ui.userfront.') ||
|
||||||
key.startsWith('ui.common.');
|
key.startsWith('ui.common.');
|
||||||
|
|||||||
@@ -52,14 +52,11 @@ class LogPolicy {
|
|||||||
required String? appEnv,
|
required String? appEnv,
|
||||||
required String? productionDebugFlag,
|
required String? productionDebugFlag,
|
||||||
}) {
|
}) {
|
||||||
final flag = parseOptionalBoolFlag(productionDebugFlag);
|
|
||||||
if (flag.specified) {
|
|
||||||
return flag.enabled;
|
|
||||||
}
|
|
||||||
if (!isProductionEnv(appEnv)) {
|
if (!isProductionEnv(appEnv)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
final flag = parseOptionalBoolFlag(productionDebugFlag);
|
||||||
|
return flag.specified && flag.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool shouldRelayClientLog({
|
static bool shouldRelayClientLog({
|
||||||
@@ -67,10 +64,12 @@ class LogPolicy {
|
|||||||
required String? appEnv,
|
required String? appEnv,
|
||||||
required String? productionDebugFlag,
|
required String? productionDebugFlag,
|
||||||
}) {
|
}) {
|
||||||
if (debugEnabled(
|
final flag = parseOptionalBoolFlag(productionDebugFlag);
|
||||||
appEnv: appEnv,
|
final debugRelayEnabled = isProductionEnv(appEnv)
|
||||||
productionDebugFlag: productionDebugFlag,
|
? flag.specified && flag.enabled
|
||||||
)) {
|
: !(flag.specified && !flag.enabled);
|
||||||
|
|
||||||
|
if (debugRelayEnabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
final normalized = level.trim().toUpperCase();
|
final normalized = level.trim().toUpperCase();
|
||||||
|
|||||||
@@ -5,16 +5,98 @@ cd /workspace
|
|||||||
/bin/sh ./scripts/sync_userfront_locales.sh
|
/bin/sh ./scripts/sync_userfront_locales.sh
|
||||||
|
|
||||||
cd /workspace/userfront
|
cd /workspace/userfront
|
||||||
|
USERFRONT_INTERNAL_PORT="${USERFRONT_INTERNAL_PORT:-5000}"
|
||||||
|
USERFRONT_FLUTTER_RUN_FLAGS="${USERFRONT_FLUTTER_RUN_FLAGS:---debug}"
|
||||||
|
USERFRONT_BOOT_WARMUP_ATTEMPTS="${USERFRONT_BOOT_WARMUP_ATTEMPTS:-120}"
|
||||||
|
USERFRONT_BOOT_WARMUP_INTERVAL_SECONDS="${USERFRONT_BOOT_WARMUP_INTERVAL_SECONDS:-0.5}"
|
||||||
|
USERFRONT_BOOT_WARMUP_LOCALES="${USERFRONT_BOOT_WARMUP_LOCALES:-ko en}"
|
||||||
|
USERFRONT_BOOT_WARMUP_VIEWPORTS="${USERFRONT_BOOT_WARMUP_VIEWPORTS:-mobile:390 desktop:1440}"
|
||||||
|
|
||||||
|
warm_get() {
|
||||||
|
path="$1"
|
||||||
|
locale="$2"
|
||||||
|
viewport="$3"
|
||||||
|
width="${viewport#*:}"
|
||||||
|
if [ "$width" = "$viewport" ]; then
|
||||||
|
width=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
wget -qO- \
|
||||||
|
--header="Accept-Language: $locale" \
|
||||||
|
--header="Viewport-Width: $width" \
|
||||||
|
"http://127.0.0.1:${USERFRONT_INTERNAL_PORT}${path}" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
warm_userfront_once() {
|
||||||
|
flutter_pid="$1"
|
||||||
|
attempt=1
|
||||||
|
started_at="$(date +%s)"
|
||||||
|
|
||||||
|
while [ "$attempt" -le "$USERFRONT_BOOT_WARMUP_ATTEMPTS" ]; do
|
||||||
|
if wget -qO- "http://127.0.0.1:${USERFRONT_INTERNAL_PORT}/flutter_bootstrap.js" >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if ! kill -0 "$flutter_pid" 2>/dev/null; then
|
||||||
|
echo "[userfront-boot] warmup skipped because flutter exited before readiness" >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
sleep "$USERFRONT_BOOT_WARMUP_INTERVAL_SECONDS"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$attempt" -gt "$USERFRONT_BOOT_WARMUP_ATTEMPTS" ]; then
|
||||||
|
echo "[userfront-boot] warmup skipped after ${USERFRONT_BOOT_WARMUP_ATTEMPTS} readiness attempts" >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[userfront-boot] one-shot warmup starting locales=\"${USERFRONT_BOOT_WARMUP_LOCALES}\" viewports=\"${USERFRONT_BOOT_WARMUP_VIEWPORTS}\"" >&2
|
||||||
|
|
||||||
|
for locale in $USERFRONT_BOOT_WARMUP_LOCALES; do
|
||||||
|
for viewport in $USERFRONT_BOOT_WARMUP_VIEWPORTS; do
|
||||||
|
warm_get "/${locale}/signin" "$locale" "$viewport" || true
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
for asset in \
|
||||||
|
/ \
|
||||||
|
/flutter_bootstrap.js \
|
||||||
|
/main.dart.mjs \
|
||||||
|
/main.dart.wasm \
|
||||||
|
/canvaskit/skwasm.js \
|
||||||
|
/canvaskit/skwasm.wasm \
|
||||||
|
/canvaskit/skwasm_heavy.js \
|
||||||
|
/canvaskit/skwasm_heavy.wasm \
|
||||||
|
/assets/AssetManifest.bin.json \
|
||||||
|
/assets/FontManifest.json
|
||||||
|
do
|
||||||
|
wget -qO- "http://127.0.0.1:${USERFRONT_INTERNAL_PORT}${asset}" >/dev/null 2>&1 || true
|
||||||
|
done
|
||||||
|
|
||||||
|
finished_at="$(date +%s)"
|
||||||
|
elapsed_seconds=$((finished_at - started_at))
|
||||||
|
echo "[userfront-boot] one-shot warmup completed in ${elapsed_seconds}s" >&2
|
||||||
|
}
|
||||||
|
|
||||||
set -- flutter run \
|
set -- flutter run \
|
||||||
-d web-server \
|
-d web-server \
|
||||||
--web-hostname 0.0.0.0 \
|
--web-hostname 0.0.0.0 \
|
||||||
--web-port "${USERFRONT_INTERNAL_PORT:-5000}" \
|
--web-port "${USERFRONT_INTERNAL_PORT}" \
|
||||||
--wasm \
|
--wasm \
|
||||||
--dart-define=BACKEND_URL="${BACKEND_URL:-}" \
|
--dart-define=BACKEND_URL="${BACKEND_URL:-}" \
|
||||||
--dart-define=CLIENT_LOG_DEBUG="${CLIENT_LOG_DEBUG:-false}" \
|
--dart-define=CLIENT_LOG_DEBUG="${CLIENT_LOG_DEBUG:-false}" \
|
||||||
--dart-define=APP_ENV="${APP_ENV:-dev}" \
|
--dart-define=APP_ENV="${APP_ENV:-dev}" \
|
||||||
--dart-define=USERFRONT_URL="${USERFRONT_URL:-}" \
|
--dart-define=USERFRONT_URL="${USERFRONT_URL:-}" \
|
||||||
${USERFRONT_FLUTTER_RUN_FLAGS:-} \
|
${USERFRONT_FLUTTER_RUN_FLAGS} \
|
||||||
--no-web-resources-cdn
|
--no-web-resources-cdn
|
||||||
|
|
||||||
exec "$@"
|
"$@" &
|
||||||
|
flutter_pid="$!"
|
||||||
|
|
||||||
|
terminate() {
|
||||||
|
kill "$flutter_pid" 2>/dev/null || true
|
||||||
|
wait "$flutter_pid" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
trap terminate INT TERM
|
||||||
|
warm_userfront_once "$flutter_pid"
|
||||||
|
wait "$flutter_pid"
|
||||||
|
|||||||
@@ -78,15 +78,18 @@ const canvasKitConfig = 'config:{canvasKitBaseUrl:"canvaskit/"}';
|
|||||||
|
|
||||||
bootstrap = bootstrap.replace(
|
bootstrap = bootstrap.replace(
|
||||||
/_flutter\.loader\.load\(\{\s*serviceWorkerSettings:\s*(\{[^{}]*\})\s*,\s*config:\s*\{[\s\S]*?serviceWorkerUrl[\s\S]*?\}\s*,\s*config:\s*\{[^}]*\}\s*\}\);/g,
|
/_flutter\.loader\.load\(\{\s*serviceWorkerSettings:\s*(\{[^{}]*\})\s*,\s*config:\s*\{[\s\S]*?serviceWorkerUrl[\s\S]*?\}\s*,\s*config:\s*\{[^}]*\}\s*\}\);/g,
|
||||||
`_flutter.loader.load({${canvasKitConfig}});`,
|
(_match, settings) =>
|
||||||
|
`_flutter.loader.load({serviceWorkerSettings:${ensureServiceWorkerUrl(settings)},${canvasKitConfig}});`,
|
||||||
);
|
);
|
||||||
bootstrap = bootstrap.replace(
|
bootstrap = bootstrap.replace(
|
||||||
/_flutter\.loader\.load\(\{\s*serviceWorkerSettings:\s*(\{[^{}]*\})\s*,\s*config:\s*\{[^}]*\}\s*\}\);/g,
|
/_flutter\.loader\.load\(\{\s*serviceWorkerSettings:\s*(\{[^{}]*\})\s*,\s*config:\s*\{[^}]*\}\s*\}\);/g,
|
||||||
`_flutter.loader.load({${canvasKitConfig}});`,
|
(_match, settings) =>
|
||||||
|
`_flutter.loader.load({serviceWorkerSettings:${ensureServiceWorkerUrl(settings)},${canvasKitConfig}});`,
|
||||||
);
|
);
|
||||||
bootstrap = bootstrap.replace(
|
bootstrap = bootstrap.replace(
|
||||||
/_flutter\.loader\.load\(\{\s*serviceWorkerSettings:\s*(\{[^{}]*\})\s*\}\);/g,
|
/_flutter\.loader\.load\(\{\s*serviceWorkerSettings:\s*(\{[^{}]*\})\s*\}\);/g,
|
||||||
`_flutter.loader.load({${canvasKitConfig}});`,
|
(_match, settings) =>
|
||||||
|
`_flutter.loader.load({serviceWorkerSettings:${ensureServiceWorkerUrl(settings)},${canvasKitConfig}});`,
|
||||||
);
|
);
|
||||||
bootstrap = bootstrap.replace(
|
bootstrap = bootstrap.replace(
|
||||||
/_flutter\.loader\.load\(\);/g,
|
/_flutter\.loader\.load\(\);/g,
|
||||||
@@ -302,4 +305,34 @@ async function cacheFirst(request) {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureServiceWorkerUrl(settings) {
|
||||||
|
const serviceWorkerUrl = `"/flutter_service_worker.js?v=" + ${serviceWorkerVersionExpression(settings)}`;
|
||||||
|
if (/serviceWorkerUrl\s*:/.test(settings)) {
|
||||||
|
return settings.replace(
|
||||||
|
/serviceWorkerUrl\s*:\s*[^,\n}]+,?/,
|
||||||
|
`serviceWorkerUrl: ${serviceWorkerUrl},`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const closingBraceIndex = settings.lastIndexOf('}');
|
||||||
|
if (closingBraceIndex < 0) {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
const beforeClosing = settings.slice(0, closingBraceIndex).trimEnd();
|
||||||
|
const afterClosing = settings.slice(closingBraceIndex);
|
||||||
|
const separator =
|
||||||
|
beforeClosing.endsWith('{') || beforeClosing.endsWith(',') ? '' : ',';
|
||||||
|
return `${beforeClosing}${separator}
|
||||||
|
serviceWorkerUrl: ${serviceWorkerUrl},
|
||||||
|
${afterClosing}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function serviceWorkerVersionExpression(settings) {
|
||||||
|
const match = settings.match(/serviceWorkerVersion\s*:\s*([^,\n}]+)/);
|
||||||
|
return (
|
||||||
|
match?.[1]?.replace(/\/\*[\s\S]*?\*\//g, '').trim() ??
|
||||||
|
'serviceWorkerVersion'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`[userfront] optimized ${basename(buildDir)} with hashed entrypoints and brotli assets`);
|
console.log(`[userfront] optimized ${basename(buildDir)} with hashed entrypoints and brotli assets`);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('explicit debug flag applies in development-like environment', () {
|
test('explicit true enables debug in development-like environment', () {
|
||||||
expect(
|
expect(
|
||||||
LogPolicy.debugEnabled(appEnv: 'dev', productionDebugFlag: 'true'),
|
LogPolicy.debugEnabled(appEnv: 'dev', productionDebugFlag: 'true'),
|
||||||
isTrue,
|
isTrue,
|
||||||
@@ -23,13 +23,16 @@ void main() {
|
|||||||
LogPolicy.debugEnabled(appEnv: 'development', productionDebugFlag: '1'),
|
LogPolicy.debugEnabled(appEnv: 'development', productionDebugFlag: '1'),
|
||||||
isTrue,
|
isTrue,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('explicit false does not suppress local debug in development', () {
|
||||||
expect(
|
expect(
|
||||||
LogPolicy.debugEnabled(appEnv: 'dev', productionDebugFlag: 'false'),
|
LogPolicy.debugEnabled(appEnv: 'dev', productionDebugFlag: 'false'),
|
||||||
isFalse,
|
isTrue,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
LogPolicy.debugEnabled(appEnv: 'development', productionDebugFlag: '0'),
|
LogPolicy.debugEnabled(appEnv: 'development', productionDebugFlag: '0'),
|
||||||
isFalse,
|
isTrue,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ void main() {
|
|||||||
|
|
||||||
expect(translations['ui.admin.nav.api_keys'], isNull);
|
expect(translations['ui.admin.nav.api_keys'], isNull);
|
||||||
expect(translations['ui.dev.console_title'], isNull);
|
expect(translations['ui.dev.console_title'], isNull);
|
||||||
|
expect(
|
||||||
|
translations['err.userfront.auth_proxy.login_failed'],
|
||||||
|
'Login failed.',
|
||||||
|
);
|
||||||
expect(translations['ui.userfront.login.action.submit'], 'Sign in');
|
expect(translations['ui.userfront.login.action.submit'], 'Sign in');
|
||||||
expect(translations['ui.common.theme_light'], 'Light');
|
expect(translations['ui.common.theme_light'], 'Light');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -122,7 +122,7 @@
|
|||||||
</main>
|
</main>
|
||||||
<script>
|
<script>
|
||||||
var baronBootstrapStartedAt = performance.now();
|
var baronBootstrapStartedAt = performance.now();
|
||||||
var baronMinimumShellMs = 1100;
|
var baronMinimumShellMs = 0;
|
||||||
window.addEventListener("flutter-first-frame", function () {
|
window.addEventListener("flutter-first-frame", function () {
|
||||||
var elapsedMs = performance.now() - baronBootstrapStartedAt;
|
var elapsedMs = performance.now() - baronBootstrapStartedAt;
|
||||||
window.setTimeout(
|
window.setTimeout(
|
||||||
@@ -136,6 +136,63 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script src="flutter_bootstrap.js" async></script>
|
<script>
|
||||||
|
(function () {
|
||||||
|
function loadFlutter() {
|
||||||
|
var script = document.createElement("script");
|
||||||
|
script.src = "flutter_bootstrap.js";
|
||||||
|
script.async = true;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
var hostname = window.location.hostname;
|
||||||
|
var isLocalhost =
|
||||||
|
hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
|
||||||
|
if (!isLocalhost || !("serviceWorker" in navigator)) {
|
||||||
|
loadFlutter();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.serviceWorker
|
||||||
|
.getRegistrations()
|
||||||
|
.then(function (registrations) {
|
||||||
|
return Promise.all(
|
||||||
|
registrations.map(function (registration) {
|
||||||
|
return registration.unregister();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
if (!window.caches) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return caches.keys().then(function (keys) {
|
||||||
|
return Promise.all(
|
||||||
|
keys
|
||||||
|
.filter(function (key) {
|
||||||
|
return (
|
||||||
|
key.indexOf("baron-userfront-") === 0 ||
|
||||||
|
key.indexOf("flutter-app-cache") === 0
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.map(function (key) {
|
||||||
|
return caches.delete(key);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
window.location.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadFlutter();
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.warn("[baron] failed to clear local service worker", error);
|
||||||
|
loadFlutter();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user