Files
ServerKit/frontend/package.json
T
Juan DenisandClaude Opus 5 cff35cc651 feat(sdk): share i18next with extensions; generate the vendor shims
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>
2026-08-20 00:16:04 -04:00

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"
}
}