1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Ppoppo SDK shared primitives — internal mechanism for the
//! Ppoppo SDK family (`pas-external`, future `pas-plims`, `pcs-external`).
//!
//! ## Stability — not a stable public API
//!
//! This crate is published to crates.io as a transitive dependency of
//! the SDK family above (cargo enforces "all transitive deps of a
//! published crate must themselves be published"). It is **not** a
//! stable public API; it carries no SemVer guarantees beyond the
//! current minor and may rearrange shapes between minors. Consume
//! the SDK crates that re-export from it (`pas-external::*`,
//! eventually `pas-plims::*` / `pcs-external::*`); do not depend on
//! `ppoppo-sdk-core` directly from a 3rd-party application.
//!
//! Phase A foundation (RFC `RFC_2026-05-08_app-credential-collapse.md`)
//! — collapses the verifier port + audit trait + session-liveness port +
//! discovery primitive + perimeter Bearer-auth Layer kit + identity
//! types out of `pas-external` so multiple SDK crates and 1st-party
//! services (chat-auth, chat-api) all consume the same primitives.
//!
//! ## Surface (Slice 1a)
//!
//! - `error::SdkCoreError` — narrow error type for sdk-core primitives.
//! - `types::{Ppnum, PpnumId, SessionId, UserId, KeyId}` — SDK-shared
//! identity types. `Ppnum::TryFrom<String>` is the validated boundary.
//! - `audit::*` — `AuditSink` trait + `AuditEvent` + `VerifyErrorKind` +
//! `IdTokenFailureKind` + `RateLimiter` trait + `RateLimitKey` +
//! `compose_source_id` + `compose_id_token_source_id`. Plus the
//! in-tree utility impls (`NoopAuditSink`, `MemoryAuditSink`,
//! `MemoryRateLimiter`, `RateLimitedAuditSink`) — utility impls live
//! here too because the audit module is one cohesive unit.
//! - `session_liveness::{SessionLiveness, SessionLivenessError}` —
//! per-request L2 row liveness port. Wired into the verifier slot.
//! Trait-only (no `cipher`/`liveness` AES wrapper code — that stays
//! in pas-external as a feature-gated submodule).
//!
//! ## Surface (Slice 1b — populated when verifier cohesive group lands)
//!
//! - `verifier::*` — `BearerVerifier` trait + `JwtVerifier` impl +
//! `MemoryBearerVerifier` + `VerifiedClaims` + `VerifyConfig` +
//! `VerifyError` + `JwksCache`. Audit decision E (cohesive group —
//! no trait/impl split across crates).
//!
//! ## Surface (Slice 2 — populated)
//!
//! - `discovery::{Discovery, DiscoveryError, fetch_discovery}` — OIDC
//! discovery document fetch (`<issuer>/.well-known/openid-configuration`).
//! RFC 8414 §3.3 issuer-mismatch defense lives here. Gated on
//! `well-known-fetch` (HTTP fetch + URL types).
//!
//! ## Surface (Slice 4 — populated)
//!
//! - `bearer::*` — perimeter Bearer-auth Layer kit. `AuthProvider<S>`
//! port + `BearerAuthLayer<Sess, P>` tower::Layer + `BearerAuthConfig`
//! + `VerifyError` + `MemoryAuthProvider<S>` (test-support). Gated on
//! `axum` feature. 1st-party services (chat-auth) import direct from
//! `ppoppo_sdk_core::bearer::*` (audit decision B); 3rd-party
//! consumers (RCW/CTW) reach the same kit through
//! `pas_external::bearer::*` re-export (audit decision D).
//!
//! ## Surface (Phase E — populated)
//!
//! - `token_cache::{TokenCache, TokenCacheConfig, TokenSource, TokenCacheError,
//! ClientCredentialsSource}` — JWT retention layer with single-flight
//! refresh. `TokenCache` owns a `Box<dyn TokenSource>`; the built-in
//! `ClientCredentialsSource` covers the OAuth2 `client_credentials` grant.
//! Gated on `token-cache` (cache+trait) and `client-credentials` (HTTP source).
//! - `interceptor::{AuthInterceptor, BearerCredential}` — tonic sync
//! `Interceptor` that attaches `Authorization: Bearer <token>` per outgoing
//! gRPC call. Constructed from a pre-fetched `BearerCredential` (one instance
//! per call). Gated on `tonic-interceptor`.
//! - `retry::retry_after` — extract `retry-after` integer-seconds hint from
//! a `tonic::Status`'s metadata. Counterpart of chat-api's
//! `resource_exhausted_with_retry_after` producer. Gated on
//! `tonic-interceptor` (shares the tonic dep — no extra transitive
//! weight for crates that already enable the interceptor). RFC
//! 2026-05-12 D5.
//! - `grpc::{PathPrefixChannel, Error, classify_status}` — the two remaining
//! gRPC-client legs shared by the gRPC SDK family (`pas-plims`,
//! `pcs-external`): the GKE Ingress path-prefix channel + the shared
//! `Status`→`Error` classifier (the family retry taxonomy, one home). Both
//! SDKs re-export `grpc::Error` as their public error type. Gated on
//! `grpc-client` (adds tonic transport/TLS + `http` + `tower-service` on
//! top of the interceptor/token-cache/retry legs). Reached via the
//! `grpc::` path — `grpc::Error` is deliberately NOT flat-re-exported: a
//! root-level `Error` would misread as sdk-core's own `error::SdkCoreError`
//! (a semantic-clarity choice — the names differ, so not a real clash; same
//! module-path convention as bearer/verifier).
//!
//! ## Out of scope (later phases)
//!
//! - `scopes::*` — sealed-trait family parent for SDK-specific scope marker types.
// Top-level re-exports — keep narrow (≤ 25 public names budget for Phase A).
pub use SdkCoreError;
pub use ;
pub use ;
pub use ;
pub use MemoryAuditSink;
// Verifier cohesive group (audit decision E + G).
pub use ;
pub use ;
pub use MemoryBearerVerifier;
// Discovery primitive (Slice 2).
pub use ;
// NOTE: bearer kit (`AuthProvider`, `BearerAuthLayer`, `BearerAuthConfig`,
// `VerifyError`, `MemoryAuthProvider`) is intentionally NOT flat-re-exported
// at the crate root. The bearer-side `VerifyError` would collide with the
// verifier-side `VerifyError`; rather than rename one, consumers import
// through the explicit `ppoppo_sdk_core::bearer::*` module path so the
// "this is the perimeter Layer kit, not the token verifier" semantic is
// visible at the import site (audit decision F — flat module under bearer
// itself; keep parent namespaces clean).