Skip to content

feat(metadata): add AppMetadata value class (pluggable-encryption provider metadata)#408

Merged
Xlin123 merged 1 commit into
trunkfrom
gkc-metadata-appmetadata
Jul 3, 2026
Merged

feat(metadata): add AppMetadata value class (pluggable-encryption provider metadata)#408
Xlin123 merged 1 commit into
trunkfrom
gkc-metadata-appmetadata

Conversation

@gkc

@gkc gkc commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What

Adds an AppMetadata value class to at_client and exposes it as
Metadata.appMetadata, mirroring the canonical Dart at_commons
AppMetadata (at_key.dart).

  • AppMetadata value class — an SDK-owned providerId routing field plus
    an opaque additional map the SDK preserves but does not interpret. Provides:
    • toJson() → the flat object { "providerId": …, …additional } (additional
      entries serialised flat, not nested — matching canonical).
    • fromJson(Map) → routes every key other than providerId into additional;
      throws on a missing/blank providerId.
    • encode()base64(JSON(toJson())), the wire form.
    • decode(Object) → accepts a base64(JSON) String (wire), a flat Map
      (metadata-map form), or an already-parsed AppMetadata; null/"null" → null.
  • Metadata.appMetadata typed as AppMetadata. toString() appends
    :appMetadata:<base64(JSON)> last, after immutable, matching the
    canonical fragment order. Static Metadata.encodeAppMetadata /
    Metadata.decodeAppMetadata delegate to the value class for API parity with
    the Dart client, and Jackson (@JsonValue / @JsonCreator) round-trips the
    flat-object form used in metadata maps.

Why

appMetadata is the provider-owned crypto metadata the SDK stamps on encrypted
records. Its providerId selects the crypto provider able to decrypt the value
— the routing key of the pluggable encrypt/decrypt provider model. The Java
client is a fast follower to implement that model as part of adopting the
post-quantum-safety enhancements currently in flight on the Dart client SDK, and
the provider model depends on AppMetadata; this change lands the value class so
that work has it to build on.

It also unblocks a Java atServer implementation, which needs AppMetadata on
Metadata to parse, store, and re-emit appMetadata through llookup:all /
sync / notify — the receiver relies on providerId to pick the right decryptor
after sync or cached delivery. Without it the field is dropped and pluggable-
encryption round-trips fail.

Canonical parity

Aspect Canonical (at_commons AppMetadata) This change (at_client)
Model providerId + additional value object providerId + additional value class
toJson flat {providerId, …additional} flat {providerId, …additional}
fromJson non-providerId keys → additional; validates non-providerId keys → additional; validates
Wire encoding base64(JSON) via encodeAppMetadata base64(JSON) via encode() / encodeAppMetadata
Decode String(base64) / Map / AppMetadata via decodeAppMetadata same, via decode() / decodeAppMetadata
Fragment position last, after immutable last, after immutable

Tests

MetadataTest +8 (72 total): toJson/fromJson flattening + validation,
encode/decode round-trip (incl. the static Metadata helpers), decode
of Map/AppMetadata/null, the base64 toString() fragment, and Jackson
deserialisation of a nested appMetadata object.

…vider metadata)

Mirrors the canonical at_commons AppMetadata (at_key.dart): an SDK-owned
providerId routing field plus opaque `additional` entries, exposed on Metadata
as the appMetadata field.

- New AppMetadata value class: providerId + additional Map, with toJson()
  (flat {providerId, ...additional}), fromJson(Map), encode() (base64(JSON)),
  and decode() (accepts a base64 String, a flat Map, or an AppMetadata) —
  mirroring canonical encodeAppMetadata / decodeAppMetadata.
- Metadata.appMetadata typed as AppMetadata; toString() appends
  :appMetadata:<base64(JSON)> LAST after immutable, matching the canonical
  metadata fragment order. Static Metadata.encodeAppMetadata /
  decodeAppMetadata delegate for API parity, and Jackson
  (@jsonvalue / @JsonCreator) round-trips the flat-object form used in
  metadata maps.

Groundwork for the Java client's fast-follow adoption of the pluggable
encrypt/decrypt provider model (the post-quantum-safety work in flight on the
Dart SDK), which routes on appMetadata.providerId. It also lets a Java
atServer parse, store, and re-emit appMetadata through llookup:all / sync /
notify so the receiver can select the right decryptor after sync or cached
delivery.

MetadataTest +8 (72 total).
@gkc gkc force-pushed the gkc-metadata-appmetadata branch from 22f1644 to 06088b9 Compare July 3, 2026 15:26
@gkc gkc changed the title feat(metadata): add appMetadata field (base64(JSON) provider metadata) feat(metadata): add AppMetadata value class (pluggable-encryption provider metadata) Jul 3, 2026
@gkc gkc requested a review from Xlin123 July 3, 2026 15:38
@Xlin123 Xlin123 merged commit b1a9ebe into trunk Jul 3, 2026
4 checks passed
@Xlin123 Xlin123 deleted the gkc-metadata-appmetadata branch July 3, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants