{"_id":"@boltmcp/jq","_rev":"3-4f76b7b826bd73a4a7c4b10d70f66691","name":"@boltmcp/jq","dist-tags":{"latest":"0.1.11"},"versions":{"0.1.9":{"name":"@boltmcp/jq","version":"0.1.9","license":"MIT","_id":"@boltmcp/jq@0.1.9","maintainers":[{"name":"dan-kwiat","email":"dan.kwiat@gmail.com"}],"homepage":"https://github.com/boltmcp/jaq-ts#readme","bugs":{"url":"https://github.com/boltmcp/jaq-ts/issues"},"dist":{"shasum":"9fd639b396e03e042bb169fa4be8750c88f13a1f","tarball":"https://registry.npmjs.org/@boltmcp/jq/-/jq-0.1.9.tgz","fileCount":4,"integrity":"sha512-jePHdFVl6WuIdntjiZYvWegM0OqhkZZNFsNDZuGOIJgvGZzUUv6j5NkC6vlneDp0QcKorsPhD3FGe16ArkUW6w==","signatures":[{"sig":"MEQCID7jU8u8VXg5xDMR2BUfxPlfKHb7PcyTP7vEIhKh1W85AiAdsr7pJ8u83rZvjcFzUhaRLrCmCD1BMhMcCpIo7wF8vg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33493},"main":"index.js","napi":{"targets":["x86_64-unknown-linux-musl","aarch64-unknown-linux-musl","aarch64-apple-darwin"],"binaryName":"jaq-ts"},"type":"module","types":"index.d.ts","engines":{"node":">= 18"},"gitHead":"c90d9931d6a243c9bcf9ec304b56f8da7da80e81","scripts":{"build":"napi build --platform --release --esm","version":"napi version","artifacts":"napi artifacts","build:debug":"napi build --platform --esm"},"_npmUser":{"name":"dan-kwiat","email":"dan.kwiat@gmail.com"},"repository":{"url":"git+https://github.com/boltmcp/jaq-ts.git","type":"git"},"_npmVersion":"11.11.0","description":"jq filter engine for TypeScript, powered by jaq and NAPI-RS","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/","provenance":false},"_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.2.0"},"optionalDependencies":{"@boltmcp/jaq-ts-darwin-arm64":"0.1.9","@boltmcp/jaq-ts-linux-x64-musl":"0.1.9","@boltmcp/jaq-ts-linux-arm64-musl":"0.1.9"},"_npmOperationalInternal":{"tmp":"tmp/jq_0.1.9_1776433143133_0.9649235187525926","host":"s3://npm-registry-packages-npm-production"}},"0.1.10":{"name":"@boltmcp/jq","version":"0.1.10","license":"MIT","_id":"@boltmcp/jq@0.1.10","maintainers":[{"name":"dan-kwiat","email":"dan.kwiat@gmail.com"}],"homepage":"https://github.com/boltmcp/jq#readme","bugs":{"url":"https://github.com/boltmcp/jq/issues"},"dist":{"shasum":"da88455c05a8d3234017595907d5fafa73600f64","tarball":"https://registry.npmjs.org/@boltmcp/jq/-/jq-0.1.10.tgz","fileCount":4,"integrity":"sha512-iSK+xDq8qfuu5o3o6lL/3k9iHAEfivjr6vxdUk71dPfsvxmcQQIwj101Hs9daGOn2vjGKaE0OIaPn+BgEFsajg==","signatures":[{"sig":"MEYCIQCeaTJ8A2vo1JPowalzReiwG5p9ino7r4pEZg/bClFlZgIhAMIEJ1rF/TMjewScjToaD2b9FLmxb56ksXEn7G7ua2EM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33493},"main":"index.js","napi":{"targets":["x86_64-unknown-linux-musl","aarch64-unknown-linux-musl","aarch64-apple-darwin"],"binaryName":"jaq-ts"},"type":"module","types":"index.d.ts","engines":{"node":">= 18"},"gitHead":"5836f18669022ccaf3c61a125b9d3096f7f3347c","scripts":{"build":"napi build --platform --release --esm","version":"napi version","artifacts":"napi artifacts","build:debug":"napi build --platform --esm"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:00a5e28e-83c0-4acd-a702-4762042ebaef"}},"repository":{"url":"git+https://github.com/boltmcp/jq.git","type":"git"},"_npmVersion":"11.11.0","description":"jq filter engine for TypeScript, powered by jaq and NAPI-RS","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/","provenance":false},"_hasShrinkwrap":false,"devDependencies":{"@napi-rs/cli":"^3.2.0"},"optionalDependencies":{"@boltmcp/jaq-ts-darwin-arm64":"0.1.10","@boltmcp/jaq-ts-linux-x64-musl":"0.1.10","@boltmcp/jaq-ts-linux-arm64-musl":"0.1.10"},"_npmOperationalInternal":{"tmp":"tmp/jq_0.1.10_1776433909780_0.19774352586393307","host":"s3://npm-registry-packages-npm-production"}},"0.1.11":{"name":"@boltmcp/jq","version":"0.1.11","description":"jq filter engine for TypeScript, powered by jaq and NAPI-RS","type":"module","main":"index.js","types":"index.d.ts","napi":{"binaryName":"jaq-ts","packageName":"@boltmcp/jaq-ts","targets":["x86_64-unknown-linux-musl","aarch64-unknown-linux-musl","aarch64-apple-darwin"]},"repository":{"type":"git","url":"git+https://github.com/boltmcp/jq.git"},"license":"MIT","publishConfig":{"registry":"https://registry.npmjs.org/","access":"public","provenance":false},"scripts":{"artifacts":"napi artifacts","build":"napi build --platform --release --esm","build:debug":"napi build --platform --esm","version":"napi version"},"devDependencies":{"@napi-rs/cli":"^3.2.0"},"optionalDependencies":{"@boltmcp/jaq-ts-linux-x64-musl":"0.1.11","@boltmcp/jaq-ts-linux-arm64-musl":"0.1.11","@boltmcp/jaq-ts-darwin-arm64":"0.1.11"},"engines":{"node":">= 18"},"gitHead":"4fe954bfea923ece04f01a77727e6e9de91606b8","_id":"@boltmcp/jq@0.1.11","bugs":{"url":"https://github.com/boltmcp/jq/issues"},"homepage":"https://github.com/boltmcp/jq#readme","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-xSEpHdqOhsci9AZN9JcZ6bfF/0lfb5MzAyOiEfrzsWV5ARaCfyco5snUo4uPAzGbRuYnDmpg/03WmTZNLUWu5g==","shasum":"601a74616793abdcb03a0b8fa49e84cfcfb3315b","tarball":"https://registry.npmjs.org/@boltmcp/jq/-/jq-0.1.11.tgz","fileCount":4,"unpackedSize":34110,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCFoA82jEZ6jqCtDx1NCLjMKlGDTxyVufsmxIGQV2aF0QIgIbFysS6gGeKJEKA5JVxa50KWygFP2wiCiEqwylV3p38="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:00a5e28e-83c0-4acd-a702-4762042ebaef"}},"directories":{},"maintainers":[{"name":"dan-kwiat","email":"dan.kwiat@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jq_0.1.11_1776435522768_0.12061426118167651"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-17T13:39:03.033Z","modified":"2026-04-17T14:18:43.014Z","0.1.9":"2026-04-17T13:39:03.280Z","0.1.10":"2026-04-17T13:51:49.915Z","0.1.11":"2026-04-17T14:18:42.904Z"},"bugs":{"url":"https://github.com/boltmcp/jq/issues"},"license":"MIT","homepage":"https://github.com/boltmcp/jq#readme","repository":{"type":"git","url":"git+https://github.com/boltmcp/jq.git"},"description":"jq filter engine for TypeScript, powered by jaq and NAPI-RS","maintainers":[{"name":"dan-kwiat","email":"dan.kwiat@gmail.com"}],"readme":"# @boltmcp/jq\n\nNative jq filter engine for TypeScript, powered by [jaq](https://github.com/01mf02/jaq) and [NAPI-RS](https://napi.rs/).\n\nCompile and run [jq](https://jqlang.github.io/jq/) filters on JSON values at native speed, directly from TypeScript. No child processes, no WASM overhead.\n\n## Installation\n\n```sh\nnpm install @boltmcp/jq\n```\n\nnpm automatically installs the correct native binary for your platform.\n\n## Supported Platforms\n\n| Platform | Architecture          | libc |\n| -------- | --------------------- | ---- |\n| Linux    | x64                   | musl |\n| Linux    | arm64                 | musl |\n| macOS    | arm64 (Apple Silicon) | -    |\n\n## Usage\n\n```ts\nimport { compile } from \"@boltmcp/jq\"\n\n// Compile a jq filter (reusable across many inputs)\nconst filter = compile(\".items | map(select(.active)) | length\")\n\n// Run against a JSON value\nconst result = filter.run({\n  items: [\n    { name: \"a\", active: true },\n    { name: \"b\", active: false },\n    { name: \"c\", active: true },\n  ],\n})\n\nconsole.log(result.outputs) // [2]\nconsole.log(result.errors) // []\n```\n\n### Handling multiple outputs\n\njq filters can produce zero, one, or many outputs per input:\n\n```ts\nconst explode = compile(\".[]\")\nexplode.run([10, 20, 30])\n// { outputs: [10, 20, 30], errors: [] }\n\nconst nothing = compile(\"empty\")\nnothing.run(null)\n// { outputs: [], errors: [] }\n```\n\n### Error handling\n\nCompilation errors throw immediately:\n\n```ts\ntry {\n  compile(\"invalid syntax [[[\")\n} catch (e) {\n  // Error: parse/compile error details\n}\n```\n\nRuntime errors are collected in the `errors` array (the filter does not throw):\n\n```ts\nconst filter = compile(\".foo\")\nfilter.run(42)\n// { outputs: [], errors: ['cannot index 42 with \"foo\"'] }\n```\n\n### Filter reuse\n\nThe `compile()` step parses and compiles the jq filter. Reuse the `CompiledFilter` object to amortize this cost across many inputs:\n\n```ts\nconst filter = compile(\".timestamp | fromdateiso8601\")\nfor (const event of events) {\n  const { outputs } = filter.run(event)\n  // ...\n}\n```\n\n## API Reference\n\n### `compile(filter: string): CompiledFilter`\n\nCompiles a jq filter string. Throws on syntax or compilation errors.\n\n### `CompiledFilter`\n\n#### `.filter: string` (getter)\n\nReturns the original filter string.\n\n#### `.run(input: unknown): RunResult`\n\nRuns the compiled filter against a JSON-compatible value. Never throws. Returns a `RunResult`.\n\n### `RunResult`\n\n```ts\ninterface RunResult {\n  outputs: unknown[] // Values produced by the filter\n  errors: string[] // Runtime error messages (empty on success)\n}\n```\n\n## Design Decisions\n\n### Why jaq, not jq\n\n[jaq](https://github.com/01mf02/jaq) is a Rust reimplementation of jq that provides:\n\n- **Embeddable library** (`jaq-core`): jq does not expose a stable C library API suitable for embedding. jaq-core is designed for library use and is memory-safe.\n- **Performance**: jaq is fastest on 20 out of 30 benchmarks vs jq and gojq (see jaq README).\n- **Thread safety**: jaq-core can be used in multi-threaded environments. jq's C implementation has global state.\n\n### Why NAPI-RS, not WASM\n\nNAPI-RS compiles Rust to a native Node.js addon (`.node` file). Alternatives considered:\n\n- **WASM (e.g., jq-wasm)**: Portable but slower. WASM has overhead for JS/WASM boundary crossing and limited access to native instructions. NAPI-RS produces native machine code with zero interop overhead.\n- **Child process (e.g., node-jq)**: Spawns `jq` as a subprocess per invocation. High per-call overhead from process creation, JSON serialization to/from stdin/stdout, and requires `jq` to be installed on the system.\n- **FFI/C binding**: Would require wrapping jq's C library, which has no stable embedding API and is not memory-safe.\n\n### Why separate `compile()` + `run()`, not a single function\n\nThe two-step API amortizes compilation cost. In hot paths the filter is compiled once and reused. A convenience `run(filter, input)` function was considered but omitted to keep the API surface minimal and encourage correct usage. Wrapping the two-step API in a one-shot helper is trivial:\n\n```ts\nfunction run(filter: string, input: unknown) {\n  return compile(filter).run(input)\n}\n```\n\n### Why JS values, not JSON strings\n\nInput and output are JS values (`unknown`), not JSON strings. Alternatives considered:\n\n- **JSON string I/O**: Would require the caller to `JSON.stringify` input and `JSON.parse` output, adding boilerplate and serialization overhead. NAPI-RS efficiently bridges JS values to Rust's `serde_json::Value` without an intermediate string representation.\n- **Both**: Offering both `run(input: unknown)` and `runRaw(json: string)` was considered but deferred. The JS value API covers all use cases, and a raw string API can be added later if profiling shows benefit for large payloads.\n\n### Why runtime errors are collected, not thrown\n\nCompilation errors throw (they indicate a broken filter). Runtime errors are collected in `RunResult.errors` because:\n\n- jq filters can produce a **mix** of values and errors in a single run (e.g., `.[] | .foo` on `[{\"foo\":1}, 42]` produces one value and one error).\n- Throwing on the first error would discard partial results.\n- The caller can check `result.errors.length` and decide how to handle errors based on their use case.\n\n### Why always return an array\n\n`RunResult.outputs` is always an array, even for filters that produce exactly one output. Alternative considered:\n\n- **Return single value when exactly one output**: Would require the caller to check `Array.isArray()` or handle two return shapes. Always returning an array is consistent and predictable. The caller can do `result.outputs[0]` when they know the filter produces a single value.\n\n### Why musl + darwin only\n\nThe target platforms match the deployment environment:\n\n- **Linux musl** (x64 + arm64): For `node:24-alpine` Docker containers. Alpine uses musl libc, not glibc.\n- **macOS** (arm64 + x64): For local development on macOS.\n- **Linux glibc**: Not included because the consumer runs on Alpine. Adding glibc targets is straightforward if needed (add targets to `napi` config in `package.json`).\n- **Windows**: Not included because the consumer runs in Linux containers. Can be added if needed.\n\n### Why jaq-core/std/json, not jaq-all\n\nThe package depends on `jaq-core`, `jaq-std`, and `jaq-json` individually, not on the `jaq-all` convenience crate. `jaq-all` bundles `jaq-fmts` which adds YAML, TOML, CBOR, and XML format support that we don't need. Using the lower-level crates produces a smaller binary and fewer dependencies.\n\n## Development\n\n### Prerequisites\n\n- [Rust toolchain](https://rustup.rs/)\n- Node.js >= 18\n\n### Building locally\n\n```sh\nnpm install\nnpm run build        # release build\nnpm run build:debug  # debug build (faster compilation)\n```\n\nThis produces:\n\n- `index.js` — ESM loader that selects the correct native binary\n- `index.d.ts` — TypeScript type declarations\n- `jaq-ts.<platform>.node` — native binary for your platform\n\n### Testing locally\n\n```sh\nnode --input-type=module -e '\nimport { compile } from \"./index.js\"\nconst f = compile(\".foo | map(. + 1)\")\nconsole.log(f.run({ foo: [1, 2, 3] }))\n'\n```\n\n## Publishing\n\nPublishing is automated via GitHub Actions. Push a semver tag to trigger a release:\n\n```sh\ngit tag v0.1.0\ngit push origin v0.1.0\n```\n\nCI builds native binaries for all 3 platforms, then publishes to npm using [trusted publishing](https://docs.npmjs.com/trusted-publishers/) (OIDC — no npm token needed). Provenance is disabled because the source repository is private.\n\n### npm packages published\n\n| Package                            | Contents                       |\n| ---------------------------------- | ------------------------------ |\n| `@boltmcp/jq`                      | JS loader + TypeScript types   |\n| `@boltmcp/jaq-ts-linux-x64-musl`   | Linux x64 musl native binary   |\n| `@boltmcp/jaq-ts-linux-arm64-musl` | Linux arm64 musl native binary |\n| `@boltmcp/jaq-ts-darwin-arm64`     | macOS arm64 native binary      |\n\nThe `\"packageName\": \"@boltmcp/jaq-ts\"` in the `napi` section of `package.json` controls the naming of these platform-specific packages in the generated `index.js`. It is independent of the parent package name (`@boltmcp/jq`) — without it, `napi build` would derive platform package names from the parent, producing incorrect names like `@boltmcp/jq-darwin-arm64`.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}