{"id":51926830,"url":"https://github.com/guenchi/igropyr-quickjs","last_synced_at":"2026-07-28T03:00:47.222Z","repository":{"id":372478816,"uuid":"1307570823","full_name":"guenchi/igropyr-quickjs","owner":"guenchi","description":"Quickjs Chez Scheme FFI  binding","archived":false,"fork":false,"pushed_at":"2026-07-21T13:57:41.000Z","size":10,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-07-21T14:10:41.809Z","etag":null,"topics":["chez-scheme","quickjs"],"latest_commit_sha":null,"homepage":"http://igropyr.dev","language":"Scheme","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guenchi.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":"2026-07-21T10:22:57.000Z","updated_at":"2026-07-21T13:55:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/guenchi/igropyr-quickjs","commit_stats":null,"previous_names":["guenchi/igropyr-quickjs"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/guenchi/igropyr-quickjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guenchi%2Figropyr-quickjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guenchi%2Figropyr-quickjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guenchi%2Figropyr-quickjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guenchi%2Figropyr-quickjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guenchi","download_url":"https://codeload.github.com/guenchi/igropyr-quickjs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guenchi%2Figropyr-quickjs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35973263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-28T02:00:06.341Z","response_time":109,"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":["chez-scheme","quickjs"],"created_at":"2026-07-28T03:00:39.545Z","updated_at":"2026-07-28T03:00:47.177Z","avatar_url":"https://github.com/guenchi.png","language":"Scheme","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chez-quickjs\n\n`(igropyr quickjs)` — embed a JavaScript engine\n([QuickJS](https://github.com/quickjs-ng/quickjs)) in a\n[Chez Scheme](https://cisco.github.io/ChezScheme/) process behind a small,\nhardened C shim. Load a **fixed** JS bundle at boot, then call its global\nfunctions with one UTF-8 string argument and get a string back. User input is\nthe **argument**, never code — the bundle is baked at build time, so the attack\nsurface is \"a C library parsing a user string\", the same class as zlib or a\ndatabase driver.\n\nThis is the **C-shim** binding: QuickJS is statically linked into one\nself-contained dylib, version-pinned, so the only native runtime dependency is\nthat dylib. [Igropyr](https://github.com/guenchi/Igropyr) also ships a\npure-Scheme binding with the **same exports** (`(igropyr quickjs)`, binding a\nstock `libquickjs` directly over the FFI); this repo is a drop-in replacement\nfor it — reach for the shim when a stock `libquickjs` is awkward to obtain (for\nexample Homebrew ships only a static archive) or when you want a self-contained,\nversion-pinned artifact.\n\n## Dependency\n\n`(igropyr quickjs)` imports\n[`(igropyr platform)`](https://github.com/guenchi/igropyr-platform) (host\ndetection + shared-object loading). Put it on your library path so the import\nresolves.\n\n## Build the shim\n\nRequires the QuickJS library and headers:\n\n```sh\n# macOS\nbrew install quickjs\n# Debian/Ubuntu: quickjs from the distro, or built from source\n#   (expects quickjs/quickjs.h + libquickjs)\n\n./build-quickjs-shim.sh        # -\u003e libigropyr-quickjs.dylib  (or .so on Linux)\n```\n\nQuickJS is statically linked, so the resulting dylib is the only native runtime\ndependency. Without it the library still imports fine; `qjs-boot!` reports the\nmissing shim.\n\n## Use\n\n```scheme\n(import (igropyr quickjs))\n\n(qjs-boot! \"function slugify(s){ return s.toLowerCase().replace(/\\\\s+/g,'-') }\")\n(qjs-call! \"slugify\" \"Hello World\")     ; =\u003e \"hello-world\"\n```\n\n- `(qjs-boot! source [opts])` — load (or reload) the bundle. `opts` is an\n  alist: `(mem-mb . 64)`, `(stack-kb . 1024)`, `(timeout-ms . 2000)`,\n  `(so-path . \"...\")`. Options are validated; negative caps are rejected.\n- `(qjs-call fname arg)` → `(values ok? string)` — call a global function with\n  one string argument; the result on `#t`, the JS error text on `#f`. Never\n  raises on a JS error.\n- `(qjs-call! fname arg)` → string — the raising variant.\n- `(qjs-healthy?)` / `(qjs-generation)` / `(qjs-shutdown!)`.\n\nResolution order for the dylib: explicit `(so-path ...)` \u003e the\n`IGROPYR_QUICKJS_SO` env var \u003e `igropyr/libigropyr-quickjs.{dylib,so}` \u003e the\nplain name on the loader path.\n\n## What the shim gives you\n\n- **Memory limit** — `JS_SetMemoryLimit`: allocation past the cap becomes an\n  in-JS OOM exception, never touches system memory.\n- **Stack limit** — `JS_SetMaxStackSize` + `JS_UpdateStackTop` per call: deep\n  recursion is a `RangeError`, not a C stack smash. The stack base is\n  re-anchored each call, so calls may come from any host thread.\n- **Wall-clock deadline** — `JS_SetInterruptHandler` + a monotonic deadline: a\n  call over `timeout-ms` is aborted by the engine.\n- **Exception boundary** — every call is checked; a JS error comes back as a\n  string, nothing propagates past the ABI. A throwing property getter and a\n  non-string-coercible result are reported (with the pending exception drained),\n  not swallowed or leaked into the next call.\n- **Crash-only rebuild** — any failed call discards the whole JS heap and\n  reboots the runtime from the saved bundle; `qjs-generation` counts rebuilds,\n  and a call after `qjs-shutdown!` reports cleanly.\n- **Serialized engine** — a pthread mutex guards the single runtime, so the\n  shim is safe to call from any OS thread.\n\n## Test\n\nBuild the shim, then run `test/quickjs.sc` with `(igropyr quickjs)` and\n`(igropyr platform)` resolvable on your library path (and `CHEZSCHEMELIBEXTS`\nset so `.sc` files load). The test is shim-gated: it skips cleanly when the\ndylib is not built, so it is safe to run on a host without QuickJS.\n\n## Files\n\n- `quickjs.sc` — the `(igropyr quickjs)` library (binds the C shim).\n- `c/quickjs-shim.c` — the hardened C shim (a four-function C ABI).\n- `build-quickjs-shim.sh` — builds the shim dylib.\n- `test/quickjs.sc` — end-to-end test.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguenchi%2Figropyr-quickjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguenchi%2Figropyr-quickjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguenchi%2Figropyr-quickjs/lists"}