Lays down the v1.1.3 plumbing:
- `ScriptKind` enum in `picloud-shared` ('endpoint' | 'module').
- `ModuleSource` trait + `ModuleScript` DTO + `NoopModuleSource` in
`picloud-shared`. Resolver lives in `executor-core`; Postgres impl
in `manager-core` (`PostgresModuleSource`).
- `Services::new` grows a fifth `modules: Arc<dyn ModuleSource>` arg.
- `ScriptValidator` returns `ValidatedScript { imports }` so the
manager can populate the dep-graph table on save. New
`validate_module` method on the trait gates module-shape rules.
- `Engine::execute_ast(&Arc<rhai::AST>, req)` lets the orchestrator's
script cache reuse compiled ASTs. `Engine::execute(&str, req)` is
preserved as a convenience that compiles inline. `Engine::compile`
exposes the AST for callers that want to cache.
- `PicloudModuleResolver` replaces `DummyModuleResolver` per-call.
Bridges Rhai's sync `ModuleResolver::resolve` to async
`ModuleSource::lookup` via `Handle::block_on`. Enforces:
- cross-app isolation (resolver captures `Arc<SdkCallCx>`),
- circular import detection (in-progress stack on the resolver),
- import depth limit (default 8 via
`Limits::module_import_depth_max`).
- Module-shape validation walks `ast.statements()` via `rhai/internals`
and accepts only `Var { CONSTANT }`, `Import`, and `Noop`. The
manager admin endpoint runs `validate_module` at save (primary
gate); resolver re-runs it at load (defense in depth).
- LRU cache `(AppId, name) -> (updated_at, Arc<Module>)` owned by
`Engine`. Size from `PICLOUD_MODULE_CACHE_SIZE` (default 512).
- Migration `0015_scripts_kind.sql` adds `scripts.kind` + composite
index + module-name shape CHECK.
- Migration `0016_script_imports.sql` adds the dep-graph table with
FK CASCADE on both columns.
- Repo: `kind` threaded through SELECT/INSERT/UPDATE. New
`count_routes_for_script` / `count_triggers_for_script` /
`list_imports` methods. `create`/`update` open a transaction and
call `replace_imports_tx` to populate the dep-graph.
- Admin endpoint: accepts `kind`; rejects reserved module names;
rejects `endpoint → module` transitions when routes / triggers
exist.
- SDK_VERSION 1.3 → 1.4.
Workspace builds; full test suite (~440 tests) green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
109 lines
2.8 KiB
TOML
109 lines
2.8 KiB
TOML
[workspace]
|
|
resolver = "2"
|
|
members = [
|
|
"crates/shared",
|
|
"crates/executor-core",
|
|
"crates/orchestrator-core",
|
|
"crates/manager-core",
|
|
"crates/picloud",
|
|
"crates/picloud-manager",
|
|
"crates/picloud-orchestrator",
|
|
"crates/picloud-executor",
|
|
"crates/picloud-cli",
|
|
]
|
|
|
|
[workspace.package]
|
|
version = "1.1.2"
|
|
edition = "2021"
|
|
rust-version = "1.92"
|
|
license = "MIT OR Apache-2.0"
|
|
authors = ["PiCloud contributors"]
|
|
repository = "https://github.com/fhamm/picloud"
|
|
|
|
[workspace.dependencies]
|
|
# Internal crates
|
|
picloud-shared = { path = "crates/shared" }
|
|
picloud-executor-core = { path = "crates/executor-core" }
|
|
picloud-orchestrator-core = { path = "crates/orchestrator-core" }
|
|
picloud-manager-core = { path = "crates/manager-core" }
|
|
|
|
# Async + HTTP
|
|
tokio = { version = "1.40", features = ["full"] }
|
|
axum = "0.8"
|
|
tower = "0.5"
|
|
tower-http = { version = "0.6", features = ["trace", "cors"] }
|
|
hyper = "1"
|
|
|
|
# Serialization
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
|
|
# Errors + logging
|
|
thiserror = "1"
|
|
anyhow = "1"
|
|
tracing = "0.1"
|
|
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
|
|
|
|
# IDs + time
|
|
uuid = { version = "1", features = ["v4", "serde"] }
|
|
chrono = { version = "0.4", features = ["serde"] }
|
|
|
|
# Async traits
|
|
async-trait = "0.1"
|
|
|
|
# Rhai scripting
|
|
rhai = { version = "1.19", features = ["sync", "serde"] }
|
|
|
|
# Postgres (manager-core only — others stay DB-free)
|
|
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres", "uuid", "chrono", "json", "macros", "migrate"] }
|
|
|
|
# Config
|
|
figment = { version = "0.10", features = ["toml", "env"] }
|
|
|
|
# HTTP client (for RemoteExecutorClient later)
|
|
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|
|
|
|
# URL parsing (for match-preview admin endpoint)
|
|
url = "2"
|
|
urlencoding = "2"
|
|
|
|
# Auth (admin users + sessions + API keys)
|
|
argon2 = "0.5"
|
|
rand = { version = "0.8", features = ["getrandom"] }
|
|
sha2 = "0.10"
|
|
base64 = "0.22"
|
|
data-encoding = "2.6"
|
|
|
|
# Stdlib utility crates (v1.1.0 stdlib PR — registered into the
|
|
# Rhai engine as the regex::/random::/etc. namespaces)
|
|
regex = "1"
|
|
hex = "0.4"
|
|
percent-encoding = "2"
|
|
|
|
# LRU caches (v1.1.3 — top-level script AST cache in orchestrator-core +
|
|
# per-module compiled-module cache in executor-core).
|
|
lru = "0.12"
|
|
|
|
[workspace.lints.rust]
|
|
unsafe_code = "forbid"
|
|
|
|
[workspace.lints.clippy]
|
|
all = { level = "warn", priority = -1 }
|
|
pedantic = { level = "warn", priority = -1 }
|
|
module_name_repetitions = "allow"
|
|
missing_errors_doc = "allow"
|
|
missing_panics_doc = "allow"
|
|
doc_markdown = "allow"
|
|
# API ergonomics: we deliberately take values by ownership for owned
|
|
# inputs (e.g. ExecRequest) and accept Rhai's Box<EvalAltResult> as-is.
|
|
needless_pass_by_value = "allow"
|
|
boxed_local = "allow"
|
|
|
|
[profile.release]
|
|
lto = "thin"
|
|
codegen-units = 1
|
|
strip = "symbols"
|
|
|
|
[profile.dev]
|
|
debug = 1
|