diff --git a/Cargo.toml b/Cargo.toml index e87c094..77a0468 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -138,6 +138,12 @@ tracing-subscriber = { version = "0.3", default-features = false, features = [ "fmt", "env-filter", ] } +# Mirror the optional server-only deps so the `#[cfg(any(feature = "server", +# test))]` server modules (indexing/appview/oauth) compile and their tests run +# under a plain `cargo test`, not only `--features server`. +axum-extra = { version = "0.10", features = ["cookie"] } +base64 = "0.22" +keyring = "3" [build-dependencies] dotenvy = "0.15" diff --git a/e2e/tests/home.spec.ts b/e2e/tests/home.spec.ts index b87eafa..ff43c64 100644 --- a/e2e/tests/home.spec.ts +++ b/e2e/tests/home.spec.ts @@ -43,7 +43,7 @@ test('home thing cards remain readable at narrow widths', async ({ page }) => { await expect(page.getByRole('img', { name: 'Blueprint placeholder for missing preview media' })).toHaveCount(2); }); -test('foundation route shows PM-38 primitives and reusable states', async ({ page }) => { +test('foundation route shows foundation primitives and reusable states', async ({ page }) => { await page.goto('/foundation'); await expect(page.getByRole('heading', { name: 'Foundation', exact: true })).toBeVisible(); @@ -61,5 +61,5 @@ test('home page no longer uses workflow roadmap demo copy as the product surface await expect(page.getByText('Project lexicon')).toHaveCount(0); await expect(page.getByText('Jira and Confluence')).toHaveCount(0); await expect(page.getByText('Polytoken workflow')).toHaveCount(0); - await expect(page.getByText('PM-38 foundation')).toHaveCount(0); + await expect(page.getByText('Front-end foundation')).toHaveCount(0); }); diff --git a/src/appview/actor.rs b/src/appview/actor.rs index 3a0fbe0..67fb5c2 100644 --- a/src/appview/actor.rs +++ b/src/appview/actor.rs @@ -1,6 +1,6 @@ //! `space.polymodel.actor.*` read endpoint handlers: `getProfile` (typed union //! of polymodel profileView / app.bsky profileViewDetailed) and `getSession` -//! (PM-9 identity primitive; PM-26 returns the unauthenticated marker). +//! (the session identity primitive). use axum::extract::State; use jacquard::identity::PublicResolver; @@ -66,8 +66,8 @@ pub(super) async fn get_profile( } /// Fetch `app.bsky.actor.getProfile` from `https://public.api.bsky.app` via the -/// unauthenticated jacquard client. This is the only network path in PM-26's -/// read endpoints; tests exercise union-variant construction without it. +/// unauthenticated jacquard client. This is the only network path in the read +/// endpoints; tests exercise union-variant construction without it. async fn fetch_bsky_profile( state: &AppState, ident: &AtIdentifier, diff --git a/src/appview/mod.rs b/src/appview/mod.rs index 10a767f..d0e0038 100644 --- a/src/appview/mod.rs +++ b/src/appview/mod.rs @@ -1,4 +1,4 @@ -//! PM-26 XRPC read endpoints (appview query layer). +//! XRPC read endpoints (appview query layer). //! //! All read endpoints are backed by the SQLite projection — records in //! `record_json`, handles in `identities`, profiles in `profiles` — so the read @@ -6,9 +6,8 @@ //! [`IntoRouter`] and share [`AppState`] (SQLite pool + identity resolver + bsky //! client). //! -//! Scope (PM-26): read endpoints only. Authenticated `getSession`/viewer state is -//! PM-27; the client appview/session UX is PM-45; the SSR bridge is PM-46; the -//! PDS passthrough proxy is PM-47. +//! Not yet implemented: the SSR bridge (PM-46) and the PDS passthrough proxy +//! (PM-47). pub mod error; pub mod state; @@ -51,7 +50,7 @@ pub fn router() -> Router { .merge(GetProfileRequest::into_router(actor::get_profile)) // getSession takes no parameters, so it bypasses ExtractXrpc (which // decodes the query string; a unit-struct request from an empty query is - // rejected by serde_html_form). Identity comes from the session, PM-27. + // rejected by serde_html_form). Identity comes from the session. .route( GetSessionRequest::PATH, axum::routing::get(actor::get_session), diff --git a/src/appview/state.rs b/src/appview/state.rs index c17bbaf..4045810 100644 --- a/src/appview/state.rs +++ b/src/appview/state.rs @@ -1,13 +1,13 @@ //! Shared appview handler state. //! -//! PM-26 read endpoints are backed entirely by the SQLite projection (records +//! Read endpoints are backed entirely by the SQLite projection (records //! live in `record_json`, handles in `identities`, profiles in `profiles`). The //! read path therefore needs no Hydrant handle. `resolver` canonicalizes handle //! authorities to DIDs for `getProfile`; `bsky` fetches the //! `app.bsky.actor.defs#profileViewDetailed` union variant from the public //! AppView for actors with no polymodel profile. //! -//! PM-27 adds the confidential OAuth client, single-origin web config, and +//! It also carries the confidential OAuth client, single-origin web config, and //! private cookie-jar key. `AppState` is the Axum router state type (local, so //! the [`FromRef`] impls for [`OAuthWebConfig`] and the cookie [`Key`] satisfy //! the orphan rule); it is cheaply `Clone` (pool/resolver/oauth are @@ -28,7 +28,7 @@ use crate::oauth::{OAuthBootstrap, SqliteAuthStore}; /// State shared by all XRPC read handlers and the OAuth routes. #[derive(Clone)] pub struct AppState { - /// SQLite projection (PM-25): content, social counts, profiles, identities. + /// SQLite projection: content, social counts, profiles, identities. pub pool: SqlitePool, /// Handle→DID resolution for `getProfile` actor canonicalization. pub resolver: PublicResolver, @@ -36,7 +36,7 @@ pub struct AppState { /// (`https://public.api.bsky.app`) for the bluesky-only profile variant. /// `Arc`-wrapped because `BasicClient` (`Agent`) is not `Clone`. pub bsky: Arc, - /// Confidential OAuth client (PM-27) over the SQLite auth store. + /// Confidential OAuth client over the SQLite auth store. pub oauth: Arc>, /// Single-origin OAuth web config (cookie name + route paths). pub oauth_config: OAuthWebConfig, diff --git a/src/appview/tests.rs b/src/appview/tests.rs index c980c6f..75529c8 100644 --- a/src/appview/tests.rs +++ b/src/appview/tests.rs @@ -1,4 +1,4 @@ -//! Tests for the PM-26 appview read layer. +//! Tests for the appview read layer. //! //! The read helpers are exercised against an in-memory SQLite database with the //! migrations applied and representative rows seeded directly (the projection is diff --git a/src/appview/views.rs b/src/appview/views.rs index 483fbe4..8117dd1 100644 --- a/src/appview/views.rs +++ b/src/appview/views.rs @@ -1,4 +1,4 @@ -//! SQLite read queries and generated-view builders for the PM-26 read endpoints. +//! SQLite read queries and generated-view builders for the read endpoints. //! //! Records come from the `record_json` column (written by the projection); the //! required `record` field on thing/model/part views is built from it via diff --git a/src/client.rs b/src/client.rs index d699892..c69bfb5 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,7 +3,7 @@ //! Polymodel deliberately uses this thin client rather than Jacquard's //! credential/session `BasicClient` path: appview reads should target this //! server's `/xrpc/space.polymodel.*` routes and rely on browser-managed -//! cookies once PM-27 wires OAuth sessions. Callers send generated payload +//! cookies for OAuth sessions. Callers send generated payload //! request values, for example `client.send(GetSession).await?.into_output()`. //! Identity resolution is delegated to Jacquard's resolver over the same //! injected HTTP transport; this keeps Polymodel's appview client thin without diff --git a/src/foundation.rs b/src/foundation.rs index 995d958..beeb334 100644 --- a/src/foundation.rs +++ b/src/foundation.rs @@ -7,7 +7,7 @@ pub(crate) fn Foundation() -> Element { rsx! { main { class: "browse-page product-shell", header { class: "product-header", - div { class: "product-kicker", "PM-38 foundation" } + div { class: "product-kicker", "Front-end foundation" } div { class: "product-header-row", div { h1 { "Foundation" } @@ -24,7 +24,7 @@ pub(crate) fn Foundation() -> Element { div { class: "foundation-hero-copy", p { class: "eyebrow", "Token and asset check" } h2 { "Blueprint styling foundation" } - p { "This route keeps PM-38 primitives visible without making implementation scaffolding the product home." } + p { "This route keeps the front-end primitives visible without making implementation scaffolding the product home." } div { class: "button-row", button { class: "button button-primary", "Primary action" } button { class: "button button-ghost", "Ghost action" } diff --git a/src/indexing/config.rs b/src/indexing/config.rs index c2254f1..0a14052 100644 --- a/src/indexing/config.rs +++ b/src/indexing/config.rs @@ -20,7 +20,7 @@ pub struct ServerConfig { /// Public origin of this server, e.g. `https://polymodel.example.com`. /// /// The OAuth `client_id` is `{base_url}/oauth-client-metadata.json` and the - /// redirect URI is `{base_url}/oauth/callback` (PM-27). When unset, bootstrap + /// redirect URI is `{base_url}/oauth/callback`. When unset, bootstrap /// defaults the OAuth client origin to `https://polymodel.space`, a functional /// hosted client; set `POLYMODEL_BASE_URL` for local or alternate origins. pub base_url: Option, diff --git a/src/main.rs b/src/main.rs index 22f715b..a06c372 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,12 +19,12 @@ mod viewer_route; // Frontend compile-time configuration, generated by build.rs from POLYMODEL_*. mod env; // Server-only indexing infrastructure (Hydrant firehose + SQLite projection). -#[cfg(feature = "server")] +#[cfg(any(feature = "server", test))] mod indexing; -// Server-only XRPC read endpoints (appview query layer, PM-26). -#[cfg(feature = "server")] +// Server-only XRPC read endpoints (appview query layer). +#[cfg(any(feature = "server", test))] mod appview; -#[cfg(feature = "server")] +#[cfg(any(feature = "server", test))] mod oauth; use browse::Browse; diff --git a/src/mesh/mod.rs b/src/mesh/mod.rs index 82ecf5e..c584ab4 100644 --- a/src/mesh/mod.rs +++ b/src/mesh/mod.rs @@ -4,14 +4,14 @@ //! [`three_d_asset::TriMesh`] that carries format provenance, unit assumptions, and a //! camera framing hint. STL is parsed from in-memory bytes (no filesystem), so this //! module compiles to `wasm32-unknown-unknown` and can be consumed by any future -//! renderer ([PM-14 research](https://radiant-industries.atlassian.net/wiki/spaces/PM/pages/131340)). +//! renderer ([format ingestion research](https://radiant-industries.atlassian.net/wiki/spaces/PM/pages/131340)). //! //! Scope is STL-only for now; OBJ/glTF/3MF direct upload is tracked in PM-23. -// This module is a renderer-agnostic ingestion foundation: it is consumed by PM-19 -// (Dioxus scaffold) and PM-20/PM-21 (renderers), none of which are wired into the -// binary's main path yet. Its public surface is therefore intentionally unused at -// present, so dead-code analysis is relaxed here until those tickets land. +// This module is a renderer-agnostic ingestion foundation: it is consumed by the +// Dioxus viewer scaffold and the renderer, which are not yet wired into the +// binary's main path. Its public surface is therefore intentionally unused at +// present, so dead-code analysis is relaxed here. #![allow(dead_code)] pub mod contract; diff --git a/src/oauth/mod.rs b/src/oauth/mod.rs index 6243d79..588b5ef 100644 --- a/src/oauth/mod.rs +++ b/src/oauth/mod.rs @@ -243,7 +243,7 @@ where } // =========================================================================== -// Confidential OAuth client bootstrap (PM-27) +// Confidential OAuth client bootstrap // =========================================================================== use anyhow::Context as _; diff --git a/src/viewer.rs b/src/viewer.rs index ecbb015..49f2e8f 100644 --- a/src/viewer.rs +++ b/src/viewer.rs @@ -2,7 +2,7 @@ //! //! The viewer renders committed STL assets with [`three-d`] on a Dioxus-owned //! canvas. The design (see the "STL viewer renderer decision" Confluence note) -//! rests on three production decisions made when closing PM-20/PM-22: +//! rests on three production decisions: //! //! * **One WebGL2 session per page mount.** The session is retained across //! model switches and only the GPU mesh resources are replaced in place