Feature/cache api upgrade#127
Merged
Merged
Conversation
Bumps the FastEdge-wit submodule to b6fdc9f, which adds cache (async), cache-sync, cache-types, and utils interfaces to the gcore:fastedge reactor world. Regenerates the merged WIT files under host-api/wit/deps/. Note: wit-bindgen 0.37.0 (current pin, aligned with StarlingMonkey wasi-0.2.3) cannot parse `async func` syntax in cache.wit. C bindings generation succeeds when only cache-sync is in scope. Async cache support requires wit-bindgen >= 0.51.0 and is being explored on feature/cache-api-async.
Adds the async `cache` interface to the strip list in merge-wit-bindings.js so it is removed from the merged world along with its file, leaving only `cache-sync`. This unblocks `pnpm run wit:bindings` with our pinned wit-bindgen 0.37.0, which cannot parse `async func` syntax. Regenerates host-api/bindings to include the new cache-sync and utils imports. Existing dictionary / secret / key-value signatures are unchanged. Async cache support is being explored on feature/cache-api-async; see that branch for the wit-bindgen 0.57.1 output and notes on what bridging component-model preview-3 subtasks to JS Promises would entail.
Adds the JS API contract for the upcoming POP-local cache module: - `Cache` static class with get / exists / set / delete / expire / incr / decr / getOrSet - `CacheEntry` Body-like return shape with arrayBuffer / text / json - `CacheValue` accepts string / ArrayBuffer / ArrayBufferView / ReadableStream / Response (status + headers discarded — this is a byte cache, not an HTTP cache) - `WriteOptions` with mutually-exclusive ttl (seconds) / ttlMs / expiresAt Reads and counters are sync; `set` is async because Response and ReadableStream inputs require collection before the host call. `getOrSet` is JS-side stampede protection with in-process coalescing. Wires the new declarations into types/index.d.ts. C++ implementation is pending — see context/CACHE_API_HANDOFF.md for the resume guide.
Captures everything decided so far on feature/cache-api so a future session can pick up the C++ wiring without re-deriving the design: - Why fastedge::cache exists (POP-local, fast read+write, atomic incr — positioned alongside fastedge::kv which is global and eventually consistent) - WIT bindings state, why the async cache interface is excluded for now, and what feature/cache-api-async preserves for future async work - Public TypeScript surface and the design decisions behind it - Concrete C++ work plan in four layers: host-api wrappers, builtin, CMake registration, tests - The drafted JS shim for getOrSet / coerceToBytes / makeCacheEntry - Open questions: WriteOptions runtime validation, incr non-integer semantics, JS-shim install pattern, future dynamic-TTL extensibility Adds an index entry under "Known Issues / Future Work" pointing at the handoff doc.
C++ wrappers around the cache-sync and utils C bindings generated by wit-bindgen. Mirrors the existing kv_store_* pattern: CacheResult<T> / CacheOption<T> / CacheError parallel KvStore* templates (slated for unification into HostResult / HostOption / HostError in a follow-up cleanup once both shipping forms are in tree). cache_set / cache_delete return std::optional<CacheError> since their WIT signatures are void-on-success; everything else returns CacheResult<T>. Includes utils_set_user_diag — host-api side only; JS-facing surface for it is a separate follow-up.
Pure C++ builtin exposing the FastEdge POP-local cache as a static
`Cache` class with seven async methods plus a Body-like `CacheEntry`
wrapper:
- get / exists / delete / expire — straight Promise wrappers around
the sync host call.
- set — accepts string / ArrayBuffer / ArrayBufferView synchronously
and Response / ReadableStream / anything-with-arrayBuffer
asynchronously via JS::AddPromiseReactions. ReadableStream is
auto-wrapped in `new Response(stream)` for the unified path.
- incr / decr — atomic counter primitive; returns Number (with a
documented Number.MAX_SAFE_INTEGER caveat).
- getOrSet — in-process stampede protection. A no-prototype JSObject
inflight map persistent-rooted for the engine's lifetime coalesces
concurrent populators for the same key. Common finalize path used
by both sync and async coercion.
CacheEntry exposes arrayBuffer / text / json — Body-shape with
Promise-returning methods. arrayBuffer returns a fresh copy so callers
can't mutate the underlying buffer and corrupt subsequent reads.
API design:
- Every method returns Promise<T> — including reads/counters that are
sync at the host level today. This is forward-compat: when the
toolchain gains preview-3 async support and we swap to the async
cache.wit, application code keeps working unchanged.
- WriteOptions is `{ ttl }` (seconds) | `{ ttlMs }` | `{ expiresAt }`
(Unix epoch seconds), mutually exclusive at runtime.
- CacheValue accepts string / ArrayBuffer / ArrayBufferView /
ReadableStream / Response. Strings UTF-8 encoded; Response
status+headers discarded.
- Errors throw synchronously for input validation (caught by `await`
the same way) and reject the Promise for host I/O errors.
Also wires the import path: src/componentize/es-bundle.ts gets a
`'cache'` case re-exporting `globalThis.Cache` from
`fastedge::cache`, and CMakeLists registers the new builtin.
Updates types/fastedge-cache.d.ts to all-async; passes typecheck.
CACHE_API_HANDOFF.md now describes what shipped rather than the work plan. Captures the decisions made during implementation: - All-async surface (the late pivot for forward-compat with the eventual async WIT swap). - Pure C++ builtin with no embedded JS shim, plus the StarlingMonkey reference templates used for Body-like + Promise-reaction patterns. - The all-async refactor, the WriteOptions discriminated union, the CacheEntry Body-like return. - Open questions still on the runtime team (incr non-integer error semantics). - Future cleanups (Host* template generalisation, async WIT swap, dynamic-TTL extension, utils.set-user-diag JS surface, future HTTP Cache API layer) — all flagged as additive, not breaking. - Verification steps and integration-test scope for the next agent. Updates the index entry from "C++ wiring pending" to "implemented, awaiting verification".
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new POP-local fastedge::cache public API to the FastEdge SDK, wiring it through WIT, C++ host/runtime bindings, JS builtins, TypeScript declarations, docs, and examples. It also extends KV with entry-style readers and aligns project/example configs with the newer ES2023 runtime baseline.
Changes:
- Added
fastedge::cacheend-to-end: WIT imports, generated bindings, host wrappers, runtime builtin, bundler resolution, TS types, docs, and examples. - Added async
KvStoreEntry-based helpers (getEntry,zrangeByScoreEntries,zscanEntries) plus related docs/examples. - Updated globals/types, example tsconfigs, workspace wiring, and plugin/doc-generation metadata for the expanded SDK surface.
Reviewed changes
Copilot reviewed 47 out of 54 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
types/index.d.ts |
Registers new cache type declarations. |
types/globals.d.ts |
Expands global Web/API typings. |
types/fastedge-kv.d.ts |
Adds entry-style KV API types. |
types/fastedge-cache.d.ts |
Defines new public cache API. |
tsconfig.json |
Raises root TS target to ES2023. |
src/componentize/es-bundle.ts |
Resolves fastedge::cache imports; pins esbuild target/format. |
src/cli/fastedge-init/create-config.ts |
Updates scaffolded jsconfig target. |
runtime/fastedge/scripts/merge-wit-bindings.js |
Excludes async cache WIT; documents rationale. |
runtime/fastedge/host-api/wit/deps/fastedge/world.wit |
Imports utils and sync cache interfaces. |
runtime/fastedge/host-api/wit/deps/fastedge/utils.wit |
Adds utils WIT interface. |
runtime/fastedge/host-api/wit/deps/fastedge/cache-types.wit |
Adds shared cache WIT types. |
runtime/fastedge/host-api/wit/deps/fastedge/cache-sync.wit |
Adds sync cache WIT API. |
runtime/fastedge/host-api/include/fastedge_host_api.h |
Declares cache host wrapper types/APIs. |
runtime/fastedge/host-api/fastedge_host_api.cpp |
Implements cache host wrappers. |
runtime/fastedge/host-api/bindings/bindings.h |
Regenerated bindings for cache/utils imports. |
runtime/fastedge/CMakeLists.txt |
Registers new cache builtin. |
runtime/fastedge/builtins/kv-store.h |
Declares new KV entry-style methods. |
runtime/fastedge/builtins/kv-store.cpp |
Implements KvStoreEntry and new KV methods. |
runtime/fastedge/builtins/cache.cpp |
Implements JS-facing cache builtin. |
pnpm-workspace.yaml |
Adds workspace SDK override. |
pnpm-lock.yaml |
Updates lockfile for workspace linking/new examples. |
github-pages/src/content/docs/reference/fastedge/kv/zset.md |
Documents new KV sorted-set entry helpers. |
github-pages/src/content/docs/reference/fastedge/kv/key-value.md |
Documents getEntry KV API. |
fastedge-plugin-source/manifest.json |
Adds cache example/plugin source mappings. |
fastedge-plugin-source/generate-docs.sh |
Includes cache types in SDK doc generation. |
fastedge-plugin-source/.generation-config.md |
Updates SDK doc-generation requirements. |
examples/static-assets/tsconfig.json |
Modernizes example TS config. |
examples/README.md |
Lists new cache examples. |
examples/react-with-hono-server/tsconfig.fastedge.json |
Modernizes FastEdge TS config. |
examples/mcp-server/tsconfig.json |
Modernizes example TS config. |
examples/kv-store/tsconfig.json |
Modernizes example TS config. |
examples/kv-store-basic/src/index.js |
Switches example to getEntry(). |
examples/cache/tsconfig.json |
Adds TS config for new cache example. |
examples/cache/src/index.ts |
Adds full cache patterns example. |
examples/cache/README.md |
Documents full cache example. |
examples/cache/package.json |
Adds package metadata for cache example. |
examples/cache/.fastedge/build-config.js |
Adds build config for cache example. |
examples/cache-basic/src/index.js |
Adds basic cache CRUD example. |
examples/cache-basic/README.md |
Documents basic cache example. |
examples/cache-basic/package.json |
Adds package metadata for basic cache example. |
docs/STATIC_SITES.md |
Minor formatting cleanup. |
docs/SDK_API.md |
Documents cache API and new KV entry APIs. |
docs/quickstart.md |
Updates KV quickstart to entry-style API. |
docs/INIT_CLI.md |
Clarifies init prompt behavior. |
docs/INDEX.md |
Refreshes index formatting/version references. |
docs/BUILD_CLI.md |
Documents positional config path and clarifies build pipeline. |
docs/ASSETS_CLI.md |
Minor formatting cleanup. |
context/development/BUILD_SYSTEM.md |
Documents customer bundling/tsconfig behavior. |
context/CONTEXT_INDEX.md |
Adds cache API project status notes. |
context/CHANGELOG.md |
Records cache/KV/tsconfig changes. |
context/CACHE_API_HANDOFF.md |
Adds cache implementation handoff details. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
qrdl
previously approved these changes
May 5, 2026
Picks up upstream removal of the async cache.wit interface (component-model preview-3 async funcs) and an associated cache-types.wit doc-comment edit. The merge script no longer needs to filter cache.wit out, since it's gone upstream — drop 'cache' from fastedgeDepsToRemove. No behavioural change: cache-sync was already what the JS SDK uses, the async interface was being filtered before this submodule bump anyway.
Regenerate runtime/fastedge/host-api/bindings/{bindings.c,bindings.h,
bindings_component_type.o} with wit-bindgen-cli 0.30.0 to fix a canonical-ABI
lowering regression in 0.37.0 that traps every JS-built component on
wasmtime 36 hosts (FastEdge edge):
WARN incoming handler cause=error while executing
Caused by: pointer not aligned
WARN execute cause=guest never invoked `response-outparam::set` method
0.37.0 generates lowering code that reads pointer/length fields from
variant-with-string types at unaligned offsets — for example in wasi:http
result/option decoding:
// wit-bindgen 0.30.0 (works)
option.val = (bindings_string_t) { ... (ptr + 4) ..., ... (ptr + 8) ... };
// wit-bindgen 0.37.0 (traps)
option.val = (bindings_string_t) { ... (ptr + 1) ..., ... (ptr + 5) ... };
These helpers fire on every incoming request, so the trap surfaces as
`530: fastedge: Execute error` for all examples — including hello-world
that doesn't touch any new interface. Confirmed end-to-end: hello-world
and cache-basic both run cleanly with 0.30.0-regenerated bindings on the
wasmtime 36 edge host.
The earlier rationale for pinning to 0.37.0 ("align with StarlingMonkey
wasi-0.2.3") was incorrect — StarlingMonkey's host-apis are independent,
and 0.30.0 parses cache-sync/utils/cache-types WIT fine.
Documents the regression and the required version in
context/development/BUILD_SYSTEM.md (new "WIT Bindings & wit-bindgen
Version" section) and adds a CHANGELOG entry. Intentionally not enforcing
the version in create-wit-bindings.sh — the contract is documented and the
verification step (head -1 bindings.h) catches mismatches immediately.
| // `fastedge::cache` module: | ||
| // | ||
| // 1. Per-IP rate limiting (atomic counters) | ||
| // 2. Origin-cache proxy (getOrSet with a fetch populator) |
| import { Cache } from "fastedge::cache"; | ||
|
|
||
| async function app(event) { | ||
| const ip = event.request.headers.get("x-forwarded-for") ?? "unknown"; |
Comment on lines
+38
to
+43
| case 'cache': { | ||
| return { | ||
| contents: ` | ||
| export const Cache = globalThis.Cache; | ||
| `, | ||
| }; |
Collaborator
Author
There was a problem hiding this comment.
added a test suite
qrdl
approved these changes
May 6, 2026
qrdl
previously approved these changes
May 6, 2026
|
🎉 This PR is included in version 2.3.0-alpha.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 2.3.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.