{"id":49351329,"url":"https://github.com/eignex/kencode","last_synced_at":"2026-04-27T10:02:59.575Z","repository":{"id":324041071,"uuid":"1094418381","full_name":"Eignex/kencode","owner":"Eignex","description":"KEncode is a kotlinx.serialization library that produces short ASCII-safe texts for eg URLs or file names.","archived":false,"fork":false,"pushed_at":"2026-04-20T09:59:48.000Z","size":339,"stargazers_count":11,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-20T11:40:59.106Z","etag":null,"topics":["base36","base62","base64","binary-serialization","binary-to-text","compact-format","kotlin","kotlin-multiplatform","kotlinx-serialization","serialization","url-safe","varint","zigzag-encoding"],"latest_commit_sha":null,"homepage":"https://eignex.com/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Eignex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-11T17:21:21.000Z","updated_at":"2026-04-20T09:59:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Eignex/kencode","commit_stats":null,"previous_names":["eignex/kencodex","eignex/kencode"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/Eignex/kencode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eignex%2Fkencode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eignex%2Fkencode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eignex%2Fkencode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eignex%2Fkencode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Eignex","download_url":"https://codeload.github.com/Eignex/kencode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eignex%2Fkencode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32331306,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["base36","base62","base64","binary-serialization","binary-to-text","compact-format","kotlin","kotlin-multiplatform","kotlinx-serialization","serialization","url-safe","varint","zigzag-encoding"],"created_at":"2026-04-27T10:02:44.971Z","updated_at":"2026-04-27T10:02:59.561Z","avatar_url":"https://github.com/Eignex.png","language":"Kotlin","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://eignex.com/\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/Eignex/.github/refs/heads/main/profile/banner-white.svg\"\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/Eignex/.github/refs/heads/main/profile/banner.svg\"\u003e\n      \u003cimg alt=\"Eignex\" src=\"https://raw.githubusercontent.com/Eignex/.github/refs/heads/main/profile/banner.svg\" style=\"max-width: 100%; width: 22em;\"\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# KEncode\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.eignex/kencode.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/com.eignex/kencode)\n[![Build](https://github.com/eignex/kencode/actions/workflows/build.yml/badge.svg)](https://github.com/eignex/kencode/actions/workflows/build.yml)\n[![codecov](https://codecov.io/gh/eignex/kencode/branch/main/graph/badge.svg)](https://codecov.io/gh/eignex/kencode)\n[![License](https://img.shields.io/github/license/eignex/kencode)](https://github.com/eignex/kencode/blob/main/LICENSE)\n\nKEncode produces short, predictable text payloads for environments with strict\ncharacter or length limits such as URLs, file names, Kubernetes labels, and log\nkeys.\n\n---\n\n## Overview\n\nKEncode provides three standalone entry points:\n\n1. **ByteEncoding** text codecs: Base62, Base36, Base64, and Base85 encoders\n   for raw binary data.\n2. **PackedFormat**: A binary format serializer that supports nested objects,\n   lists, and maps. It uses bitsets for booleans and nullability to minimize\n   overhead.\n3. **EncodedFormat**: A string format serializer that wraps the above to produce\n   small deterministic string identifiers.\n\n### Installation\n\n```kotlin\ndependencies {\n    implementation(\"com.eignex:kencode:1.2.3\")\n}\n```\n\nFor PackedFormat and EncodedFormat you also need to load the\n`kotlinx.serialization` plugin and core library.\n\n## Full serialization example\n\nMinimal example using the default `EncodedFormat` (Base62 + PackedFormat):\n\n```kotlin\n@Serializable\ndata class Payload(\n    @PackedType(IntPacking.DEFAULT) val id: ULong, // low numbers are compacted\n    @PackedType(IntPacking.SIGNED) val delta: Int, // zigzagged to compact small negatives\n    val urgent: Boolean,    // Packed into bitset\n    val handled: Instant?,  // Nullability tracked via bitset\n    val type: PayloadType\n)\n\nenum class PayloadType { TYPE1, TYPE2, TYPE3 }\n\nval payload = Payload(123u, -2, true, null, PayloadType.TYPE1)\n\nval encoded = EncodedFormat.encodeToString(payload)\n// \u003e 0fiXYI (that's it, this specific payload fits in 4 raw bytes)\nval decoded = EncodedFormat.decodeFromString\u003cPayload\u003e(encoded)\n```\n\n---\n\n## PackedFormat\n\nPackedFormat is a BinaryFormat designed to produce the smallest feasible\npayloads for Kotlin classes by moving structural metadata into a compact header.\n\n* Bit-Packing: Booleans and nullability markers are stored in a single\n  bit-header (about 1 bit per field).\n* VarInts: Int/Long fields can be optimized using `@PackedType(IntPacking.DEFAULT)`\n  (unsigned varint) or `@PackedType(IntPacking.SIGNED)` (ZigZag) annotations.\n  The names match `kotlinx-serialization-protobuf`'s `ProtoIntegerType`, and\n  `@ProtoType` annotations are recognized automatically as a fallback.\n* Full Graph Support: Handles nested objects, lists, maps, and polymorphism\n  recursively. While this is supported it will not produce as compact\n  representations as flat structures that can pack all metadata into the same\n  header.\n\n```kotlin\nval compactFormat = PackedFormat {\n    // Change default from varint to fixed byte-width\n    defaultEncoding = IntPacking.FIXED\n    // Register custom serializers\n    serializersModule = myCustomModule\n}\nval bytes = compactFormat.encodeToByteArray(payload)\n```\n\n---\n\n## EncodedFormat\n\nEncodedFormat provides a StringFormat API that produces short tokens by\ncomposing three layers:\n\n1. Binary Layer: PackedFormat (default) or ProtoBuf (recommended for\n   cross-language compatibility).\n2. Transform Layer: Optional `PayloadTransform` applied after serialization.\n   Use `CompactZeros` to strip leading zero bytes, `Checksum.asTransform()` for\n   integrity checks, or supply your own for encryption or error-correcting codes.\n   Chain multiple transforms with `PayloadTransform.then`.\n3. Text Layer: Base62 (default), Base36, Base64, or Base85.\n\n```kotlin\nval customFormat = EncodedFormat {\n    codec = Base36                  // Use Base36 instead of Base62 (for lowercase)\n    checksum = Crc16                // Convenience shorthand for transform = Crc16.asTransform()\n    binaryFormat = ProtoBuf         // Use ProtoBuf instead of PackedFormat\n}\n\nval token = customFormat.encodeToString(payload)\n\n// Chain transforms: strip leading zeros, then append checksum\nval withBoth = EncodedFormat {\n    transform = CompactZeros.then(Crc16.asTransform())\n}\n```\n\n---\n\n## Base Encoders\n\nKEncode includes standalone codecs for byte-to-text conversion. All\nimplementations support custom alphabets.\n\n* Base62 / Base36: Uses fixed-block encoding for predictable lengths without\n  padding. Main use is to have 100% alpha-numeric output, with or without\n  upper-case.\n* Base85: High-density encoding (4 bytes to 5 characters).\n* Base64 / Base64Url: RFC 4648 compatible.\n\nEncoding `\"any byte data\"` (13 bytes):\n\n| Codec  | Output                  | Length | Alphabet         |\n|--------|-------------------------|--------|------------------|\n| Base62 | `2BVj6VHhfNlsGmoMQF`    | 18     | `[0-9A-Za-z]`    |\n| Base36 | `0ksef5o4kvegb70nre15t` | 21     | `[0-9a-z]`       |\n| Base64 | `YW55IGJ5dGUgZGF0YQ==`  | 20     | `[0-9A-Za-z+/=]` |\n| Base85 | `@;^?5@X3',+Cno\u0026@/`     | 17     | ASCII 33–117     |\n\n---\n\n## Extensions\n\nThere are examples in the jvmTest source of how to extend the encoding with encryption or error correction.\n\n### Encryption\n\nWrap a cipher as a `PayloadTransform` and pass it to `EncodedFormat`:\n\n```kotlin\n@Serializable\ndata class SecretPayload(val id: Long)\n\nval encryptingTransform = object : PayloadTransform {\n    override fun encode(data: ByteArray): ByteArray = cipher.encrypt(data)\n    override fun decode(data: ByteArray): ByteArray = cipher.decrypt(data)\n}\n\nval secureFormat = EncodedFormat {\n    transform = encryptingTransform\n}\n\nval token = secureFormat.encodeToString(SecretPayload.serializer(), payload)\nval decoded = secureFormat.decodeFromString(SecretPayload.serializer(), token)\n```\n\nSee [EncryptionExample](https://github.com/Eignex/kencode/blob/main/src/jvmTest/kotlin/com/eignex/kencode/EncryptionExample.kt)\nfor the full exapmle using BouncyCastle.\n\n### Error Correction\n\nWrap an error-correcting code as a `PayloadTransform` to recover from corrupted bytes:\n\n```kotlin\nval eccTransform = object : PayloadTransform {\n    override fun encode(data: ByteArray): ByteArray = ecc.encode(data)\n    override fun decode(data: ByteArray): ByteArray = ecc.decode(data)\n}\n\nval robustFormat = EncodedFormat {\n    transform = eccTransform\n}\n\nval token = robustFormat.encodeToString(SecretPayload.serializer(), payload)\nval decoded = robustFormat.decodeFromString(SecretPayload.serializer(), token)\n```\n\nSee [ErrorCorrectionExample](https://github.com/Eignex/kencode/blob/main/src/jvmTest/kotlin/com/eignex/kencode/ErrorCorrectionExample.kt)\nfor the full example using zxing and simulated byte corruption.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feignex%2Fkencode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feignex%2Fkencode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feignex%2Fkencode/lists"}