feat(v1.1.1-kv): Rhai kv:: SDK module + ctx.event wiring
Wires the KV store into Rhai scripts via the handle pattern:
let widgets = kv::collection("widgets");
widgets.set("k", #{ n: 1 });
let v = widgets.get("k"); // value or () if absent
widgets.has("k") / widgets.delete("k")
let page = widgets.list(); // cursor-style pagination
`KvHandle` is a custom Rhai type holding `Arc<dyn KvService>` + the
per-call `Arc<SdkCallCx>`. Methods route async service calls through
`tokio::Handle::current().block_on(...)` — works because
`LocalExecutorClient` runs the script under `spawn_blocking` so a
runtime is reachable. The bridge surfaces `app_id` exclusively
through `cx.app_id`; no public-facing argument can spoof an app.
`TriggerEvent` lands in `picloud-shared` as the wire shape the
dispatcher will emit (KV + DeadLetter variants — KV exercised now,
DL hooks up with the dispatcher in commit 5/8). `SdkCallCx` and
`ExecRequest` grow `is_dead_letter_handler: bool` and
`event: Option<TriggerEvent>`. `engine.rs::build_ctx_map` flattens
the event into `ctx.event` for triggered handlers; direct ingress
leaves the key absent so scripts can `if "event" in ctx`.
Tests:
- 7 `sdk_kv.rs` integration tests covering the full Rhai surface
(round-trip, missing-key unit, has bool, delete was-present,
empty-collection rejection, cursor pagination, cross-app
isolation through the bridge).
- 3 new `engine.rs` tests pinning `ctx.event` shape per
design notes §4 (KV insert with value, delete with unit value,
direct invocations have no `event` key).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
//! the cx in is shared by both sides. Pure value type — no handles, no
|
||||
//! DB pool references, no allocations beyond what's in `Principal`.
|
||||
|
||||
use crate::{AppId, ExecutionId, Principal, RequestId};
|
||||
use crate::{AppId, ExecutionId, Principal, RequestId, TriggerEvent};
|
||||
|
||||
/// Per-invocation context for every stateful SDK service call.
|
||||
///
|
||||
@@ -51,4 +51,19 @@ pub struct SdkCallCx {
|
||||
/// `execution_id` of the original ingress execution. Lets the audit
|
||||
/// log group every fan-out execution under the originating event.
|
||||
pub root_execution_id: ExecutionId,
|
||||
|
||||
/// `true` only when this invocation is a `dead_letter` trigger
|
||||
/// handler. Set by the dispatcher when it picks an outbox row
|
||||
/// whose trigger has `kind = 'dead_letter'`. The retry / dead-
|
||||
/// letter machinery short-circuits when this is set: handlers
|
||||
/// execute once, with no retry, and a failed run can NEVER be
|
||||
/// dead-lettered itself (design notes §4 recursion-stop rule).
|
||||
/// `false` for every other invocation, including the script
|
||||
/// being used as a non-DL trigger handler.
|
||||
pub is_dead_letter_handler: bool,
|
||||
|
||||
/// The event that fired this script, when it's a triggered
|
||||
/// invocation. `None` for direct ingress (HTTP request, manual
|
||||
/// run). Surfaced to scripts as `ctx.event`.
|
||||
pub event: Option<TriggerEvent>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user