feat(v1.1.5): files SDK + files:* triggers

Filesystem-backed blob storage as the fifth concrete trigger kind.

- `files::collection(c).{create,head,get,update,delete,list}` Rhai SDK
  (blob in/out; metadata maps; missing-field throws naming the field).
- `FilesService` trait in picloud-shared; `FsFilesRepo` (atomic
  write: temp→fsync→rename→fsync-dir→DB; single-pass SHA-256;
  checksum-verified reads → Corrupted) + `FilesServiceImpl` in
  manager-core. Metadata in Postgres (0018), bytes on disk under
  PICLOUD_FILES_ROOT with 0o700 shard dirs.
- `files:*` trigger kind via the Layout-E pattern (0019: widen both
  CHECKs + files_trigger_details), TriggerEvent::Files (metadata only,
  no bytes), emit_files fan-out, dispatcher arm, admin endpoint
  POST /triggers/files (reuses validate_trigger_target).
- AppFilesRead/AppFilesWrite capabilities → script:read/script:write
  (seven-scope commitment held). AppPubsubPublish reserved for v1.1.6.
- Admin files API (list + delete) + dashboard Files view per app.

Cross-app isolation keyed on cx.app_id at every layer. ~45 new tests
(service in-memory, fs tempdir, bridge integration). No DB required
for the suite. publish_ephemeral and the orphan sweep stay deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-03 21:18:17 +02:00
parent 03d03ea6e7
commit 6e132b6ee0
29 changed files with 3599 additions and 31 deletions

View File

@@ -20,9 +20,9 @@
use std::sync::Arc;
use crate::{
DeadLetterService, DocsService, HttpService, KvService, ModuleSource, NoopDeadLetterService,
NoopDocsService, NoopEventEmitter, NoopHttpService, NoopKvService, NoopModuleSource,
ServiceEventEmitter,
DeadLetterService, DocsService, FilesService, HttpService, KvService, ModuleSource,
NoopDeadLetterService, NoopDocsService, NoopEventEmitter, NoopFilesService, NoopHttpService,
NoopKvService, NoopModuleSource, ServiceEventEmitter,
};
/// SDK service bundle. See module docs for the lifecycle and the v1.1.x
@@ -60,6 +60,13 @@ pub struct Services {
/// the picloud binary; `NoopHttpService` in tests that don't make
/// network calls.
pub http: Arc<dyn HttpService>,
/// Filesystem-backed blob storage (v1.1.5). Scripts get
/// `files::collection(name).{create,head,get,update,delete,list}`.
/// Backed by a Postgres-metadata + on-disk-bytes repo in the
/// picloud binary; `NoopFilesService` in tests that don't touch
/// files.
pub files: Arc<dyn FilesService>,
}
impl Services {
@@ -74,6 +81,7 @@ impl Services {
events: Arc<dyn ServiceEventEmitter>,
modules: Arc<dyn ModuleSource>,
http: Arc<dyn HttpService>,
files: Arc<dyn FilesService>,
) -> Self {
Self {
kv,
@@ -82,6 +90,7 @@ impl Services {
events,
modules,
http,
files,
}
}
@@ -99,6 +108,7 @@ impl Services {
Arc::new(NoopEventEmitter),
Arc::new(NoopModuleSource),
Arc::new(NoopHttpService),
Arc::new(NoopFilesService),
)
}
}