{"id":48093953,"url":"https://github.com/nostrability/schemata-codegen","last_synced_at":"2026-04-04T15:34:06.300Z","repository":{"id":346944695,"uuid":"1192273715","full_name":"nostrability/schemata-codegen","owner":"nostrability","description":"Nostr-aware code generator for schemata schemas — typed tag tuples, kind interfaces, and runtime validators","archived":false,"fork":false,"pushed_at":"2026-03-26T22:50:14.000Z","size":91,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-27T00:38:21.173Z","etag":null,"topics":["codegen","interop","json-schema","nostr","nostrability","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nostrability.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2026-03-26T03:53:19.000Z","updated_at":"2026-03-26T20:39:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nostrability/schemata-codegen","commit_stats":null,"previous_names":["nostrability/schemata-codegen"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/nostrability/schemata-codegen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrability%2Fschemata-codegen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrability%2Fschemata-codegen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrability%2Fschemata-codegen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrability%2Fschemata-codegen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nostrability","download_url":"https://codeload.github.com/nostrability/schemata-codegen/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nostrability%2Fschemata-codegen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31403959,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["codegen","interop","json-schema","nostr","nostrability","typescript"],"created_at":"2026-04-04T15:34:06.131Z","updated_at":"2026-04-04T15:34:06.259Z","avatar_url":"https://github.com/nostrability.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# schemata-codegen\n\nNostr-aware code generator that reads [schemata](https://github.com/nostrability/schemata)'s compiled JSON schemas and produces typed code for 13 languages. Schemata-codegen includes tag tuple types, kind event interfaces, runtime validators, kind metadata, and error messages. \n\nUnlike the [validator approach](https://github.com/nostrability/schemata?tab=readme-ov-file#validators), no \"heavy\" validator is needed (e.g. AJV etc.), and code is run natively. For the real world practitioner, this means that schemata-codegen can be deployed to production, and not just constrained to CI. \n\nThe above said, schemata-codegen is complementary to the schemata validator approach.\n\n## How it fits in the schemata ecosystem\n\n| Repo | Role |\n|---|---|\n| [schemata](https://github.com/nostrability/schemata) | The schemas themselves (YAML source, compiled JSON dist/) |\n| schemata-{rs,py,go,...} | Data packages — embed the compiled JSON for a given language |\n| schemata-validator-{rs,py,go,...} | Runtime validators — pass/fail a JSON blob against a schema (AJV, jsonschema, etc.) |\n| **schemata-codegen** | **Code generator — produces typed language constructs from the schemas** |\n\nThe data packages give you access to raw schemas. The validators check whether a JSON blob conforms to a schema (pass/fail — useful for conformance testing, which is what [sherlock](https://github.com/nostrability/sherlock) does against live relay data). The codegen produces **typed language constructs** — so when you're writing code that builds or reads tags, the compiler catches structural mistakes (wrong position, missing field, bad marker value) that `string[][]` silently accepts.\n\n## Direct comparison schemata-codegen vs schemata-validator approach\n\n| Phase | schemata-js-ajv | schemata-codegen |                                                                                          \n  |-------|-----------------|------------------|                                                                                                                           \n  | **Write code** (authoring) | Nothing / no types | IDE autocomplete, type errors at compile time |                                                                      \n  | **Build** (compile) | Nothing | Type checker catches wrong field names, missing tags |                                                                                 \n  | **Construct event** (runtime) | Nothing until event is finished | Lightweight tag validator can check before signing |                                                 \n  | **Validate finished event** | Full JSON Schema validation via AJV | Could also validate, but AJV is more thorough |                                                    \n  | **Display to user** | Cryptic error paths | KIND_NAMES for UI, human-friendly error messages |             \n\n## Why not use an existing JSON Schema code generator?\n\nEvery existing generator ([quicktype](https://quicktype.io/), [typify](https://github.com/oxidecomputer/typify), [datamodel-codegen](https://github.com/koxudaxi/datamodel-code-generator), [Zod 4](https://zod.dev/)) fails on schemata's schemas. The features that make schemata valuable — tag tuple structure via `items`-as-array, `contains`, `if/then`, `oneOf` + `allOf` composition — are exactly what every generator chokes on. See [findings.md](findings.md) for the full assessment.\n\nschemata-codegen takes a different approach: instead of generically parsing JSON Schema, it pattern-matches against the specific structural shapes schemata uses and fails loudly on anything unrecognized.\n\n## Usage\n\n```bash\nnpm install\nnpm run build\n\n# Generate all outputs:\nnode dist/index.js --schemas ../schemata/dist --all\n\n# Or pick specific outputs:\nnode dist/index.js --schemas ../schemata/dist --out tags.d.ts --kinds kinds.d.ts --validators validators.ts\n```\n\n## CLI flags\n\n### TypeScript outputs\n\n| Flag | Output | Description |\n|------|--------|-------------|\n| `--out` | `tags.d.ts` | Tag tuple types (always generated) |\n| `--kinds` | `kinds.d.ts` | Kind event interfaces with literal discriminants |\n| `--validators` | `validators.ts` | Zero-dependency runtime tag validators |\n| `--registry` | `kind-registry.ts` | Kind metadata (name, NIP, required tags, category) |\n| `--errors` | `error-messages.ts` | Human-friendly error messages from schema errorMessage fields |\n| `--ajv-schemas` | `ajv-schemas/` | AJV-ready JSON schemas (see [AJV schemas](#ajv-ready-schemas-ajv-schemas) below) |\n\n### Multi-language validators\n\n| Flag | Output | API option |\n|------|--------|------------|\n| `--c-validators` | `validators.c` + `validators.h` | `--c-api generic\\|nostrdb` |\n| `--rust-validators` | `validators.rs` | `--rust-api generic\\|nostr\\|nostrdb` |\n| `--go-validators` | `validators.go` | |\n| `--python-validators` | `validators.py` | |\n| `--kotlin-validators` | `Validators.kt` | |\n| `--java-validators` | `SchemataValidators.java` | |\n| `--swift-validators` | `Validators.swift` | |\n| `--dart-validators` | `validators.dart` | |\n| `--php-validators` | `validators.php` | |\n| `--csharp-validators` | `Validators.cs` | |\n| `--cpp-validators` | `validators.hpp` | |\n| `--ruby-validators` | `validators.rb` | |\n\n### Other\n\n| Flag | Description |\n|------|-------------|\n| `--all` | Generate all outputs |\n| `--dump-plan` | Dump ValidatorAction[] plan as JSON |\n\n**No generated outputs are committed.** Run `--all` or individual flags to produce them locally. Tests verify correctness by generating and compiling the outputs during CI.\n\n## Generated outputs\n\n### Tag tuple types (`tags.d.ts`)\n\n156 tag schemas classified into 5 patterns:\n\n```typescript\n// fixed_tuple (96 tags) — exact length, typed positions\nexport type AmountTag = readonly [\"amount\", string];\nexport type EmojiTag = readonly [\"emoji\", string, string];\n\n// optional_trailing (8 tags) — union of valid lengths\nexport type RTag =\n  | readonly [\"r\", string]\n  | readonly [\"r\", string, \"read\" | \"write\"];\n\n// open_tail (46 tags) — typed prefix, rest string[]\nexport type TTag = readonly [\"t\", string, ...string[]];\n\n// discriminated_union (2 tags) — oneOf with named variants\nexport type ETag = ETagVariant1 | ETagVariant2;\n\n// structured_metadata (4 tags) — open-tail with contains constraints\nexport type ImetaTag = readonly [\"imeta\", string, ...string[]];\n// Runtime: must contain entries matching: ^url https?://\\S+$, ^m (image/...)$\n```\n\n### Kind event interfaces (`kinds.d.ts`)\n\n177 per-kind interfaces with literal `kind` discriminants, a `NostrEvent` discriminated union, and `KNOWN_KINDS` mapping.\n\n```typescript\nexport interface Kind10002Event {\n  readonly kind: 10002;\n  readonly content: string;\n  readonly tags: string[][];\n  // ...\n}\n\nexport type NostrEvent = Kind0Event | Kind1Event | ... | Kind40000Event;\n```\n\n### Runtime validators (`validators.ts`)\n\n136 kind-level validators and 3 tag-level validators. Zero dependencies — plain functions on `string[][]`. Works in any TypeScript/JavaScript environment without AJV. The same 136 validators are also generated for C, Rust, Go, Python, Kotlin, Java, Swift, Dart, PHP, C#, C++, and Ruby.\n\n```typescript\nimport { validateKind9735Tags, validateKindTags } from './validators.js';\n\nconst errors = validateKind9735Tags(event.tags);\n// Or dispatch by kind number:\nconst errors = validateKindTags(event.kind, event.tags);\n```\n\n### Kind registry (`kind-registry.ts`)\n\nStructured metadata for all 177 kinds — kind number, NIP, human-readable name, required tags, category.\n\n```typescript\nimport { KIND_NAMES, KIND_REGISTRY } from './kind-registry.js';\n\nKIND_NAMES[9735]  // \"Zap Receipt (NIP-57)\"\nKIND_REGISTRY[9735].requiredTags  // [\"p\", \"bolt11\", \"description\"]\n```\n\n### Error messages (`error-messages.ts`)\n\nHuman-friendly error messages extracted from schema `errorMessage` fields. Base field messages (shared across all kinds) and per-kind messages.\n\n```typescript\nimport { BASE_ERROR_MESSAGES, KIND_ERROR_MESSAGES } from './error-messages.js';\n\nBASE_ERROR_MESSAGES[\"pubkey\"]  // \"pubkey must be a secp256k1 public key\"\nKIND_ERROR_MESSAGES[7]  // [{ keyword: \"...\", message: \"kind must equal 7\" }, ...]\n```\n\n### AJV-ready schemas (`ajv-schemas/`)\n\nPre-processed JSON schemas with nested `$schema`, `$id`, and `errorMessage` fields stripped at build time. These can be passed directly to `ajv.compile()` without runtime preprocessing.\n\nConsumers who use AJV (sherlock, nostr-watch, nostria) can generate these once and load them instead of stripping fields at runtime.\n\n```bash\nnode dist/index.js --schemas ../schemata/dist --ajv-schemas ./ajv-schemas\n\n# Then in your code:\nimport kind7Schema from './ajv-schemas/kind-7.json';\nconst validate = ajv.compile(kind7Schema);  // No preprocessing needed\n```\n\n## Using with nostr-tools\n\nAfter generating outputs (see [Usage](#usage) above), the validators and kind registry work directly with [nostr-tools](https://github.com/nbd-wtf/nostr-tools) — no wrapper needed. Both `kind` (`number`) and `tags` (`string[][]`) match what codegen expects:\n\n```typescript\nimport type { Event } from 'nostr-tools';\nimport { validateKindTags } from './validators.js';\nimport { KIND_NAMES } from './kind-registry.js';\n\nfunction handleEvent(event: Event) {\n  const errors = validateKindTags(event.kind, event.tags);\n  if (errors.length \u003e 0) {\n    console.warn(`Invalid ${KIND_NAMES[event.kind]}:`, errors);\n    return;\n  }\n  // event.tags validated — safe to process\n}\n```\n\n## Using with NDK\n\nSame pattern with [NDK](https://github.com/nostr-dev-kit/ndk). `NDKEvent.tags` is `string[][]` and `NDKEvent.kind` is `NDKKind | number` — both compatible with codegen's validators:\n\n```typescript\nimport { NDKEvent } from '@nostr-dev-kit/ndk';\nimport { validateKindTags } from './validators.js';\nimport { KIND_NAMES } from './kind-registry.js';\n\nfunction handleEvent(event: NDKEvent) {\n  const errors = validateKindTags(event.kind, event.tags);\n  if (errors.length \u003e 0) {\n    console.warn(`Invalid ${KIND_NAMES[event.kind]}:`, errors);\n    return;\n  }\n  // event.tags validated — safe to process\n}\n```\n\n## See Also\n\n- [PATTERNS.md](https://github.com/nostrability/schemata/blob/master/PATTERNS.md) — catalog of 69+ regex patterns with codegen classification and pipeline docs\n- [schemata](https://github.com/nostrability/schemata) — source YAML schemas and compiled JSON dist/\n- [sherlock](https://github.com/nostrability/sherlock) — schema conformance scanner using codegen outputs\n\n## Tests\n\n```bash\nnpm test    # 317 tests — extraction, emission, tsc compilation, runtime validation\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnostrability%2Fschemata-codegen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnostrability%2Fschemata-codegen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnostrability%2Fschemata-codegen/lists"}