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
201 changes: 165 additions & 36 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
@@ -1,59 +1,188 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

name: Java CI with Gradle

on:
push:
branches: [ "main" ]
branches: ["main"]
pull_request:
branches: [ "main" ]
branches: ["main"]
workflow_call:

permissions:
contents: read

env:
GRADLE_OPTS: -Dorg.gradle.daemon=false

jobs:
build:
compile:
name: Compile ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
include:
- target: jvmTest
- name: JVM
os: ubuntu-latest
- target: :scribe-slf4j:test
task: :scribe:compileKotlinJvm
- name: Android
os: ubuntu-latest
- target: iosArm64TestKlibrary
os: macos-latest
- target: testAndroidHostTest
task: :scribe:compileAndroidMain
- name: JS
os: ubuntu-latest
task: :scribe:compileKotlinJs
- name: wasmJs
os: ubuntu-latest
task: :scribe:compileKotlinWasmJs
- name: wasmWasi
os: ubuntu-latest
- target: :scribe:linuxX64Test
task: :scribe:compileKotlinWasmWasi
- name: androidNativeArm32
os: ubuntu-latest
- target: :scribe:macosArm64Test
task: :scribe:compileKotlinAndroidNativeArm32
- name: androidNativeArm64
os: ubuntu-latest
task: :scribe:compileKotlinAndroidNativeArm64
- name: androidNativeX86
os: ubuntu-latest
task: :scribe:compileKotlinAndroidNativeX86
- name: androidNativeX64
os: ubuntu-latest
task: :scribe:compileKotlinAndroidNativeX64
- name: iosArm64
os: macos-latest
task: :scribe:compileKotlinIosArm64
- name: iosSimulatorArm64
os: macos-latest
task: :scribe:compileKotlinIosSimulatorArm64
- name: iosX64
os: macos-latest
- target: :scribe:mingwX64Test
task: :scribe:compileKotlinIosX64
- name: macosArm64
os: macos-latest
task: :scribe:compileKotlinMacosArm64
- name: tvosArm64
os: macos-latest
task: :scribe:compileKotlinTvosArm64
- name: tvosSimulatorArm64
os: macos-latest
task: :scribe:compileKotlinTvosSimulatorArm64
- name: watchosArm32
os: macos-latest
task: :scribe:compileKotlinWatchosArm32
- name: watchosArm64
os: macos-latest
task: :scribe:compileKotlinWatchosArm64
- name: watchosDeviceArm64
os: macos-latest
task: :scribe:compileKotlinWatchosDeviceArm64
- name: watchosSimulatorArm64
os: macos-latest
task: :scribe:compileKotlinWatchosSimulatorArm64
- name: linuxArm64
os: ubuntu-latest
task: :scribe:compileKotlinLinuxArm64
- name: linuxX64
os: ubuntu-latest
task: :scribe:compileKotlinLinuxX64
- name: mingwX64
os: windows-latest
task: :scribe:compileKotlinMingwX64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v4
- uses: actions/cache@v4
with:
path: ~/.konan
key: ${{ runner.os }}-konan-${{ hashFiles('gradle/libs.versions.toml', 'scribe/build.gradle.kts', 'scribe-slf4j/build.gradle.kts') }}
restore-keys: ${{ runner.os }}-konan-
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: temurin
- name: Compile target
uses: gradle/gradle-build-action@ce999babab2de1c4b649dc15f0ee67e6246c994f
with:
arguments: ${{ matrix.task }} --no-configuration-cache

runtime:
name: Test ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
include:
- name: JVM
os: ubuntu-latest
task: :scribe:jvmTest
- name: Android host
os: ubuntu-latest
task: :scribe:testAndroidHostTest
- name: SLF4J JVM
os: ubuntu-latest
task: :scribe-slf4j:test
- name: LinuxX64
os: ubuntu-latest
task: :scribe:linuxX64Test
- name: JS Node
os: ubuntu-latest
task: :scribe:jsNodeTest
- name: wasmJs Node
os: ubuntu-latest
task: :scribe:wasmJsNodeTest
- name: wasmWasi Node
os: ubuntu-latest
task: :scribe:wasmWasiNodeTest
- name: JS Chrome Headless
os: ubuntu-latest
browser: true
task: :scribe:jsBrowserTest
- name: wasmJs Chrome Headless
os: ubuntu-latest
browser: true
task: :scribe:wasmJsBrowserTest
- name: macOS Arm64
os: macos-latest
task: :scribe:macosArm64Test
- name: iOS simulator
os: macos-latest
task: :scribe:iosSimulatorArm64Test
- name: tvOS simulator
os: macos-latest
task: :scribe:tvosSimulatorArm64Test
- name: watchOS simulator
os: macos-latest
task: :scribe:watchosSimulatorArm64Test
- name: MinGW
os: windows-latest
task: :scribe:mingwX64Test
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v4
- uses: actions/cache@v4
with:
path: |
~/.konan
${{ env.USERPROFILE }}\.konan
key: ${{ runner.os }}-${{ hashFiles('**/.lock') }}
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
uses: gradle/gradle-build-action@ce999babab2de1c4b649dc15f0ee67e6246c994f
with:
arguments: ${{ matrix.target }}
- uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v4
- uses: actions/cache@v4
with:
path: ~/.konan
key: ${{ runner.os }}-konan-${{ hashFiles('gradle/libs.versions.toml', 'scribe/build.gradle.kts', 'scribe-slf4j/build.gradle.kts') }}
restore-keys: ${{ runner.os }}-konan-
- name: Set up Chrome Headless
if: matrix.browser == true
uses: browser-actions/setup-chrome@v1
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: temurin
- name: Run target tests
uses: gradle/gradle-build-action@ce999babab2de1c4b649dc15f0ee67e6246c994f
with:
arguments: ${{ matrix.task }} --no-configuration-cache
- name: Upload test results on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.name }}
path: |
scribe/build/test-results/
scribe/build/reports/tests/
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<a href="./LICENSE">
<img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg">
</a>
<img alt="Platform Targets" src="https://img.shields.io/badge/targets-android%20%7C%20jvm%20%7C%20ios%20%7C%20linuxX64%20%7C%20mingwX64%20%7C%20macosArm64-0A7EA4">
<img alt="Platform Targets" src="https://img.shields.io/badge/targets-22-0A7EA4">
</p>

<p align="center">
Expand Down Expand Up @@ -45,7 +45,7 @@ Add Scribe to your `commonMain` dependencies:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("com.rafambn:scribe:0.6.0")
implementation("com.rafambn:scribe:0.7.0")
}
}
}
Expand Down Expand Up @@ -95,13 +95,27 @@ scroll.seal(BillingScribe)

Each `Scribe` object has independent configuration and delivery lifecycle. A `Scroll` is a mutable JSON-element map initialized by `newScroll(...)`; pass the runtime that should enrich and deliver it to `scroll.seal(scribe)`. Each `seal(...)` call emits a separate snapshot of the scroll data.

## Supported targets

Version 0.7.0 publishes the core `scribe` module for exactly these 22 targets:

- JVM: `jvm`, `android`
- Web: `js`, `wasmJs`, `wasmWasi`
- Android Native: `androidNativeArm32`, `androidNativeArm64`, `androidNativeX86`, `androidNativeX64`
- Apple: `iosArm64`, `iosSimulatorArm64`, `iosX64`, `macosArm64`, `tvosArm64`, `tvosSimulatorArm64`, `watchosArm32`, `watchosArm64`, `watchosDeviceArm64`, `watchosSimulatorArm64`
- Other Native: `linuxArm64`, `linuxX64`, `mingwX64`

The `js` and `wasmJs` targets support both browser and Node.js execution; `wasmWasi` is configured for Node.js. The project inherits Kotlin `2.4.10`, kotlinx.serialization `1.11.0`, and kotlinx.coroutines `1.11.0` runtime requirements. The `scribe-slf4j` module remains JVM-only.

Both artifacts are consumed from Maven Central. Scribe does not publish an npm package; Kotlin/JS and Kotlin/Wasm consumers use the Gradle Multiplatform dependency above.

## SLF4J

For JVM applications, add the SLF4J provider:

```kotlin
dependencies {
implementation("com.rafambn:scribe-slf4j:0.6.0")
implementation("com.rafambn:scribe-slf4j:0.7.0")
}
```

Expand Down
14 changes: 11 additions & 3 deletions docs/api-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,15 @@ object ApplicationScribe : Scribe() {
ApplicationScribe.hire()
```

`onIgnition` is read when processing is first hired, but handles uncaught
exceptions at the platform level. Multiple runtimes should not independently
claim this application-global hook. Archivist failures are reported by the
`onIgnition` is registered on the first `hire()` and unregistered by `retire()`.
Scribe keeps one internal platform dispatcher and fans each failure out once to
every active callback; a callback failure does not prevent the remaining
callbacks or the runtime's previous handler from observing it. Browser JS and
wasmJs observe global errors and unhandled Promise rejections. Node uses only
its uncaught-exception monitor, distinguishing `uncaughtException` from
`unhandledRejection` through the monitor's `origin` argument, so it does not
change Node's normal termination behavior. An unhandled rejection reaches the
monitor only when the host's current `--unhandled-rejections` policy promotes
it. wasmWasi has no portable global hook, so `hire()` rejects a non-null
`onIgnition` with an explicit unsupported-operation error. Archivist failures are reported by the
`onArchiveFailure` property defined by the implementation.
8 changes: 7 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

Use the library from shared code in your Kotlin Multiplatform module:

The published artifacts are available from Maven Central. Add the dependency to your shared source set:

```kotlin
kotlin {
sourceSets {
commonMain.dependencies {
implementation("com.rafambn:scribe:0.6.0")
implementation("com.rafambn:scribe:0.7.0")
}
}
}
Expand Down Expand Up @@ -106,6 +108,10 @@ AnalyticsScribe.hire()

Dismissing `PaymentsScribe` pauses only its job and does not stop `AnalyticsScribe`.

`onIgnition` observes global uncaught failures after the first `hire()` and is
unregistered by `retire()`. wasmWasi has no portable global hook; configure
`onIgnition = null` there or `hire()` reports an unsupported-operation error.

The emitted event shape is the scroll map itself:

```json
Expand Down
16 changes: 12 additions & 4 deletions docs/lifecycle-and-delivery.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ in the backend's private buffer.

## Uncaught Exceptions

Override `onIgnition` on an application-owned `Scribe` to install the platform uncaught exception
hook when processing is first hired. The hook is platform-global even though it is configured on
one instance. Archivist failures are handled separately by the implementation's
`onArchiveFailure` property.
Override `onIgnition` on an application-owned `Scribe` to observe platform-level failures. The
callback is registered on the first `hire()` and unregistered during `retire()`. Scribe installs
one internal platform dispatcher and delivers each failure once to every active Scribe callback;
callback failures are isolated and the previous platform handler is preserved. Browser JS and
wasmJs observe synchronous global errors and unhandled Promise rejections. Node observes uncaught
exceptions through `uncaughtExceptionMonitor`, using its `origin` argument to distinguish ordinary
uncaught exceptions from promoted unhandled rejections, without replacing Node's normal termination
path. A rejection is visible there only when the host's current `--unhandled-rejections` policy
promotes it. wasmWasi has no portable global hook, so a non-null `onIgnition` makes `hire()` fail with
an unsupported-operation message; normal logging works when it is null. Fatal delivery is best effort
and does not wait for the asynchronous Scribe buffer to drain. Archivist failures are handled
separately by the implementation's `onArchiveFailure` property.
2 changes: 1 addition & 1 deletion docs/slf4j.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Add the provider to a JVM application's runtime dependencies:

```kotlin
dependencies {
implementation("com.rafambn:scribe-slf4j:0.6.0")
implementation("com.rafambn:scribe-slf4j:0.7.0")
}
```

Expand Down
9 changes: 4 additions & 5 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@ kotlin = "2.4.10"
compose-multiplatform = "1.11.1"
android-minSdk = "24"
android-compileSdk = "37"
material3 = "1.9.0"
vanniktechMavenPublish = "0.37.0"
kotlinxSerialization = "1.11.0"
kotlinxCoroutines = "1.11.0"
androidx-activity-compose = "1.13.0"
slf4j = "2.0.18"
classgraph = "4.8.181"
mockk = "1.14.11"

[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerialization" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "material3" }
scribe = { module = "com.rafambn:scribe", version = "0.5.0" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" }
scribe = { module = "com.rafambn:scribe", version = "0.7.0" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classgraph" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }

[plugins]
android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
Expand Down
Loading
Loading