packages feed

keiro-core 0.8.0.0 → 0.9.0.0

raw patch · 3 files changed

+60/−3 lines, 3 filesdep ~keikiPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: keiki

API changes (from Hackage documentation)

+ Keiro.Codec.IdDomain: parseKindIdV7Text :: forall (prefix :: Symbol). ValidPrefix prefix => Text -> Either IdDomainFailure (KindID prefix)
+ Keiro.Codec.IdDomain: parseKindIdV7Value :: forall (prefix :: Symbol). ValidPrefix prefix => Value -> Parser (KindID prefix)

Files

CHANGELOG.md view
@@ -6,6 +6,22 @@  ## [Unreleased] +## 0.9.0.0 — 2026-08-02++### Breaking Changes++- Requires `keiki >=0.8 && <0.9`, replacing the previous `>=0.7 && <0.8` bound.+  Consumers must solve for the same Keiki major; verification results and+  rendering may differ from the 0.7 line.++### New Features++- Adds `parseKindIdV7Text` and `parseKindIdV7Value` to+  `Keiro.Codec.IdDomain`. Both construct a prefix-indexed `KindID` only after+  the frozen TypeID-v7 policy succeeds; the Aeson entry point preserves the+  owning JSON field path for malformed, wrong-prefix, non-canonical, and non-v7+  failures.+ ## 0.8.0.0 — 2026-08-01  No changes this release. Version moves with the package set.
keiro-core.cabal view
@@ -1,6 +1,6 @@ cabal-version:   3.0 name:            keiro-core-version:         0.8.0.0+version:         0.9.0.0 synopsis:        Core contracts for Keiro packages description:   Stable stream, codec, event-stream, and integration-event contracts@@ -31,6 +31,7 @@   default-extensions:     DeriveAnyClass     DuplicateRecordFields+    ImportQualifiedPost     MultilineStrings     OverloadedLabels     OverloadedStrings@@ -60,7 +61,7 @@     , bytestring    >=0.11 && <0.13     , deepseq       >=1.5  && <1.6     , generic-lens  >=2.2  && <2.4-    , keiki         >=0.7  && <0.8+    , keiki         >=0.8  && <0.9     , kiroku-store  >=0.3  && <0.4     , lens          >=5.2  && <5.4     , mmzk-typeid   >=0.7  && <0.8
src/Keiro/Codec/IdDomain.hs view
@@ -7,15 +7,24 @@     typeIdV7Domain,     idDomainAcceptsText,     validateIdDomainText,+    parseKindIdV7Text,+    parseKindIdV7Value,     idDomainTextPattern,     idDomainSampleText,   ) where +import Data.Aeson (Value, withText)+import Data.Aeson.Types (Parser)+import Data.KindID (KindID)+import Data.KindID qualified as KindID+import Data.KindID.Class (ValidPrefix) import Data.List.NonEmpty (NonEmpty (..))+import Data.Proxy (Proxy (..)) import Data.Text (Text) import Data.Text qualified as T import Data.TypeID qualified as TypeID+import GHC.TypeLits (symbolVal) import Keiki.ProjectionDomain   ( DomainConstructionError,     TextPattern,@@ -68,7 +77,13 @@ -- version check, so both operations are part of this frozen contract. validateIdDomainText :: IdDomainContract -> Text -> Either IdDomainFailure () validateIdDomainText contract input = do-  parsed <- either (Left . IdDomainMalformed . T.pack . show) Right (TypeID.parseText input)+  parsed <- case TypeID.parseText input of+    Right value -> Right value+    Left reason ->+      case TypeID.parseText (T.toLower input) of+        Right canonical+          | TypeID.toText canonical == T.toLower input -> Left IdDomainNonCanonical+        _ -> Left (IdDomainMalformed (T.pack (show reason)))   let actualPrefix = TypeID.getPrefix parsed   if actualPrefix == idDomainPrefix contract     then pure ()@@ -77,6 +92,31 @@     then pure ()     else Left IdDomainNonCanonical   maybe (Right ()) (Left . IdDomainNotUuidV7 . T.pack . show) (TypeID.checkTypeID parsed)++-- | Parse a canonical TypeID-v7 whose prefix is reflected in the result type.+-- Keiro's frozen admission policy runs before the dependency constructs the+-- prefix-indexed value, so generated consumers cannot accidentally widen it.+parseKindIdV7Text :: forall prefix. (ValidPrefix prefix) => Text -> Either IdDomainFailure (KindID prefix)+parseKindIdV7Text input = do+  validateIdDomainText (typeIdV7Domain expectedPrefix) input+  either (Left . IdDomainMalformed . T.pack . show) Right (KindID.parseText @prefix input)+  where+    expectedPrefix = T.pack (symbolVal (Proxy @prefix))++-- | Aeson parser for generated integration-contract fields. When used with+-- @explicitParseField@, Aeson attaches the owning field key to these stable+-- Keiro admission failures.+parseKindIdV7Value :: forall prefix. (ValidPrefix prefix) => Value -> Parser (KindID prefix)+parseKindIdV7Value = withText "KindID" $ \input ->+  either (fail . T.unpack . renderIdDomainFailure) pure (parseKindIdV7Text @prefix input)++renderIdDomainFailure :: IdDomainFailure -> Text+renderIdDomainFailure failure = case failure of+  IdDomainNonCanonical -> "TypeID text is not canonical lowercase"+  IdDomainWrongPrefix expected actual ->+    "TypeID prefix mismatch: expected '" <> expected <> "', found '" <> actual <> "'"+  IdDomainMalformed reason -> "malformed TypeID text: " <> reason+  IdDomainNotUuidV7 reason -> "TypeID suffix is not UUIDv7: " <> reason  idDomainTextPattern :: IdDomainContract -> Either DomainConstructionError TextPattern idDomainTextPattern contract = do