npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

kotlin-kvision-spa-framework-resources

v1.1.0

Published

A **Single-Page Application (SPA) framework** built with [KVision](https://kvision.io) and Kotlin/JS. This library provides a clean, modular foundation for developing reactive SPAs in Kotlin — featuring authentication, routing, multi-tenancy, and lifecy

Readme

Kotlin KVision SPA Framework

A Single-Page Application (SPA) framework built with KVision and Kotlin/JS.
This library provides a clean, modular foundation for developing reactive SPAs in Kotlin — featuring authentication, routing, multi-tenancy, and lifecycle management.


🚀 Overview

kotlin-kvision-spa-framework simplifies SPA development in Kotlin by providing:

  • A ready-to-use application lifecycle (SpaApplication)
  • Built-in authentication and refresh token handling
  • Tenant-aware configuration (SpaTenantInfo)
  • Modular routing and root module setup
  • Integrated REST service and reactive state management
  • A built-in dashboard template via DefaultSecuredModule
  • Support for modular routing via DefaultRootApplicationModule
  • Per-feature secured modules via DefaultSecuredPageModule

It consists of:

  • A Kotlin/JS dependency
  • A companion NPM package for static resources (CSS, JS, icons, etc.)

📦 Installation

Add the following to your Kotlin Multiplatform Gradle project:

plugins {
    val kotlinVersion: String by System.getProperties()
    kotlin("plugin.serialization") version kotlinVersion
    kotlin("multiplatform") version kotlinVersion
    val kvisionVersion: String by System.getProperties()
    id("io.kvision") version kvisionVersion
}

repositories {
    mavenCentral()
    mavenLocal()
}

// Versions
val kotlinVersion: String by System.getProperties()
val kvisionVersion: String by System.getProperties()

kotlin {
    js(IR) {
        browser {
            useEsModules()
            commonWebpackConfig {
                outputFileName = "main.bundle.js"
                sourceMaps = false
            }
            testTask {
                useKarma {
                    useChromeHeadless()
                }
            }
        }
        binaries.executable()
        compilerOptions {
            target.set("es2015")
        }
    }
    sourceSets["jsMain"].dependencies {
        implementation("io.kvision:kvision:$kvisionVersion")
        implementation("io.kvision:kvision-bootstrap:$kvisionVersion")
        implementation("io.kvision:kvision-routing-navigo-ng:$kvisionVersion")
        implementation("io.kvision:kvision-state-flow:$kvisionVersion")

        // ✅ Add the SPA framework dependencies
        implementation("com.bittokazi.sonartype:kotlinKvisionSpaFramework-js:1.0.8")
        implementation(npm("kotlin-kvision-spa-framework-resources", "1.0.8"))
    }
}
// ✅ Add the SPA framework dependencies (use latest version)
implementation("com.bittokazi.sonartype:kotlinKvisionSpaFramework-js:1.0.8")
implementation(npm("kotlin-kvision-spa-framework-resources", "1.0.8"))

🧠 Quick Start Example

Example main() setup using the framework:

fun main() {

    importDefaultResources()
    SpaApplication.init()
    SpaAppEngine.restService.REFRESH_TOKEN_ENDPOINT = "${SpaAppEngine.restService.BASE_URL}/login/refresh/token"

    AppEngine.restService = SpaAppEngine.restService
    AppEngine.authService = AuthService()
    AppEngine.tenantService = TenantService()
    AppEngine.userService = UserService()

    SpaAppEngine.APP_BASE_ROUTE = "/app"
    SpaAppEngine.APP_DASHBOARD_ROUTE = "/app/dashboard"
    SpaAppEngine.APP_LOGIN_ROUTE = "/app/login"

    SpaApplication.applicationConfiguration = ApplicationConfiguration(
        spaTenantInfo = SpaTenantInfo(
            cpanel = false,
            enabledConfigPanel = false,
            name = "SpaApplication"
        ),
        isTenantEnabled = true,
        rootApplicationModule = rootModule(),
        tenantInformationProvider = AppEngine.tenantService,
        authHolderType = AuthHolderType.LOCAL_STORAGE,
        menuProvider = AppEngine.authService,
        refreshTokenRequestProvider = AppEngine.authService,
        logoutActionProvider = AppEngine.authService
    )

    SpaApplication.start()
}

🧩 Using DefaultRootApplicationModule

Defines the public routes (login, signup, home) and links to the secured dashboard module.

fun rootModule(): ApplicationModule = DefaultRootApplicationModule(
    loginPage = { LoginPage() },
    securedModule = dashboardModule(),
    authInformationProvider = AppEngine.authService,
    RouterConfiguration(
        route = "/app",
        title = "App Home",
        view = { HomePage() }
    ),
    RouterConfiguration(
        route = "/app/signup",
        title = "Sign Up",
        view = { SignupPage() }
    )
)

| Parameter | Description | |------------|-------------| | loginPage | Defines the login component | | securedModule | The authenticated dashboard area | | RouterConfiguration | Adds public routes like /app or /app/signup |


🔐 Using DefaultSecuredModule

Provides a complete dashboard shell for authenticated areas.

fun dashboardModule() = DefaultSecuredModule(
    layoutLoader = DefaultLayoutLoader(),
    modules = listOf(
        userModule(),
        tenantModule(),
        pageModule(),
        categoryModule(),
        postModule(),
        commentModule()
    ),
    RouterConfiguration(
        route = AppEngine.APP_DASHBOARD_ROUTE,
        title = "Dashboard Home",
        view = {
            Div {
                p { content = "Hello Dashboard!!!" }
            }
        },
        dashboardContainer = ContentContainerType.CARD
    )
)

| Parameter | Description | |------------|-------------| | layoutLoader | Defines the dashboard layout | | modules | Registers feature modules (users, posts, etc.) | | RouterConfiguration | Defines a home or landing route | | ContentContainerType | Controls layout container style |


📘 Using DefaultSecuredPageModule

The DefaultSecuredPageModule represents a single feature or section within the dashboard —
for example, the Users management section.

fun userModule() = DefaultSecuredPageModule(
    RouterConfiguration(
        route = "/app/dashboard/users",
        title = "All Users",
        view = { UsersPage() }
    ),
    RouterConfiguration(
        route = "/app/dashboard/users/add",
        title = "Add User",
        view = { AddUserPage() }
    )
)

| Parameter | Description | |------------|-------------| | RouterConfiguration | Defines one or more routes for this section | | view | Specifies which component (page) to render | | title | Used for navigation and breadcrumbs | | route | Defines the relative URL path within the dashboard |

This allows you to modularize each section of your app — users, posts, settings, etc.


🧱 Example View Container

Here’s an example of a simple page container view (UsersPage) used inside a module:

class UsersPage : SimplePanel() {

    init {
        table(className = "table table-hover my-0") {
            thead {
                tr {
                    th { content = "#" }
                    th { content = "Email" }
                    th { content = "Name" }
                    th { content = "Role" }
                    th { content = "Actions" }
                }
            }
            tbody {
                AppEngine.userService.getAll().then {
                    it.data.forEachIndexed { index, user ->
                        tr {
                            td { content = "${index + 1}" }
                            td { content = user.email }
                            td { content = "${user.firstName} ${user.lastName}" }
                            td { content = user.roles?.get(0)?.name }
                            td { /* Action buttons go here */ }
                        }
                    }
                }.then {
                    SpaAppEngine.routing.updatePageLinks()
                }
            }
        }
    }
}

This demonstrates:

  • Fetching data from a service (AppEngine.userService)
  • Rendering it dynamically in a table
  • Updating links using SpaAppEngine.routing.updatePageLinks()

⚙️ Commands

▶️ Run with Hot Reload

./gradlew run

🏗️ Build for Production

./gradlew build

📜 License

Licensed under the MIT License.
See LICENSE for details.


💬 Support & Contributing

  • Open issues or feature requests on GitHub
  • Fork the repo and submit pull requests
  • Use GitHub Discussions for community Q&A