Known Limitations & TODOs
This page documents known technical debts, workarounds, and planned improvements in the current Mapo v2 implementation. Items are tagged with their priority and the phase in which they are expected to be addressed.
installModule deprecation warning (active in selected modules)
Affects: mapomodule/src/module.ts, @mapomodule/core/src/module.ts
Status: Low risk, functional
Nuxt 4.1 introduced moduleDependencies as the replacement for many installModule() use cases, and Mapo adopts it where compatible (for example in @mapomodule/uikit).
However, in the current pnpm strict monorepo setup, the meta-module mapomodule still needs resolver-based transitive installs (resolver.resolvePath(...) + installModule(...)) so consuming apps are not forced to declare every @mapomodule/* package explicitly.
This means deprecation warnings can still appear in these two files, but runtime behavior is correct.
Nuxt 4.1+ moduleDependencies feature
Affects: currently used in @mapomodule/uikit/src/module.ts for @nuxt/ui dependency declaration
Status: Active
Mapo now declares module dependencies with moduleDependencies instead of calling installModule() in setup().
What this provides:
- explicit dependency graph between modules
- optional semver constraints (
version) - per-dependency config merge controls:
defaults: apply only when user config is missingoverrides: force values overnuxt.options
- cleaner setup code with fewer runtime checks
For Mapo specifically:
- keep
moduleDependencieswhere module names resolve reliably in consumer apps - keep resolver-based
installModulewhere transitive local package resolution is still required
This hybrid strategy preserves the public API and pnpm strict compatibility while progressively adopting Nuxt 4.1+ patterns.
Subpath imports required in runtime code
Affects: @mapomodule/core/src/runtime/**, any package that imports stores at runtime
Status: Active workaround required
nuxt-module-builder compiles packages and generates .d.ts type declaration files. For the main entry (@mapomodule/store) this resolves to dist/module.mjs — the Nuxt module file that imports @nuxt/kit. Importing @mapomodule/store from runtime code (plugins, composables) causes @nuxt/kit to be loaded in a browser context, which fails.
The fix: always use subpath imports in runtime code:
// Correct
import { useAuthStore } from "@mapomodule/store/runtime/stores/auth";
// Wrong — imports @nuxt/kit, breaks in client context
import { useAuthStore } from "@mapomodule/store";In Vue components and pages, useAuthStore is auto-imported by Nuxt and this does not apply.
Root cause: nuxt-module-builder conflates the module entry (Nuxt lifecycle code) with the runtime exports. There is no standard way to express "this package has both a Nuxt module entry and runtime exports" cleanly in a single package.json exports map with correct .d.ts generation.
Mitigation in place: every runtime package now runs a dedicated declaration pass after nuxt-module-build build:
tsc -p tsconfig.build-types.jsonfor TS-only packages (core,store)vue-tsc -p tsconfig.build-types.jsonfor SFC packages (form,uikit)
For SFC packages, the build also runs scripts/clean-empty-vue-dts.mjs to remove zero-byte .vue.d.ts / .d.vue.ts stubs emitted in dist/. TypeScript can prefer those sibling declarations over the real .vue source; when they are empty, consumer types silently collapse to any.
The ./runtime/* export resolves its types condition to ./src/runtime/*.ts, and src/ is included in the published files, so runtime subpath imports stay typed both in the monorepo (stub mode) and for npm consumers (built mode).
tsconfig paths workaround in @mapomodule/core
Affects: packages/@mapomodule/core/tsconfig.json
Status: Active workaround required
nuxt-module-builder generates empty .d.ts files for runtime subpath imports (e.g. @mapomodule/store/runtime/stores/auth). This causes TypeScript to see no types when @mapomodule/core imports from @mapomodule/store/runtime/*.
The fix is a paths override in @mapomodule/core/tsconfig.json that points TypeScript directly at the source .ts files during development:
"paths": {
"@mapomodule/store": ["./node_modules/@mapomodule/store/src/index.ts"],
"@mapomodule/store/runtime/stores/*": ["./node_modules/@mapomodule/store/src/runtime/stores/*.ts"],
"@mapomodule/store/runtime/*": ["./node_modules/@mapomodule/store/src/runtime/*.ts"]
}Limitation (mitigated): the paths override itself only works in the monorepo, but external consumers are covered separately: published packages ship src/ (for the ./runtime/* types condition) and real .d.ts files generated by the dedicated build-types step (tsc / vue-tsc depending on package), so runtime subpath imports are typed from npm as well.
TODO: The long-term fix is proper .d.ts generation for runtime subpath exports in nuxt-module-builder. Track upstream.
@mapomodule/core plugin registration is hardcoded in mapomodule only
Affects: Users who use @mapomodule/core directly without mapomodule
Status: By design, but underdocumented
The $mapoFetch plugin (00.fetch.ts) is registered by @mapomodule/core/src/module.ts. If someone installs @mapomodule/core standalone (without mapomodule), they still get $mapoFetch — it's fine. However, if a user wants to override the 401/403 behaviour, there is no hook for it short of forking the plugin.
TODO (Phase 2): Add mapoCore.onUnauthorized and mapoCore.onForbidden config hooks so the behaviour can be overridden without forking.
Auth store has no loading/pending state
Affects: SSR hydration, login transitions
Status: By design for now — Phase 1 scope
The auth store has no isLoading flag. During the SSR init plugin, there is a brief window between plugin start and setUser() where isAuthenticated is false. Route middleware runs after the plugin resolves, so in practice this does not cause issues — but for loading skeletons or animated transitions, a pending state would be useful.
TODO (Phase 2): Add auth.isPending: boolean state — true during fetchUser() calls, false once resolved.
No automatic token refresh
Affects: Long-lived sessions
Status: Intentional for v2 — session-cookie-based auth does not require explicit refresh
Django session cookies have a configurable lifetime (typically 2 weeks). When the session expires, the next request returns 401, the 00.fetch.ts interceptor calls authStore.reset() and redirects to /login. The user must log in again.
TODO (future): If the backend supports session sliding expiry (Django SESSION_SAVE_EVERY_REQUEST = True), sessions auto-extend on activity. No Mapo code changes are needed — Django handles it. Document recommended Django session settings.
mapo-integrations-camomilla double slash bug fixed — but test coverage missing
Affects: packages/mapo-integrations-camomilla/src/runtime/server/utils/pathRewrite.ts
Status: Fixed, no regression test yet
A bug caused double slashes in rewritten URLs (e.g. /api/camomilla//users/current/) when the path already ended with /. The fix is:
rewritten.replace(/([^:]\/)\/+/g, "$1");TODO: Add unit tests for applyPathRewrite covering paths with and without trailing slashes, and paths with query strings.
No integration between mapo-integrations-camomilla and Nuxt DevTools
Status: Not started
@nuxt/devtools supports custom tabs via nuxt/devtools/kit. mapo-integrations-camomilla could expose a tab showing the proxy request log, path rewrite rules, and cookie state.
TODO (Phase 3): Add a DevTools integration to mapo-integrations-camomilla.
Direct type imports require declaring the package (pnpm strict mode)
Affects: any consuming app that imports types or runtime helpers from a specific @mapomodule/* package
Status: By design
Installing mapomodule registers all sub-modules at runtime (the meta-module resolves them from its own node_modules). However, module resolution for your own import statements follows standard Node rules: with pnpm's strict (non-hoisted) layout, @mapomodule/form/types, @mapomodule/uikit/types, @mapomodule/utils, etc. are only resolvable if the package is declared in your app's dependencies.
// package.json of the consuming app
{
"dependencies": {
"mapomodule": "...",
// Needed only if you import directly from these packages:
"@mapomodule/form": "...",
"@mapomodule/uikit": "...",
"@mapomodule/utils": "...",
},
}Two ways to avoid the extra dependencies:
- Import all shared types from the
mapomodule/typesaggregator (re-exports core, store, form, uikit and utils types) —mapomoduleis already a direct dependency. - On npm/yarn (hoisted layouts) the imports work without explicit declarations, but declaring them is still the correct, portable setup.
With a missing declaration the failure mode is TS2307: Cannot find module '@mapomodule/form/types' in vue-tsc / IDE, while the app may still run (Nuxt resolves the modules through mapomodule).
vue-tsc 3.x is required with TypeScript 6
Affects: all packages and apps, CI typechecking
Status: Resolved (pinned in devDependencies)
The monorepo uses TypeScript 6. vue-tsc 2.x is silently incompatible with TS 6: it parses <script setup lang="ts"> template expressions incorrectly and, worse, drops semantic errors entirely — a broken import (TS2307) or a wrong store API call is simply not reported. This masked a large number of real type errors for months.
Always use vue-tsc@^3 (workspace root and package devDependencies). To typecheck an app:
cd apps/example
npx nuxt prepare # regenerate .nuxt types
npx vue-tsc --noEmit -p .nuxt/tsconfig.app.json