mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-28 07:37:56 +09:00
SDK 1.2.0 -> 1.3.0 (additive). Auditing the extension surface for plan 79 found the localization gap I expected and two pre-existing bugs I did not. The gap: extensions had no way to translate anything. The SDK now re-exports the HOST's translation surface -- useTranslation, Trans, t, useLocale, useLabel, useFormat and the intl door -- and i18next/react-i18next join the shared vendor singletons. That sharing is the load-bearing part: an extension bundling its own i18next would get a separate, uninitialised instance, so every t() in it would render its English default forever and nothing would report it. Exactly the "two React copies" hazard vendorShare already documents, and exactly the failure mode this plan hit twice in core. They also join dedupe/optimizeDeps for the same reason React is there. The bugs, both caused by the same duplication: - The import map listed `react` and `react-router-dom`, but no shim existed for either. A runtime extension importing bare `react` 404'd at load. - The serverkit-sdk shim re-exported 26 of the SDK's 71 exports. An extension importing Button, Modal, EmptyState, formatBytes or timeAgo from the SDK got `undefined`. The shim's own comment claimed parity was "asserted by the frontend build + backend test_sdk_contract"; nothing asserted it. Three files independently restated the same module list -- the import map, the namespace capture, and one hand-written shim per module -- so they drifted. Now vendorManifest.js is the list, generate-vendor-shims.mjs derives every shim's exports (from the real package's namespace, or from the SDK entry's own export statements -- never typed by hand), the import map is built from the same manifest, and `--check` fails the build on drift. 26 -> 85 exports on the SDK shim, 6 -> 8 shims, all present. Manifest contributions gain an optional `labelKey` beside `label` for nav, tabs and command-palette entries, resolved at render by the same translateLabel core uses -- data cannot call t(), and a label resolved at import would translate once and never follow a switch. Omitting it renders `label` verbatim, which is what every existing extension does, so nothing breaks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
85 lines
3.6 KiB
JSON
85 lines
3.6 KiB
JSON
{
|
|
"name": "serverkit-frontend",
|
|
"private": true,
|
|
"version": "0.1.0",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "vite build",
|
|
"test": "node --test",
|
|
"lint": "eslint . && node scripts/check-settings-index.mjs && node scripts/check-theme-tokens.mjs && node scripts/check-frontend-boundaries.mjs && node scripts/check-style-ownership.mjs && node scripts/check-status-one-door.mjs && node scripts/check-status-scss.mjs && node scripts/check-i18n-literals.mjs && node scripts/check-intl-door.mjs && node scripts/extract-i18n.mjs --check && node scripts/check-i18n.mjs && node scripts/check-logical-properties.mjs && node scripts/generate-vendor-shims.mjs --check && node ../scripts/check-html-sinks.mjs",
|
|
"lint:settings-index": "node scripts/check-settings-index.mjs",
|
|
"lint:status": "node scripts/check-status-one-door.mjs",
|
|
"lint:i18n": "node scripts/check-i18n-literals.mjs",
|
|
"lint:intl": "node scripts/check-intl-door.mjs",
|
|
"lint:locales": "node scripts/check-i18n.mjs",
|
|
"lint:logical": "node scripts/check-logical-properties.mjs",
|
|
"lint:vendor-shims": "node scripts/generate-vendor-shims.mjs --check",
|
|
"vendor:shims": "node scripts/generate-vendor-shims.mjs",
|
|
"i18n:extract": "node scripts/extract-i18n.mjs",
|
|
"lint:html-sinks": "node ../scripts/check-html-sinks.mjs",
|
|
"lint:frontend-boundaries": "node scripts/check-frontend-boundaries.mjs",
|
|
"capture:skeletons": "node scripts/capture-skeletons.mjs",
|
|
"preview": "vite preview"
|
|
},
|
|
"optionalDependencies": {
|
|
"@rollup/rollup-win32-x64-msvc": "^4.62.2"
|
|
},
|
|
"dependencies": {
|
|
"@radix-ui/react-accordion": "^1.2.12",
|
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
"@radix-ui/react-avatar": "^1.1.11",
|
|
"@radix-ui/react-checkbox": "^1.3.3",
|
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
"@radix-ui/react-label": "^2.1.8",
|
|
"@radix-ui/react-popover": "^1.1.15",
|
|
"@radix-ui/react-progress": "^1.1.8",
|
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
"@radix-ui/react-select": "^2.2.6",
|
|
"@radix-ui/react-separator": "^1.1.8",
|
|
"@radix-ui/react-slot": "^1.2.4",
|
|
"@radix-ui/react-switch": "^1.2.6",
|
|
"@radix-ui/react-tabs": "^1.1.13",
|
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
"@xterm/addon-fit": "^0.10.0",
|
|
"@xterm/addon-web-links": "^0.11.0",
|
|
"@xterm/xterm": "^5.5.0",
|
|
"@xyflow/react": "^12.10.0",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"cmdk": "^1.1.1",
|
|
"i18next": "^26.3.6",
|
|
"lucide-react": "^0.363.0",
|
|
"react": "^18.3.1",
|
|
"react-dom": "^18.3.1",
|
|
"react-i18next": "^17.0.11",
|
|
"react-icons": "^5.6.0",
|
|
"react-router-dom": "^7.18.1",
|
|
"recharts": "^2.12.3",
|
|
"socket.io-client": "^4.7.2",
|
|
"sonner": "^2.0.7"
|
|
},
|
|
"devDependencies": {
|
|
"@types/react": "^18.3.3",
|
|
"@types/react-dom": "^18.3.0",
|
|
"@vitejs/plugin-react": "^6.0.3",
|
|
"boneyard-js": "^1.9.0",
|
|
"eslint": "^9.9.0",
|
|
"eslint-plugin-react": "^7.35.0",
|
|
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
|
"eslint-plugin-react-refresh": "^0.4.9",
|
|
"espree": "^11.2.0",
|
|
"globals": "^15.9.0",
|
|
"sass": "^1.86.0",
|
|
"vite": "^8.1.4"
|
|
},
|
|
"overrides": {
|
|
"lodash": "4.18.1",
|
|
"js-yaml": "4.3.1",
|
|
"@babel/core": "7.29.7",
|
|
"ws": "8.21.0",
|
|
"engine.io-client": "6.6.6"
|
|
}
|
|
}
|