Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions multipaz-tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Multipaz Developer Tools (`tools.multipaz.org`)

A secure, fully client-side developer utility for working with ISO 18013-5 mDocs, CBOR/COSE structures, and SD-JWT tokens. All computations and parsing run directly inside the visitor's browser using the Multipaz SDK compiled to Kotlin/JS.

## Project Structure

This directory uses a split-project layout to support both modern frontend development (React) and single-archive deployments (FatJar):

- **[`web/`](web/)**: A Kotlin Multiplatform (Kotlin/JS) project that compiles the React Single Page Application (SPA).
- **[`server/`](server/)**: A Kotlin JVM Ktor server project that serves the compiled React assets statically. It outputs a production-ready FatJar embedding the entire application.

---

## Getting Started

### Local Development (with Hot Reload)

To run the frontend with hot reload during development:

1. **Start the Web Dev Server**:
```bash
./gradlew :multipaz-tools:web:jsBrowserDevelopmentRun --continuous
```
This will run Webpack Dev Server (typically on port `8080` or next available) and watch for source changes in `web/` to hot-reload them in the browser.

2. **Start the Backend Server**:
```bash
./gradlew :multipaz-tools:server:run
```
This will run the Ktor backend server on port `8012`.

---

## Production Build & Packaging

To compile the React web application and package everything into a single runnable FatJar:

```bash
./gradlew :multipaz-tools:server:assemble
```

This task compiles the frontend, copies the static production bundles into the server's resource package, and outputs the FatJar to:
`multipaz-tools/server/build/libs/server-all.jar`

---

## Running and Deploying the FatJar

Once compiled, you can run the application anywhere with a Java 17+ runtime:

```bash
java -jar multipaz-tools/server/build/libs/server-all.jar
```

### Configuration
By default, the server runs on port `8012`. You can override the port by setting the `PORT` environment variable:

```bash
PORT=8080 java -jar multipaz-tools/server/build/libs/server-all.jar
```
1 change: 1 addition & 0 deletions multipaz-tools/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Parent gradle file for multipaz-tools subprojects
44 changes: 44 additions & 0 deletions multipaz-tools/server/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
plugins {
id("java-library")
id("org.jetbrains.kotlin.jvm")
alias(libs.plugins.kotlinSerialization)
alias(libs.plugins.ktor)
}

application {
mainClass.set("org.multipaz.tools.server.Main")
}

kotlin {
jvmToolchain(17)
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

dependencies {
implementation(project(":multipaz"))
implementation(libs.ktor.server.netty)
implementation(libs.ktor.server.logging)
implementation(libs.logback.classic)
}

val disableWebTargets = project.properties["disable.web.targets"]?.toString()?.toBoolean() ?: false

if (!disableWebTargets) {
evaluationDependsOn(":multipaz-tools:web")

val jsBrowserDistribution = project(":multipaz-tools:web").tasks.named("jsBrowserDistribution")

tasks.named<ProcessResources>("processResources") {
dependsOn(jsBrowserDistribution)
from(project(":multipaz-tools:web").layout.buildDirectory.dir("dist/js/productionExecutable")) {
into("static")
}
}
}

ktor {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.multipaz.tools.server

import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.routing.*
import io.ktor.server.http.content.*
import io.ktor.server.plugins.calllogging.CallLogging
import io.ktor.server.response.respondText

object Main {
@JvmStatic
fun main(args: Array<String>) {
val port = System.getenv("PORT")?.toInt() ?: 8012
println("Starting multipaz-tools server on port $port...")
val server = embeddedServer(Netty, port = port, host = "0.0.0.0") {
install(CallLogging)
routing {
singlePageApplication {
useResources = true
filesPath = "static"
defaultPage = "index.html"
}
}
}
server.start(wait = true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"server_port": 8012
}
47 changes: 47 additions & 0 deletions multipaz-tools/web/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig

plugins {
alias(libs.plugins.kotlinMultiplatform)
}

val disableWebTargets = project.properties["disable.web.targets"]?.toString()?.toBoolean() ?: false

kotlin {
if (!disableWebTargets) {
js(IR) {
browser {
commonWebpackConfig {
cssSupport { enabled.set(true) }
outputFileName = "multipaz-tools.js"
}
runTask {
devServerProperty.set(
KotlinWebpackConfig.DevServer(
port = 3000,
open = false,
static = mutableListOf(
file("src/jsMain/resources").path
)
)
)
}
}
binaries.executable()
}

sourceSets {
val jsMain by getting {
dependencies {
implementation(project(":multipaz"))
implementation(project(":multipaz-doctypes"))
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.datetime)
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlin.wrappers.react)
implementation(libs.kotlin.wrappers.react.dom)
implementation(libs.kotlin.wrappers.emotion.react.js)
}
}
}
}
}
Loading
Loading