@kromatv/sdk 0.1.40-canary.2 → 0.1.40-canary.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +3 -2
- package/package.json +1 -1
- package/rust/Cargo.toml +1 -1
- package/rust/kroma-http/Cargo.toml +1 -1
- package/rust/kroma-module-host/Cargo.toml +8 -8
- package/rust/kroma-module-host/src/auth.rs +1 -1
- package/rust/kroma-module-host/src/host_ctx.rs +4 -3
- package/rust/kroma-module-host/src/lib.rs +1 -1
- package/rust/kroma-module-host/src/storage.rs +2 -2
- package/rust/kroma-module-host/src/testing/log.rs +1 -1
- package/rust/kroma-module-host/src/testing/mod.rs +3 -2
- package/rust/kroma-module-host/src/testing/recording.rs +5 -5
- package/rust/kroma-module-host/src/testing/stub.rs +36 -44
- package/rust/kroma-module-macros/Cargo.toml +1 -1
- package/rust/kroma-module-manifest/Cargo.toml +1 -1
- package/rust/kroma-module-runtime/Cargo.toml +6 -6
- package/rust/kroma-module-runtime/src/lib.rs +15 -15
- package/rust/kroma-module-sdk/Cargo.toml +7 -13
- package/rust/kroma-module-sdk/src/lib.rs +23 -6
- package/rust/kroma-module-wire/Cargo.toml +10 -0
- package/rust/{kroma-domain → kroma-module-wire}/src/accounts.rs +1 -80
- package/rust/kroma-module-wire/src/audience.rs +75 -0
- package/rust/kroma-module-wire/src/lib.rs +14 -0
- package/rust/kroma-module-wire/src/metadata.rs +31 -0
- package/rust/kroma-module-wire/src/notifications/mod.rs +11 -0
- package/rust/{kroma-domain → kroma-module-wire}/src/notifications/spec.rs +2 -2
- package/rust/kroma-primitives/Cargo.toml +1 -1
- package/rust/kroma-sqlite/Cargo.toml +20 -0
- package/rust/{kroma-db → kroma-sqlite}/src/grant.rs +43 -5
- package/rust/kroma-sqlite/src/lib.rs +28 -0
- package/rust/kroma-sqlite/src/open.rs +56 -0
- package/rust/{kroma-db → kroma-sqlite}/src/pool.rs +1 -1
- package/rust/{kroma-db → kroma-sqlite}/src/testing.rs +18 -10
- package/rust/kroma-testing/Cargo.toml +1 -1
- package/rust/kroma-db/Cargo.toml +0 -27
- package/rust/kroma-db/src/accounts/access_tokens.rs +0 -197
- package/rust/kroma-db/src/accounts/credentials.rs +0 -97
- package/rust/kroma-db/src/accounts/invites.rs +0 -136
- package/rust/kroma-db/src/accounts/preferences.rs +0 -100
- package/rust/kroma-db/src/accounts/resets.rs +0 -202
- package/rust/kroma-db/src/accounts/sessions.rs +0 -182
- package/rust/kroma-db/src/accounts/test_support.rs +0 -14
- package/rust/kroma-db/src/accounts/verifications.rs +0 -185
- package/rust/kroma-db/src/accounts.rs +0 -244
- package/rust/kroma-db/src/admin/metrics.rs +0 -201
- package/rust/kroma-db/src/admin/play_history.rs +0 -361
- package/rust/kroma-db/src/admin/play_sort.rs +0 -113
- package/rust/kroma-db/src/admin/stats.rs +0 -108
- package/rust/kroma-db/src/admin/test_support.rs +0 -83
- package/rust/kroma-db/src/admin/watch_stats.rs +0 -458
- package/rust/kroma-db/src/admin.rs +0 -226
- package/rust/kroma-db/src/audio_analysis.rs +0 -253
- package/rust/kroma-db/src/backup/module_stores.rs +0 -204
- package/rust/kroma-db/src/backup/rows.rs +0 -155
- package/rust/kroma-db/src/backup/test_support.rs +0 -61
- package/rust/kroma-db/src/backup.rs +0 -306
- package/rust/kroma-db/src/catalog_query/find_titles.rs +0 -316
- package/rust/kroma-db/src/catalog_query/test_support.rs +0 -88
- package/rust/kroma-db/src/catalog_query.rs +0 -198
- package/rust/kroma-db/src/chunked.rs +0 -36
- package/rust/kroma-db/src/core_tables.rs +0 -99
- package/rust/kroma-db/src/curated.rs +0 -192
- package/rust/kroma-db/src/downloaded_subs.rs +0 -136
- package/rust/kroma-db/src/downloads.rs +0 -219
- package/rust/kroma-db/src/grant/escapes/schema.rs +0 -120
- package/rust/kroma-db/src/grant/escapes/statements.rs +0 -170
- package/rust/kroma-db/src/grant/escapes.rs +0 -141
- package/rust/kroma-db/src/grant/tests.rs +0 -255
- package/rust/kroma-db/src/home/genre_guard.rs +0 -249
- package/rust/kroma-db/src/home/hydration.rs +0 -126
- package/rust/kroma-db/src/home/test_support.rs +0 -60
- package/rust/kroma-db/src/home.rs +0 -244
- package/rust/kroma-db/src/hydrate.rs +0 -296
- package/rust/kroma-db/src/ingest/metadata.rs +0 -648
- package/rust/kroma-db/src/ingest/probe.rs +0 -171
- package/rust/kroma-db/src/ingest/probe_result.rs +0 -178
- package/rust/kroma-db/src/ingest/scanned_files.rs +0 -235
- package/rust/kroma-db/src/ingest/sync.rs +0 -291
- package/rust/kroma-db/src/ingest/test_support.rs +0 -114
- package/rust/kroma-db/src/ingest.rs +0 -20
- package/rust/kroma-db/src/jobs.rs +0 -269
- package/rust/kroma-db/src/lib.rs +0 -97
- package/rust/kroma-db/src/library.rs +0 -66
- package/rust/kroma-db/src/localize/items.rs +0 -303
- package/rust/kroma-db/src/localize/shows.rs +0 -192
- package/rust/kroma-db/src/localize/test_support.rs +0 -91
- package/rust/kroma-db/src/localize.rs +0 -105
- package/rust/kroma-db/src/markers.rs +0 -203
- package/rust/kroma-db/src/media/person.rs +0 -213
- package/rust/kroma-db/src/media/show_detail.rs +0 -186
- package/rust/kroma-db/src/media/shows.rs +0 -202
- package/rust/kroma-db/src/media/splash.rs +0 -199
- package/rust/kroma-db/src/media/test_support.rs +0 -31
- package/rust/kroma-db/src/media.rs +0 -296
- package/rust/kroma-db/src/metadata_core.rs +0 -348
- package/rust/kroma-db/src/notifications/digest.rs +0 -143
- package/rust/kroma-db/src/notifications/preferences.rs +0 -138
- package/rust/kroma-db/src/notifications/read_state.rs +0 -167
- package/rust/kroma-db/src/notifications/test_support.rs +0 -50
- package/rust/kroma-db/src/notifications.rs +0 -232
- package/rust/kroma-db/src/passkeys.rs +0 -163
- package/rust/kroma-db/src/pipeline/ops/drain.rs +0 -266
- package/rust/kroma-db/src/pipeline/ops/reconcile.rs +0 -274
- package/rust/kroma-db/src/pipeline/ops/test_support.rs +0 -48
- package/rust/kroma-db/src/pipeline/ops.rs +0 -49
- package/rust/kroma-db/src/pipeline/query/elements.rs +0 -200
- package/rust/kroma-db/src/pipeline/query/test_support.rs +0 -23
- package/rust/kroma-db/src/pipeline/query.rs +0 -255
- package/rust/kroma-db/src/pipeline/tests.rs +0 -319
- package/rust/kroma-db/src/pipeline.rs +0 -26
- package/rust/kroma-db/src/playback/continue_watching.rs +0 -289
- package/rust/kroma-db/src/playback/on_deck.rs +0 -53
- package/rust/kroma-db/src/playback/show_progress.rs +0 -230
- package/rust/kroma-db/src/playback/test_support.rs +0 -55
- package/rust/kroma-db/src/playback/up_next.rs +0 -208
- package/rust/kroma-db/src/playback/watch_state.rs +0 -129
- package/rust/kroma-db/src/playback.rs +0 -196
- package/rust/kroma-db/src/push_subs.rs +0 -323
- package/rust/kroma-db/src/reports.rs +0 -231
- package/rust/kroma-db/src/requests/availability.rs +0 -211
- package/rust/kroma-db/src/requests/calendar.rs +0 -221
- package/rust/kroma-db/src/requests/gaps.rs +0 -213
- package/rust/kroma-db/src/requests/search_queue.rs +0 -352
- package/rust/kroma-db/src/requests/tests.rs +0 -289
- package/rust/kroma-db/src/requests/wanted.rs +0 -351
- package/rust/kroma-db/src/requests.rs +0 -245
- package/rust/kroma-db/src/rows.rs +0 -190
- package/rust/kroma-db/src/schema/ddl.rs +0 -678
- package/rust/kroma-db/src/schema/migrations.rs +0 -261
- package/rust/kroma-db/src/schema.rs +0 -273
- package/rust/kroma-db/src/suggest.rs +0 -129
- package/rust/kroma-db/src/taste.rs +0 -77
- package/rust/kroma-db/src/tmdb_pin.rs +0 -133
- package/rust/kroma-db/src/translations.rs +0 -569
- package/rust/kroma-db/src/vectors/recommendations.rs +0 -164
- package/rust/kroma-db/src/vectors/search.rs +0 -213
- package/rust/kroma-db/src/vectors/test_support.rs +0 -31
- package/rust/kroma-db/src/vectors.rs +0 -161
- package/rust/kroma-domain/Cargo.toml +0 -17
- package/rust/kroma-domain/src/admin.rs +0 -197
- package/rust/kroma-domain/src/cast.rs +0 -178
- package/rust/kroma-domain/src/crash.rs +0 -48
- package/rust/kroma-domain/src/jobs.rs +0 -119
- package/rust/kroma-domain/src/lib.rs +0 -44
- package/rust/kroma-domain/src/library.rs +0 -21
- package/rust/kroma-domain/src/matching/mod.rs +0 -293
- package/rust/kroma-domain/src/matching/normalize.rs +0 -193
- package/rust/kroma-domain/src/media.rs +0 -297
- package/rust/kroma-domain/src/metadata.rs +0 -389
- package/rust/kroma-domain/src/naming/marker.rs +0 -215
- package/rust/kroma-domain/src/naming/mod.rs +0 -283
- package/rust/kroma-domain/src/naming/title.rs +0 -349
- package/rust/kroma-domain/src/notifications/mod.rs +0 -18
- package/rust/kroma-domain/src/notifications/view.rs +0 -55
- package/rust/kroma-domain/src/people.rs +0 -286
- package/rust/kroma-domain/src/pipeline.rs +0 -114
- package/rust/kroma-domain/src/playback.rs +0 -39
- package/rust/kroma-domain/src/push.rs +0 -163
- package/rust/kroma-domain/src/reports.rs +0 -213
- package/rust/kroma-domain/src/requests/discover.rs +0 -102
- package/rust/kroma-domain/src/requests/ledger.rs +0 -129
- package/rust/kroma-domain/src/requests/mod.rs +0 -238
- package/rust/kroma-domain/src/section.rs +0 -44
- package/rust/kroma-domain/src/slug.rs +0 -165
- /package/rust/{kroma-domain → kroma-module-wire}/src/notifications/action.rs +0 -0
- /package/rust/{kroma-domain → kroma-module-wire}/src/notifications/event.rs +0 -0
- /package/rust/{kroma-domain → kroma-module-wire}/src/notifications/param.rs +0 -0
package/dist/cli.js
CHANGED
|
@@ -23829,7 +23829,7 @@ async function serverPlatform(server) {
|
|
|
23829
23829
|
const res = await fetch(`${server.url}/api/admin/store/platform`, {
|
|
23830
23830
|
headers: { authorization: `Bearer ${server.token}` }
|
|
23831
23831
|
});
|
|
23832
|
-
if (res.status
|
|
23832
|
+
if (UNANSWERED.has(res.status))
|
|
23833
23833
|
return null;
|
|
23834
23834
|
if (!res.ok)
|
|
23835
23835
|
throw new Error(`${server.url}: GET /api/admin/store/platform failed (${res.status})`);
|
|
@@ -23859,11 +23859,12 @@ async function uploadBundle(server, path) {
|
|
|
23859
23859
|
throw new Error(`install failed (${res.status}): ${body}`);
|
|
23860
23860
|
return body;
|
|
23861
23861
|
}
|
|
23862
|
-
var DEFAULT_SERVER = "http://localhost:4040", Platform;
|
|
23862
|
+
var DEFAULT_SERVER = "http://localhost:4040", Platform, UNANSWERED;
|
|
23863
23863
|
var init_server = __esm(() => {
|
|
23864
23864
|
init_zod();
|
|
23865
23865
|
init_config();
|
|
23866
23866
|
Platform = exports_external.object({ target: exports_external.string(), serverVersion: exports_external.string() });
|
|
23867
|
+
UNANSWERED = new Set([404, 405]);
|
|
23867
23868
|
});
|
|
23868
23869
|
|
|
23869
23870
|
// src/commands/build.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kromatv/sdk",
|
|
3
|
-
"version": "0.1.40-canary.
|
|
3
|
+
"version": "0.1.40-canary.3",
|
|
4
4
|
"description": "Build KROMA modules: the SDK, the design system types, the Rust crates and the kroma CLI in one package.",
|
|
5
5
|
"author": "Maxime Scharwath <maxscharwath@gmail.com>",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
package/rust/Cargo.toml
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
[workspace]
|
|
2
2
|
resolver = "2"
|
|
3
|
-
members = ["kroma-module-sdk", "kroma-module-runtime", "kroma-module-host", "kroma-module-manifest", "kroma-module-macros", "kroma-
|
|
3
|
+
members = ["kroma-module-sdk", "kroma-module-runtime", "kroma-module-host", "kroma-module-manifest", "kroma-module-macros", "kroma-module-wire", "kroma-sqlite", "kroma-http", "kroma-primitives", "kroma-testing"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "kroma-http"
|
|
3
|
-
version = "0.1.40-canary.
|
|
3
|
+
version = "0.1.40-canary.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.88"
|
|
6
6
|
description = "KROMA's two HTTP transports: a curl process per call for the outside world, and a pooled client for the loopback seam between the core and its module sidecars"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "kroma-module-host"
|
|
3
|
-
version = "0.1.40-canary.
|
|
3
|
+
version = "0.1.40-canary.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.88"
|
|
6
6
|
description = "The host seam: the narrow HostCtx contract + shared HTTP extractors a module crate's backend needs, without depending on the whole app (kroma-engine)."
|
|
@@ -10,21 +10,21 @@ license = "MIT"
|
|
|
10
10
|
# Compiles `testing::{StubHost, Recording}`, the shared HostCtx doubles. Off by
|
|
11
11
|
# default so nothing reaches a release build; crates that test against the seam
|
|
12
12
|
# turn it on in their dev-dependencies.
|
|
13
|
-
testing = ["dep:kroma-testing", "storage", "test-serve"]
|
|
13
|
+
testing = ["dep:kroma-testing", "storage", "test-serve", "kroma-sqlite/testing"]
|
|
14
14
|
# `test_serve::{serve, blocking}` alone: an axum router on an ephemeral localhost
|
|
15
15
|
# port. Separate from `testing` because a port contract's round-trip test needs
|
|
16
16
|
# the wire and not a database.
|
|
17
17
|
test-serve = []
|
|
18
18
|
# The `storage` capability: `HostStorage`, the two pools, and the `query` helper.
|
|
19
19
|
# Off by default, and that default is the point -- a module that declares no
|
|
20
|
-
# storage must not link
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
storage = ["dep:kroma-
|
|
20
|
+
# storage must not link SQLite, whose bundled amalgamation is 1.5 MB of machine
|
|
21
|
+
# code in a sidecar that never opens a database. Enabled through
|
|
22
|
+
# `kroma-module-sdk/storage` by the modules that do.
|
|
23
|
+
storage = ["dep:kroma-sqlite"]
|
|
24
24
|
|
|
25
25
|
[dependencies]
|
|
26
|
-
kroma-
|
|
27
|
-
kroma-
|
|
26
|
+
kroma-module-wire = { path = "../kroma-module-wire" }
|
|
27
|
+
kroma-sqlite = { path = "../kroma-sqlite", optional = true }
|
|
28
28
|
kroma-http = { path = "../kroma-http" }
|
|
29
29
|
kroma-testing = { path = "../kroma-testing", optional = true }
|
|
30
30
|
axum = { version = "0.8", features = ["macros", "ws"] }
|
|
@@ -8,8 +8,9 @@ use std::sync::Arc;
|
|
|
8
8
|
use axum::http::StatusCode;
|
|
9
9
|
use axum::response::Response;
|
|
10
10
|
|
|
11
|
-
use
|
|
12
|
-
|
|
11
|
+
use kroma_module_wire::{
|
|
12
|
+
Audience, EpisodeInfo, MatchCandidate, NotificationSpec, Permission, User,
|
|
13
|
+
};
|
|
13
14
|
|
|
14
15
|
use super::{Contribution, Event, LibraryFolders};
|
|
15
16
|
|
|
@@ -180,7 +181,7 @@ mod tests {
|
|
|
180
181
|
|
|
181
182
|
use super::*;
|
|
182
183
|
|
|
183
|
-
use
|
|
184
|
+
use kroma_module_wire::NotificationEvent;
|
|
184
185
|
|
|
185
186
|
use crate::testing;
|
|
186
187
|
|
|
@@ -37,7 +37,7 @@ use axum::response::{IntoResponse, Response};
|
|
|
37
37
|
use axum::Json;
|
|
38
38
|
|
|
39
39
|
pub use async_trait::async_trait;
|
|
40
|
-
pub use
|
|
40
|
+
pub use kroma_module_wire::{
|
|
41
41
|
ActionKind, ActionSpec, ActionStyle, Audience, NotificationCategory, NotificationEvent,
|
|
42
42
|
NotificationSpec, PushCategory,
|
|
43
43
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
//! declares no storage neither links SQLite nor can reach a row.
|
|
9
9
|
|
|
10
10
|
use axum::response::Response;
|
|
11
|
-
use
|
|
11
|
+
use kroma_sqlite::Pool;
|
|
12
12
|
|
|
13
13
|
use crate::{blocking, HostCtx};
|
|
14
14
|
|
|
@@ -56,7 +56,7 @@ mod tests {
|
|
|
56
56
|
|
|
57
57
|
#[tokio::test]
|
|
58
58
|
async fn query_hands_the_closure_its_own_pool() {
|
|
59
|
-
let pool =
|
|
59
|
+
let pool = kroma_sqlite::testing::temp_pool("host-query");
|
|
60
60
|
let n: Result<i64, Response> = query(&pool, |p| {
|
|
61
61
|
let conn = p.get()?;
|
|
62
62
|
let v: i64 = conn.query_row("SELECT 1 + 1", [], |r| r.get(0))?;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
use std::collections::BTreeMap;
|
|
5
5
|
use std::sync::Mutex;
|
|
6
6
|
|
|
7
|
-
use
|
|
7
|
+
use kroma_module_wire::{Audience, NotificationSpec};
|
|
8
8
|
|
|
9
9
|
/// One thing that went onto the event bus: the addressee (`None` for a
|
|
10
10
|
/// broadcast) and the event's topic.
|
|
@@ -20,8 +20,9 @@ pub use stub::StubHost;
|
|
|
20
20
|
|
|
21
21
|
#[cfg(test)]
|
|
22
22
|
mod fixtures {
|
|
23
|
-
use
|
|
24
|
-
|
|
23
|
+
use kroma_module_wire::{
|
|
24
|
+
EpisodeInfo, MatchCandidate, NotificationEvent, NotificationSpec, User,
|
|
25
|
+
};
|
|
25
26
|
|
|
26
27
|
pub fn candidate() -> MatchCandidate {
|
|
27
28
|
MatchCandidate {
|
|
@@ -8,8 +8,8 @@ use std::sync::Arc;
|
|
|
8
8
|
|
|
9
9
|
use axum::http::StatusCode;
|
|
10
10
|
use axum::response::Response;
|
|
11
|
-
use
|
|
12
|
-
use
|
|
11
|
+
use kroma_sqlite::Pool;
|
|
12
|
+
use kroma_module_wire::{Audience, NotificationSpec, Permission, User};
|
|
13
13
|
|
|
14
14
|
use super::log::{records_into_log, Log, Published};
|
|
15
15
|
use crate::{Event, HostCtx, HostStorage, LibraryFolders};
|
|
@@ -114,7 +114,7 @@ impl<H: HostCtx> HostCtx for Recording<H> {
|
|
|
114
114
|
query: &str,
|
|
115
115
|
kind: &str,
|
|
116
116
|
year: Option<u32>,
|
|
117
|
-
) -> Vec<
|
|
117
|
+
) -> Vec<kroma_module_wire::MatchCandidate> {
|
|
118
118
|
self.inner.metadata_candidates(query, kind, year)
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -122,7 +122,7 @@ impl<H: HostCtx> HostCtx for Recording<H> {
|
|
|
122
122
|
&self,
|
|
123
123
|
tmdb_id: u64,
|
|
124
124
|
season: u32,
|
|
125
|
-
) -> Vec<
|
|
125
|
+
) -> Vec<kroma_module_wire::EpisodeInfo> {
|
|
126
126
|
self.inner.metadata_episodes(tmdb_id, season)
|
|
127
127
|
}
|
|
128
128
|
fn contributions(&self, point: &str) -> Vec<crate::Contribution> {
|
|
@@ -203,7 +203,7 @@ mod tests {
|
|
|
203
203
|
host.db()
|
|
204
204
|
.get()
|
|
205
205
|
.unwrap()
|
|
206
|
-
.execute("
|
|
206
|
+
.execute("CREATE TABLE seen (id TEXT PRIMARY KEY)", [])
|
|
207
207
|
.unwrap();
|
|
208
208
|
}
|
|
209
209
|
}
|
|
@@ -8,9 +8,11 @@ use std::sync::{Arc, Mutex};
|
|
|
8
8
|
|
|
9
9
|
use axum::http::StatusCode;
|
|
10
10
|
use axum::response::Response;
|
|
11
|
-
use
|
|
12
|
-
use
|
|
13
|
-
use
|
|
11
|
+
use kroma_sqlite::testing::TempPool;
|
|
12
|
+
use kroma_sqlite::Pool;
|
|
13
|
+
use kroma_module_wire::{
|
|
14
|
+
Audience, EpisodeInfo, MatchCandidate, NotificationSpec, Permission, User,
|
|
15
|
+
};
|
|
14
16
|
use kroma_testing::TempDir;
|
|
15
17
|
|
|
16
18
|
use super::log::{records_into_log, Log, Published};
|
|
@@ -69,16 +71,18 @@ impl StubHost {
|
|
|
69
71
|
Self::in_dir(kroma_testing::temp_dir("stub-host"))
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
/// A host over a real, empty
|
|
73
|
-
///
|
|
74
|
-
///
|
|
74
|
+
/// A host over a real, empty SQLite database inside this host's own scratch
|
|
75
|
+
/// directory, plus the module-private store beside it. Neither carries a
|
|
76
|
+
/// schema: a test that needs the core tables hands a migrated pool to
|
|
77
|
+
/// [`with_pool`](Self::with_pool). `tag` only shapes that directory's name,
|
|
78
|
+
/// to make a stray one identifiable.
|
|
75
79
|
pub fn with_db(tag: &str) -> Self {
|
|
76
80
|
let data_dir = kroma_testing::temp_dir(tag);
|
|
77
|
-
let db =
|
|
81
|
+
let db = kroma_sqlite::open(&data_dir.path().join("kroma.db")).expect("open test db");
|
|
78
82
|
// `open`, like the real runtime: a module's own file carries no core
|
|
79
83
|
// schema, only what its own migrations put there.
|
|
80
84
|
let store =
|
|
81
|
-
|
|
85
|
+
kroma_sqlite::open(&data_dir.path().join("module.sqlite")).expect("open test store");
|
|
82
86
|
Self {
|
|
83
87
|
db: Some(db),
|
|
84
88
|
store: Some(store),
|
|
@@ -106,29 +110,28 @@ impl StubHost {
|
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
|
|
109
|
-
/// A host over a
|
|
110
|
-
///
|
|
111
|
-
///
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)
|
|
118
|
-
.expect("open test store");
|
|
113
|
+
/// A host over a core database the caller built, with the module-private
|
|
114
|
+
/// store beside it. The core schema is not this crate's to know: a test that
|
|
115
|
+
/// needs it hands over `kroma_db::testing::temp_pool`, whose directory this
|
|
116
|
+
/// host then keeps for as long as it lives.
|
|
117
|
+
pub fn with_core(core: TempPool) -> Self {
|
|
118
|
+
let (db, data_dir) = core.into_parts();
|
|
119
|
+
let store =
|
|
120
|
+
kroma_sqlite::open(&data_dir.path().join("module.sqlite")).expect("open test store");
|
|
119
121
|
Self {
|
|
120
|
-
db: Some(
|
|
122
|
+
db: Some(db),
|
|
121
123
|
store: Some(store),
|
|
122
|
-
..Self::
|
|
124
|
+
..Self::in_dir(data_dir)
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
127
|
|
|
126
|
-
/// A host whose MODULE store is `pool`, with a fresh core database
|
|
127
|
-
/// For a module testing its own tables: those live in its own file,
|
|
128
|
-
/// that seeded them has to hand them over as the store and not as
|
|
128
|
+
/// A host whose MODULE store is `pool`, with a fresh, empty core database
|
|
129
|
+
/// beside it. For a module testing its own tables: those live in its own file,
|
|
130
|
+
/// so a test that seeded them has to hand them over as the store and not as
|
|
131
|
+
/// the core.
|
|
129
132
|
pub fn with_store(pool: Pool) -> Self {
|
|
130
133
|
let data_dir = kroma_testing::temp_dir("stub-core");
|
|
131
|
-
let db =
|
|
134
|
+
let db = kroma_sqlite::open(&data_dir.path().join("kroma.db")).expect("open test db");
|
|
132
135
|
Self {
|
|
133
136
|
db: Some(db),
|
|
134
137
|
store: Some(pool),
|
|
@@ -136,9 +139,8 @@ impl StubHost {
|
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
|
|
139
|
-
/// Answer `session_user(token)` with `user`.
|
|
140
|
-
///
|
|
141
|
-
/// a genuine session still authenticates through the seam.
|
|
142
|
+
/// Answer `session_user(token)` with `user`. A token nobody seeded is an
|
|
143
|
+
/// unknown session, the way the real host answers one.
|
|
142
144
|
pub fn with_session(self, token: &str, user: User) -> Self {
|
|
143
145
|
self.sessions
|
|
144
146
|
.lock()
|
|
@@ -282,12 +284,7 @@ impl HostCtx for StubHost {
|
|
|
282
284
|
self.data_dir.path()
|
|
283
285
|
}
|
|
284
286
|
fn session_user(&self, token: &str) -> Option<User> {
|
|
285
|
-
|
|
286
|
-
return Some(u.clone());
|
|
287
|
-
}
|
|
288
|
-
kroma_db::session_user(self.db.as_ref()?, token)
|
|
289
|
-
.ok()
|
|
290
|
-
.flatten()
|
|
287
|
+
self.sessions.lock().unwrap().get(token).cloned()
|
|
291
288
|
}
|
|
292
289
|
fn require(&self, _user: &User, _perm: Permission) -> Result<(), Response> {
|
|
293
290
|
Ok(())
|
|
@@ -511,24 +508,19 @@ mod tests {
|
|
|
511
508
|
}
|
|
512
509
|
|
|
513
510
|
#[test]
|
|
514
|
-
fn
|
|
511
|
+
fn with_db_hands_out_a_writable_pool_and_never_the_same_file_twice() {
|
|
515
512
|
let a = StubHost::with_db("selftest");
|
|
516
513
|
let b = StubHost::with_db("selftest");
|
|
517
|
-
|
|
518
|
-
a
|
|
519
|
-
.get()
|
|
520
|
-
|
|
521
|
-
.execute("SELECT 1 FROM users LIMIT 0", [])
|
|
522
|
-
.unwrap();
|
|
514
|
+
let ddl = "CREATE TABLE settings (key TEXT PRIMARY KEY, value TEXT NOT NULL)";
|
|
515
|
+
for host in [&a, &b] {
|
|
516
|
+
host.db().get().unwrap().execute(ddl, []).unwrap();
|
|
517
|
+
}
|
|
523
518
|
// Separate: a row in one is not in the other. Two tests running in
|
|
524
519
|
// parallel threads of one process must not share a database.
|
|
525
520
|
a.db()
|
|
526
521
|
.get()
|
|
527
522
|
.unwrap()
|
|
528
|
-
.execute(
|
|
529
|
-
"INSERT INTO settings (key, value, updated_at) VALUES ('k', 'v', 'now')",
|
|
530
|
-
[],
|
|
531
|
-
)
|
|
523
|
+
.execute("INSERT INTO settings (key, value) VALUES ('k', 'v')", [])
|
|
532
524
|
.unwrap();
|
|
533
525
|
let n: i64 = b
|
|
534
526
|
.db()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "kroma-module-macros"
|
|
3
|
-
version = "0.1.40-canary.
|
|
3
|
+
version = "0.1.40-canary.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.88"
|
|
6
6
|
description = "Proc-macros for KROMA modules: embedded_module!() discovers a module's module.json + icon at compile time so the MODULE const is one line."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "kroma-module-manifest"
|
|
3
|
-
version = "0.1.40-canary.
|
|
3
|
+
version = "0.1.40-canary.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.88"
|
|
6
6
|
description = "Low-level module manifest/registry/embedded types (below kroma-engine). Modules use the kroma-module-sdk facade; this is the shared manifest layer engine/kernel/wasm build on."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "kroma-module-runtime"
|
|
3
|
-
version = "0.1.40-canary.
|
|
3
|
+
version = "0.1.40-canary.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.88"
|
|
6
6
|
description = "The out-of-process module runtime: each module ships as its own native binary that opens the shared SQLite, serves its routes on a local port, and reaches the host over a small IPC. `serve(...)` is the whole main()."
|
|
@@ -8,9 +8,9 @@ license = "MIT"
|
|
|
8
8
|
|
|
9
9
|
[features]
|
|
10
10
|
# The `storage` capability: the module's own database plus the scoped core one.
|
|
11
|
-
# Off by default -- a module that declares no storage must not link
|
|
12
|
-
#
|
|
13
|
-
storage = ["dep:kroma-
|
|
11
|
+
# Off by default -- a module that declares no storage must not link SQLite, whose
|
|
12
|
+
# bundled amalgamation is most of a sidecar's size.
|
|
13
|
+
storage = ["dep:kroma-sqlite", "kroma-module-host/storage"]
|
|
14
14
|
|
|
15
15
|
[dependencies]
|
|
16
16
|
# The host contract the module code is written against (HostCtx / ServerModule /
|
|
@@ -20,9 +20,9 @@ kroma-module-host = { path = "../kroma-module-host" }
|
|
|
20
20
|
# Only under `storage`: the module's own database, and the core one behind the
|
|
21
21
|
# grant its manifest declared. WAL is multi-process, so both are opened here
|
|
22
22
|
# rather than proxied.
|
|
23
|
-
kroma-
|
|
23
|
+
kroma-sqlite = { path = "../kroma-sqlite", optional = true }
|
|
24
24
|
# User / Permission for local require() checks.
|
|
25
|
-
kroma-
|
|
25
|
+
kroma-module-wire = { path = "../kroma-module-wire" }
|
|
26
26
|
kroma-http = { path = "../kroma-http" }
|
|
27
27
|
axum = { version = "0.8", features = ["macros", "ws"] }
|
|
28
28
|
tokio = { version = "1", features = ["full"] }
|
|
@@ -15,7 +15,7 @@ use std::sync::{Arc, RwLock};
|
|
|
15
15
|
|
|
16
16
|
use axum::http::StatusCode;
|
|
17
17
|
use axum::response::{IntoResponse, Response};
|
|
18
|
-
use
|
|
18
|
+
use kroma_module_wire::{Permission, User};
|
|
19
19
|
use kroma_module_host::host_token::{require_host_token, HostToken};
|
|
20
20
|
use kroma_module_host::{json_error, Event, HostCtx, ServerModule};
|
|
21
21
|
|
|
@@ -49,13 +49,13 @@ impl Env {
|
|
|
49
49
|
/// Absent or unreadable is the empty grant: a pool that answers nothing,
|
|
50
50
|
/// never an unscoped one.
|
|
51
51
|
#[cfg(feature = "storage")]
|
|
52
|
-
fn grant(&self) ->
|
|
52
|
+
fn grant(&self) -> kroma_sqlite::Grant {
|
|
53
53
|
let Ok(json) = std::env::var("KROMA_MODULE_GRANT") else {
|
|
54
|
-
return
|
|
54
|
+
return kroma_sqlite::Grant::none();
|
|
55
55
|
};
|
|
56
56
|
serde_json::from_str(&json).unwrap_or_else(|error| {
|
|
57
57
|
tracing::error!(%error, "core sent a storage grant this build cannot read; denying all");
|
|
58
|
-
|
|
58
|
+
kroma_sqlite::Grant::none()
|
|
59
59
|
})
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -82,9 +82,9 @@ struct Inner {
|
|
|
82
82
|
module_id: String,
|
|
83
83
|
data_dir: PathBuf,
|
|
84
84
|
#[cfg(feature = "storage")]
|
|
85
|
-
store:
|
|
85
|
+
store: kroma_sqlite::Pool,
|
|
86
86
|
#[cfg(feature = "storage")]
|
|
87
|
-
core:
|
|
87
|
+
core: kroma_sqlite::Pool,
|
|
88
88
|
core_url: String,
|
|
89
89
|
host_token: String,
|
|
90
90
|
services: RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
|
|
@@ -102,9 +102,9 @@ impl RemoteHost {
|
|
|
102
102
|
// `open`, not `init`: the module's own file has no core schema
|
|
103
103
|
// in it, only whatever its own `migrations()` create below.
|
|
104
104
|
#[cfg(feature = "storage")]
|
|
105
|
-
store:
|
|
105
|
+
store: kroma_sqlite::open(&env.store_path())?,
|
|
106
106
|
#[cfg(feature = "storage")]
|
|
107
|
-
core:
|
|
107
|
+
core: kroma_sqlite::init_scoped(&env.db_path, &env.module_id, &env.grant())?,
|
|
108
108
|
core_url: env.core_url.clone(),
|
|
109
109
|
host_token: env.host_token.clone(),
|
|
110
110
|
services: RwLock::new(HashMap::new()),
|
|
@@ -143,11 +143,11 @@ impl RemoteHost {
|
|
|
143
143
|
|
|
144
144
|
#[cfg(feature = "storage")]
|
|
145
145
|
impl kroma_module_host::HostStorage for RemoteHost {
|
|
146
|
-
fn db(&self) -> &
|
|
146
|
+
fn db(&self) -> &kroma_sqlite::Pool {
|
|
147
147
|
&self.inner.core
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
fn store(&self) -> &
|
|
150
|
+
fn store(&self) -> &kroma_sqlite::Pool {
|
|
151
151
|
&self.inner.store
|
|
152
152
|
}
|
|
153
153
|
}
|
|
@@ -319,12 +319,12 @@ impl HostCtx for RemoteHost {
|
|
|
319
319
|
query: &str,
|
|
320
320
|
kind: &str,
|
|
321
321
|
year: Option<u32>,
|
|
322
|
-
) -> Vec<
|
|
322
|
+
) -> Vec<kroma_module_wire::MatchCandidate> {
|
|
323
323
|
let mut call = self.callback().query("q", query).query("kind", kind);
|
|
324
324
|
if let Some(year) = year {
|
|
325
325
|
call = call.query("year", year.to_string());
|
|
326
326
|
}
|
|
327
|
-
call.get_json::<Vec<
|
|
327
|
+
call.get_json::<Vec<kroma_module_wire::MatchCandidate>>(
|
|
328
328
|
&self.host_url("metadata-search"),
|
|
329
329
|
)
|
|
330
330
|
.unwrap_or_default()
|
|
@@ -334,11 +334,11 @@ impl HostCtx for RemoteHost {
|
|
|
334
334
|
&self,
|
|
335
335
|
tmdb_id: u64,
|
|
336
336
|
season: u32,
|
|
337
|
-
) -> Vec<
|
|
337
|
+
) -> Vec<kroma_module_wire::EpisodeInfo> {
|
|
338
338
|
self.callback()
|
|
339
339
|
.query("tmdbId", tmdb_id.to_string())
|
|
340
340
|
.query("season", season.to_string())
|
|
341
|
-
.get_json::<Vec<
|
|
341
|
+
.get_json::<Vec<kroma_module_wire::EpisodeInfo>>(&self.host_url("metadata-episodes"))
|
|
342
342
|
.unwrap_or_default()
|
|
343
343
|
}
|
|
344
344
|
|
|
@@ -541,7 +541,7 @@ fn apply_module_migrations(
|
|
|
541
541
|
let migrations = module.migrations();
|
|
542
542
|
if !migrations.is_empty() {
|
|
543
543
|
let conn = host.store().get()?;
|
|
544
|
-
|
|
544
|
+
kroma_sqlite::apply_migrations(&conn, migrations)?;
|
|
545
545
|
}
|
|
546
546
|
}
|
|
547
547
|
Ok(())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "kroma-module-sdk"
|
|
3
|
-
version = "0.1.40-canary.
|
|
3
|
+
version = "0.1.40-canary.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.88"
|
|
6
6
|
description = "The KROMA module SDK: the single crate every server module depends on. Re-exports the manifest layer plus the engine/host/domain/http/db surface, so modules never depend on core crates directly."
|
|
@@ -13,12 +13,10 @@ kroma-module-manifest = { path = "../kroma-module-manifest" }
|
|
|
13
13
|
kroma-module-macros = { path = "../kroma-module-macros" }
|
|
14
14
|
# Host contract: ServerModule, HostCtx, service/port resolution, async_trait.
|
|
15
15
|
kroma-module-host = { path = "../kroma-module-host" }
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
# publishes an mDNS beacon has no business linking it.
|
|
19
|
-
kroma-domain = { path = "../kroma-domain" }
|
|
16
|
+
# What a sidecar links: the wire types, the HTTP client, the SQLite pool.
|
|
17
|
+
kroma-module-wire = { path = "../kroma-module-wire" }
|
|
20
18
|
kroma-http = { path = "../kroma-http" }
|
|
21
|
-
kroma-
|
|
19
|
+
kroma-sqlite = { path = "../kroma-sqlite", optional = true }
|
|
22
20
|
kroma-primitives = { path = "../kroma-primitives" }
|
|
23
21
|
# `testing::{TempDir, temp_dir}`, the scratch dir every module test writes in.
|
|
24
22
|
kroma-testing = { path = "../kroma-testing", optional = true }
|
|
@@ -35,15 +33,11 @@ anyhow = { version = "1" }
|
|
|
35
33
|
# Everything a module's tests reach: the `StubHost` double, `test_serve`, a
|
|
36
34
|
# throwaway pool and a self-deleting scratch dir. Never `engine`: a round-trip
|
|
37
35
|
# test must not link the whole core.
|
|
38
|
-
testing = ["kroma-module-host/testing", "storage", "kroma-
|
|
36
|
+
testing = ["kroma-module-host/testing", "storage", "kroma-sqlite/testing", "dep:kroma-testing"]
|
|
39
37
|
# The `storage` capability: `host::HostStorage` and the `db` facade. A module
|
|
40
38
|
# enables it when its `module.json` declares `storage`, and only then does its
|
|
41
39
|
# binary link SQLite -- which is 1.5 MB of the 3.3 MB a sidecar used to be.
|
|
42
|
-
storage = ["dep:kroma-
|
|
43
|
-
# The `engine` facade (`engine::services`, `engine::model`): the core's own
|
|
44
|
-
# business logic, for the two modules that orchestrate it. It pulls `kroma-db`
|
|
45
|
-
# with it, because the services it exposes are written against the pool.
|
|
46
|
-
|
|
40
|
+
storage = ["dep:kroma-sqlite", "kroma-module-host/storage"]
|
|
47
41
|
|
|
48
42
|
[lints.rust]
|
|
49
|
-
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(feature, values("engine"))'] }
|
|
43
|
+
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(feature, values("core"))', 'cfg(feature, values("domain"))', 'cfg(feature, values("engine"))'] }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//! The KROMA module SDK: the ONE crate a server module depends on.
|
|
2
2
|
//!
|
|
3
|
-
//! A module must not depend on `kroma-engine`, `kroma-db`, `kroma-domain
|
|
4
|
-
//! `kroma-http` directly. This facade re-exports the manifest layer at the crate
|
|
3
|
+
//! A module must not depend on `kroma-engine`, `kroma-db`, `kroma-domain`,
|
|
4
|
+
//! `kroma-sqlite`, `kroma-module-wire` or `kroma-http` directly. This facade re-exports the manifest layer at the crate
|
|
5
5
|
//! root (`EmbeddedModule`, `ModuleManifest`, `Registry`, ...) and mirrors the
|
|
6
6
|
//! host / engine / domain / http / db / primitives surface under submodules, so a
|
|
7
7
|
//! module writes `kroma_module_sdk::engine::state::SharedState` instead of
|
|
@@ -36,9 +36,14 @@ pub mod engine {
|
|
|
36
36
|
pub use kroma_engine::*;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
///
|
|
39
|
+
/// What the host and a module exchange: the session user and its permissions,
|
|
40
|
+
/// notifications and their audience, metadata answers. Behind the `domain`
|
|
41
|
+
/// feature, the whole of `kroma-domain` on top, for a first-party module that
|
|
42
|
+
/// reads the core's own shapes.
|
|
40
43
|
pub mod domain {
|
|
44
|
+
#[cfg(feature = "domain")]
|
|
41
45
|
pub use kroma_domain::*;
|
|
46
|
+
pub use kroma_module_wire::*;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
/// The outbound HTTP client (`Fetch`, `Response`).
|
|
@@ -46,12 +51,24 @@ pub mod http {
|
|
|
46
51
|
pub use kroma_http::*;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
/// Direct SQLite access
|
|
50
|
-
///
|
|
51
|
-
/// `host::HostStorage`, not
|
|
54
|
+
/// Direct SQLite access: the pool, the grant and a module's own migrations.
|
|
55
|
+
/// Behind the `storage` feature, which a module turns on when its `module.json`
|
|
56
|
+
/// declares `storage`; the pools themselves come from `host::HostStorage`, not
|
|
57
|
+
/// from here. Under `engine`, every query the core makes of its own database as
|
|
58
|
+
/// well.
|
|
52
59
|
#[cfg(feature = "storage")]
|
|
53
60
|
pub mod db {
|
|
61
|
+
#[cfg(feature = "engine")]
|
|
54
62
|
pub use kroma_db::*;
|
|
63
|
+
pub use kroma_sqlite::{
|
|
64
|
+
apply_migrations, init_scoped, open, open_with, Grant, Pool, PoolInner, PooledConn,
|
|
65
|
+
};
|
|
66
|
+
#[cfg(all(any(test, feature = "testing"), not(feature = "core")))]
|
|
67
|
+
pub use kroma_sqlite::testing;
|
|
68
|
+
/// `temp_pool` stamps the core schema, for a grant test that has to run
|
|
69
|
+
/// against the real tables rather than a copy of them.
|
|
70
|
+
#[cfg(all(any(test, feature = "testing"), feature = "core"))]
|
|
71
|
+
pub use kroma_db::testing;
|
|
55
72
|
}
|
|
56
73
|
|
|
57
74
|
/// Small shared primitives (`now_ms`, ...).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "kroma-module-wire"
|
|
3
|
+
version = "0.1.40-canary.3"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
rust-version = "1.88"
|
|
6
|
+
description = "The JSON a module and the host exchange: the session user, notifications and their audience, metadata answers. Serde only."
|
|
7
|
+
license = "MIT"
|
|
8
|
+
|
|
9
|
+
[dependencies]
|
|
10
|
+
serde = { version = "1", features = ["derive"] }
|