lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit 9600081e87d5f8de95260f683039a889bd50aa0e
parent 3f51d10bd8b9e1fb03ef76f540b530327de2869e
Author: triesap <tyson@radroots.org>
Date:   Fri, 31 Jul 2026 16:28:33 +0000

nostr: quarantine superseded package surface

- expose only the chartered protocol adapter modules and feature vocabulary
- migrate in-capsule consumers to canonical event signing and conversion APIs
- retire prefixed compatibility names while recording out-of-scope consumers
- bind the reviewed public API and event contracts to the quarantined surface

Diffstat:
Mcontracts/event_boundary_matrix.md | 21+++++++++++----------
Mcontracts/events/social-events.md | 28++++++++++++++--------------
Mcrates/event_store/contracts/source_maintenance_v1.manifest.json | 4++--
Mcrates/event_store/contracts/source_maintenance_v1.manifest.sha256 | 2+-
Mcrates/event_store/src/generated/source_maintenance_manifest.rs | 4++--
Mcrates/net/src/nostr_client/events/post.rs | 16+++++++---------
Mcrates/net/src/nostr_client/events/profile.rs | 2+-
Mcrates/net/src/nostr_client/manager.rs | 6+++---
Acrates/nostr/COMPATIBILITY.md | 20++++++++++++++++++++
Mcrates/nostr/Cargo.toml | 9++++-----
Mcrates/nostr/README.md | 6++----
Mcrates/nostr/src/blossom.rs | 97++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mcrates/nostr/src/draft_signing.rs | 32+++++++++++++++-----------------
Mcrates/nostr/src/error.rs | 10+++++-----
Mcrates/nostr/src/event.rs | 46++++++++++++++++++++++++++++++++++++++++++----
Mcrates/nostr/src/event_adapters.rs | 2+-
Mcrates/nostr/src/event_convert.rs | 46+++++++++++++++++++++-------------------------
Mcrates/nostr/src/event_verify.rs | 74+++++++++++++++++++++++++-------------------------------------------------
Mcrates/nostr/src/events/application_handler.rs | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mcrates/nostr/src/events/comment.rs | 30++++++++++++------------------
Mcrates/nostr/src/events/deletion.rs | 33++++++++++++++-------------------
Mcrates/nostr/src/events/food_availability.rs | 30+++++++++++++-----------------
Mcrates/nostr/src/events/jobs.rs | 17++++++++---------
Mcrates/nostr/src/events/metadata.rs | 20+++++++-------------
Mcrates/nostr/src/events/mod.rs | 20++++++++++----------
Mcrates/nostr/src/events/post.rs | 37+++++++++++--------------------------
Mcrates/nostr/src/events/reply.rs | 28++++++++++------------------
Mcrates/nostr/src/filter.rs | 20++++++++------------
Mcrates/nostr/src/job_adapter.rs | 8++++----
Mcrates/nostr/src/lib.rs | 28+++++++++++++++-------------
Mcrates/nostr/src/nip17.rs | 160+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mcrates/nostr/src/signing.rs | 16++++++++--------
Mcrates/nostr/src/tag.rs | 11++++++-----
Mcrates/nostr/src/tags.rs | 34++++++++++++++++------------------
Mcrates/nostr/src/types.rs | 209+++++++++++++++++++++++++++++++++++--------------------------------------------
Mcrates/nostr/tests/blossom_conformance.rs | 156++++++++++++++++++++++++++++++++-----------------------------------------------
Mcrates/nostr/tests/coverage.rs | 187++++++++++++++++++++++++++++++-------------------------------------------------
Mcrates/nostr/tests/food_availability_profile.rs | 38++++++++++++++++----------------------
Mcrates/nostr/tests/generic_builder_boundary.rs | 18+++++++++---------
Mcrates/nostr/tests/nip09_deletion_request_profile.rs | 20++++++++++----------
Mcrates/nostr/tests/nip10_reply_profile.rs | 32++++++++++++++------------------
Mcrates/nostr/tests/nip17_conformance.rs | 27++++++++++++---------------
Mcrates/nostr/tests/nip22_comment_profile.rs | 18++++++++----------
Mcrates/nostr/tests/package_boundary.rs | 108++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mcrates/nostr/tests/post_profile.rs | 17+++++++----------
Mcrates/nostr/tests/profile_event_builder.rs | 7+++----
Mcrates/nostr_runtime/src/types.rs | 8++++----
Mcrates/nostr_signer/src/nip46.rs | 12++++++------
Mcrates/outbox/Cargo.toml | 1+
Mcrates/outbox/src/store.rs | 144++++++++++++++++++++++++++++++-------------------------------------------------
Mcrates/replica_sync/src/ingest.rs | 4++--
Mcrates/transport_nostr/src/publish.rs | 4++--
Mcrates/transport_nostr/tests/transport.rs | 13++++++-------
Mdocs/api/radroots_nostr.txt | 568++++++++++++++++++++++++++++++++++---------------------------------------------
Mtools/xtask/src/contract.rs | 34++++++++++++++--------------------
55 files changed, 1261 insertions(+), 1381 deletions(-)

diff --git a/contracts/event_boundary_matrix.md b/contracts/event_boundary_matrix.md @@ -102,8 +102,8 @@ event id wins at equal time. Side-specific errors identify an invalid previous or current candidate before revision comparison. The `radroots_nostr` `events` feature seals strict FoodAvailability wire parts -behind a builder whose timestamp cannot be mutated after validation. It supports -local signing and typed client publication; generic authoring rejects focused +behind a builder whose timestamp cannot be mutated after validation. With the +`signing` feature it supports local signing; generic authoring rejects focused and mixed kind-`30402` profiles. Signed-event relay remains transport-only. The non-default `legacy-ingest` replica feature verifies kind-`30402` NIP-01 events first, selects the raw addressable head before profile decoding, and @@ -205,8 +205,9 @@ relay availability. The event-contract registry v7 classifies `radroots.social.comment.v1` as `TypedOnly` for authoring and `AdmissionOnly` for matching. Registry versions -`1` through `6` are stale. Generic kind-`1111` signing and client publication -fail before signer access. The complete operation surface is exactly +`1` through `6` are stale. Generic kind-`1111` signing fails before signer +access; publication remains transport-owned. The complete operation surface +is exactly `social.comment.build_authored_draft`, `social.comment.project_verified_event`, and `social.comment.verify_and_admit_event`. @@ -252,8 +253,8 @@ qualifying inputs. The event-contract registry v7 classifies `radroots.social.deletion_request.v1` as `TypedOnly` for authoring and -`AdmissionOnly` for matching. Generic kind-`5` signing and client publication -fail before signer access. +`AdmissionOnly` for matching. Generic kind-`5` signing fails before signer +access; publication remains transport-owned. The complete operation surface is exactly `social.deletion_request.build_authored_draft`, @@ -275,9 +276,9 @@ not weaken or add effect fields to the request corpus. | profile | 0 | AuthoredProfile / RadrootsInboundProfileMetadata | events.profile.publish, events.profile.list, events.profile.get | publish must use `profile.build_authored_draft`; inbound projection must use `profile.parse_inbound_metadata`; authored output is deterministic JSON with no marker tag | | follow | 3 | Follow | events.follow.publish, events.follow.list, events.follow.get | replaceable event | | post | 1 | AuthoredUpdate / AuthoredPhotoUpdate / AuthoredAsk / RadrootsInboundPostProjection | events.post.publish, events.post.list, events.post.get | ordinary kind-1 reads remain generic; exact root-card subtypes require verified admission; any `e` tag produces a thread-excluded candidate without a Reply claim | -| reply | 1 | AuthoredNip10Reply / RadrootsInboundNip10ReplyProjection / RadrootsAdmittedNip10ReplyEvent / RadrootsNostrNip10ReplyEventBuilder | social.reply.build_authored_draft, social.reply.project_verified_event, social.reply.verify_and_admit_event | strict marked direct/nested NIP-10 authoring; verified marked or positional inbound admission with advisory-metadata diagnostics; never a root card; target existence, kind, author, and relay availability are not proven | -| comment | 1111 | AuthoredNip22Comment / RadrootsInboundNip22CommentProjection / RadrootsAdmittedNip22CommentEvent / RadrootsNostrNip22CommentEventBuilder | social.comment.build_authored_draft, social.comment.project_verified_event, social.comment.verify_and_admit_event | strict NIP-22 event/address roots limited to kinds `30402`, `31922`, and `31923`; tolerant verified projection; registry-v7 typed-only authoring and admission-only matching | -| deletion_request | 5 | AuthoredNip09DeletionRequest / RadrootsInboundNip09DeletionProjection / RadrootsAdmittedNip09DeletionRequestEvent / RadrootsNip09SuppressionDecision / RadrootsNostrNip09DeletionRequestEventBuilder | social.deletion_request.build_authored_draft, social.deletion_request.project_verified_event, social.deletion_request.verify_and_admit_event, social.deletion_request.evaluate_suppression | effect-free NIP-09 request authoring and verified projection plus pure immutable suppression evaluation; same-author direct event targets and inclusive address cutoffs; kind-5 immunity; advisory kinds ignored; registry-v7 typed-only authoring and admission-only matching | +| reply | 1 | AuthoredNip10Reply / RadrootsInboundNip10ReplyProjection / RadrootsAdmittedNip10ReplyEvent / Nip10ReplyBuilder | social.reply.build_authored_draft, social.reply.project_verified_event, social.reply.verify_and_admit_event | strict marked direct/nested NIP-10 authoring; verified marked or positional inbound admission with advisory-metadata diagnostics; never a root card; target existence, kind, author, and relay availability are not proven | +| comment | 1111 | AuthoredNip22Comment / RadrootsInboundNip22CommentProjection / RadrootsAdmittedNip22CommentEvent / Nip22CommentBuilder | social.comment.build_authored_draft, social.comment.project_verified_event, social.comment.verify_and_admit_event | strict NIP-22 event/address roots limited to kinds `30402`, `31922`, and `31923`; tolerant verified projection; registry-v7 typed-only authoring and admission-only matching | +| deletion_request | 5 | AuthoredNip09DeletionRequest / RadrootsInboundNip09DeletionProjection / RadrootsAdmittedNip09DeletionRequestEvent / RadrootsNip09SuppressionDecision / Nip09DeletionRequestBuilder | social.deletion_request.build_authored_draft, social.deletion_request.project_verified_event, social.deletion_request.verify_and_admit_event, social.deletion_request.evaluate_suppression | effect-free NIP-09 request authoring and verified projection plus pure immutable suppression evaluation; same-author direct event targets and inclusive address cutoffs; kind-5 immunity; advisory kinds ignored; registry-v7 typed-only authoring and admission-only matching | | reaction | 7 | Reaction | events.reaction.publish, events.reaction.list, events.reaction.get | requires event, pubkey, or address tags | | repost | 6 | Repost | events.repost.publish, events.repost.list, events.repost.get | NIP-18 kind-1 repost surface | | generic_repost | 16 | GenericRepost | events.generic_repost.publish, events.generic_repost.list, events.generic_repost.get | NIP-18 generic repost surface | @@ -304,7 +305,7 @@ not weaken or add effect fields to the request corpus. | document | 30361 | Document | events.document.publish, events.document.list, events.document.get | requires `d` and pubkey tags; optional address tag | | resource_area | 30370 | ResourceArea | events.resource_area.publish, events.resource_area.list, events.resource_area.get | addressable; GCS location and `g` tag required | | resource_cap | 30371 | ResourceHarvestCap | events.resource_cap.publish, events.resource_cap.list, events.resource_cap.get | addressable; required address, pubkey, key, start, and end tags | -| food_availability | 30402 | FoodAvailabilityDetails / RadrootsInboundFoodAvailabilityProjection / RadrootsAdmittedFoodAvailabilityEvent / RadrootsNostrFoodAvailabilityEventBuilder | food_availability.build_authored_draft, food_availability.project_verified_event, food_availability.verify_and_admit_event, food_availability.validate_revision | focused `radroots.food.availability.v1` profile; strict deterministic authoring, verified projection/admission, stable-coordinate revision validation, sealed Nostr signing/publication, generic-authoring reservation, and raw-head-first partitioning only behind the non-default `legacy-ingest` replica feature; BUD-02 upload evidence remains a runtime prerequisite | +| food_availability | 30402 | FoodAvailabilityDetails / RadrootsInboundFoodAvailabilityProjection / RadrootsAdmittedFoodAvailabilityEvent / FoodAvailabilityBuilder | food_availability.build_authored_draft, food_availability.project_verified_event, food_availability.verify_and_admit_event, food_availability.validate_revision | focused `radroots.food.availability.v1` profile; strict deterministic authoring, verified projection/admission, stable-coordinate revision validation, sealed Nostr signing, transport-owned publication, generic-authoring reservation, and raw-head-first partitioning only behind the non-default `legacy-ingest` replica feature; BUD-02 upload evidence remains a runtime prerequisite | | operational_listing | 30402 | OperationalListing | events.operational_listing.publish, events.operational_listing.list, events.operational_listing.get | NIP-99 classified-listing kind with the richer Radroots operational profile; canonical Markdown content and tags; farm author required | | dvm_request | 5000-5999 | JobRequest | events.dvm_request.publish, events.dvm_request.list, events.dvm_request.get | generic DVM request surface | | dvm_result | 6000-6999 | JobResult | events.dvm_result.publish, events.dvm_result.list, events.dvm_result.get | generic DVM result surface | diff --git a/contracts/events/social-events.md b/contracts/events/social-events.md @@ -181,12 +181,12 @@ and are accepted only after deserialization revalidates the registry version, contract, kind, shape, policy, recomputed event id, and known fields. The frozen-draft signing boundary repeats that validation, so stale version-`1` through version-`6` drafts must be rebuilt. Typed root posts, Replies, -Comments, and Deletion Requests enter Nostr signing and client publication -only through opaque typed builders that expose timestamp selection and -signing, but no raw tag/content mutation or public conversion to the upstream -builder. The opaque generic builder rejects kind `0`, every kind `1` event, -kind `5`, and kind `1111` at both direct signing and client publication before -a signer is consulted. +Comments, and Deletion Requests enter Nostr signing only through opaque typed +builders that expose timestamp selection and signing, but no raw tag/content +mutation or public conversion to the upstream builder. Publication remains a +transport concern operating on signed events. The opaque generic builder +rejects kind `0`, every kind `1` event, kind `5`, and kind `1111` before a +signer is consulted. ### NIP-10 Reply Trust Layers @@ -217,8 +217,8 @@ Strict authoring is deterministic. A direct Reply emits two-element `p` tag. A nested Reply emits the root `e` tag, then `["e",<parent-id>,<relay-or-empty>,"reply"]`, then the root and parent author `p` tags in that order; equal authors are emitted once. No other authored tag -shape is accepted. Signing and client publication are exposed only through the -sealed `RadrootsNostrNip10ReplyEventBuilder`. +shape is accepted. Signing is exposed only through the sealed +`Nip10ReplyBuilder`; publication remains transport-owned. Inbound projection requires a signature-and-id verified envelope. It accepts preferred marked `e` references, including the optional NIP-10 author hint, and @@ -688,13 +688,13 @@ enter this comparison. Kind, author, `d`, and `published_at` must remain stable. have a later `created_at`, or the lower event id when both timestamps are equal. Invalid previous and current inputs have side-specific errors. -With the `events` feature, `radroots_nostr_build_food_availability_event` fixes `created_at` during +With the `events` feature, `build_food_availability_event` fixes `created_at` during typed construction, derives the exact strict wire parts, and returns a sealed builder with no raw -tag, content, or timestamp mutation. The builder supports local signing and, with the `client` -feature, typed relay publication. Generic builder signing and client publication reject focused and -mixed-marker kind-`30402` events before signer access. Marker-free generic NIP-99 and -operational-only builders remain available for explicit compatibility, while relaying an already -signed event remains transport-only and establishes no Radroots authoring claim. +tag, content, or timestamp mutation. With the `signing` feature, the builder supports local signing. +Generic builder signing rejects focused and mixed-marker kind-`30402` events before signer access. +Marker-free generic NIP-99 and operational-only builders remain available for explicit +compatibility. Relay publication remains transport-only and establishes no Radroots authoring +claim. Behind the explicit non-default `legacy-ingest` feature, legacy replica ingestion verifies kind-`30402` identifiers and signatures before acquiring its write transaction, then selects the diff --git a/crates/event_store/contracts/source_maintenance_v1.manifest.json b/crates/event_store/contracts/source_maintenance_v1.manifest.json @@ -873,8 +873,8 @@ { "role": "contract_command_authority", "path": "tools/xtask/src/contract.rs", - "byte_length": 508374, - "sha256": "c498f6fda5e595c7165465a9f261b45acc7ef47762e1fc04fd94026f9ecf2167", + "byte_length": 508073, + "sha256": "26d1825a0d7a4a3bb983478f2ef87dc228cbfb68f794bb52864e34a62ef1eead", "hash_algorithm": "sha256_bytes_v1" }, { diff --git a/crates/event_store/contracts/source_maintenance_v1.manifest.sha256 b/crates/event_store/contracts/source_maintenance_v1.manifest.sha256 @@ -1 +1 @@ -032aab678a257acd2215d631b53d4883b41c74d023725d3ccd0518d8d5858a86 +ef7894006bc64f8b72718708f16babe3302209c6b1e74465def57d6b1862a9b6 diff --git a/crates/event_store/src/generated/source_maintenance_manifest.rs b/crates/event_store/src/generated/source_maintenance_manifest.rs @@ -1,8 +1,8 @@ // @generated by `cargo xtask contract source-maintenance-manifest --write`; do not edit. -pub(crate) const SOURCE_MAINTENANCE_MANIFEST_JSON: &str = "{\n \"schema_version\": 1,\n \"contract_id\": \"radroots_event_store.source_maintenance_v1\",\n \"hook_id\": \"source_maintenance_v1\",\n \"manifest_schema\": {\n \"path\": \"crates/event_store/contracts/source_maintenance_v1.manifest.schema.json\",\n \"byte_length\": 12315,\n \"sha256\": \"96ea98a5abf3348b61565954cd34f2c622411d8dd34205ef04134bbe0e3d3f2b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"predecessor\": {\n \"hook_id\": \"food_availability_projection_v1\",\n \"manifest\": {\n \"path\": \"crates/event_store/contracts/food_availability_projection_v1.manifest.json\",\n \"byte_length\": 17455,\n \"sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n },\n \"migration\": {\n \"version\": 4,\n \"name\": \"source_maintenance\",\n \"up\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.up.sql\",\n \"byte_length\": 19841,\n \"sha256\": \"ab2724188f8d08c897eebea2533a635e7c74282a25e84e4c0c37e78b08837a43\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"down\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.down.sql\",\n \"byte_length\": 5172,\n \"sha256\": \"fe44fd53c51545c08ea479b385e6781079dab70fc63da2a3c205d727a00ce860\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"schema_sha256\": \"074f85b663444ac150239ecd8441ea4a96ad83a798a55e22d2e5e2f7ee943a8c\",\n \"catalog\": {\n \"objects\": [\n \"radroots_event_store_source_capacity_delete_guard\",\n \"radroots_event_store_source_capacity_insert_guard\",\n \"radroots_event_store_source_capacity_marker_close_guard\",\n \"radroots_event_store_source_capacity_update_guard\",\n \"radroots_event_store_source_capacity_v1\",\n \"radroots_event_store_source_generation_capacity_advance\",\n \"radroots_event_store_source_generation_capacity_guard\"\n ],\n \"replaced_objects\": [\n \"radroots_event_store_food_availability_image_delete_guard\",\n \"radroots_event_store_food_availability_projection_delete_guard\",\n \"radroots_event_store_source_rebuild_marker_insert_guard\"\n ],\n \"tables\": [\n \"radroots_event_store_source_capacity_v1\"\n ],\n \"fts5_tables\": []\n }\n },\n \"source_maintenance\": {\n \"version\": 1,\n \"event_contract_registry_version\": 7,\n \"capacity_authority_id\": \"radroots_event_store_source_capacity_v1\",\n \"accounting\": {\n \"algorithm\": \"sqlite_cast_blob_octet_sum_v1\",\n \"raw_event_columns\": [\n \"event_id\",\n \"pubkey\",\n \"tags_json\",\n \"content\",\n \"sig\",\n \"raw_json\"\n ],\n \"raw_tag_columns\": [\n \"event_id\",\n \"tag_name\",\n \"tag_value\",\n \"tag_json\"\n ],\n \"nullable_raw_tag_columns\": [\n \"tag_value\"\n ]\n },\n \"limits\": {\n \"raw_events\": 25000,\n \"raw_tags\": 250000,\n \"raw_event_text_bytes\": 67108864,\n \"raw_tag_text_bytes\": 33554432,\n \"retained_source_generations\": 8\n },\n \"reopen_validation\": {\n \"mode\": \"bounded_full_raw_recount_v1\",\n \"raw_event_rejection_scan_bound\": 25001,\n \"raw_tag_rejection_scan_bound\": 250001,\n \"generation_history_validation\": \"bounded_count_plus_active_ordinal_v1\",\n \"retained_generation_rejection_scan_bound\": 9\n },\n \"rebuild_seal\": {\n \"nip09_hook_id\": \"nip09_reconciliation_v1\",\n \"nip09_manifest_sha256\": \"74af832420ffbaa9805e89df3c0b34f126a443e1598f757e3372f407f9003b77\",\n \"food_hook_id\": \"food_availability_projection_v1\",\n \"food_manifest_sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"food_scope_fingerprint_sha256\": \"8b63c5ddc48a2cc7db69295238b96d5f814dba50427c80b4d0079f061e6d3de0\",\n \"active_generation_authority\": \"radroots_event_store_source_state\",\n \"marker_close_authority\": \"radroots_event_store_source_capacity_marker_close_guard\"\n }\n },\n \"entry_points\": [\n {\n \"role\": \"migration_registry\",\n \"rust_path\": \"radroots_event_store::migrations::EVENT_STORE_MIGRATIONS[3]\"\n },\n {\n \"role\": \"migration_apply_hook\",\n \"rust_path\": \"radroots_event_store::schema::apply_migration_hook\"\n },\n {\n \"role\": \"migration_validation_hook\",\n \"rust_path\": \"radroots_event_store::schema::validate_migration_hook_state\"\n },\n {\n \"role\": \"capacity_query\",\n \"rust_path\": \"radroots_event_store::RadrootsEventStore::source_capacity_v1\"\n },\n {\n \"role\": \"raw_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_unique_raw_source_append_v1\"\n },\n {\n \"role\": \"raw_append_advance\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::advance_source_capacity_after_insert_v1\"\n },\n {\n \"role\": \"generation_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_source_generation_append_v1\"\n },\n {\n \"role\": \"generation_rebuild_bind\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::bind_source_capacity_to_generation_v1\"\n },\n {\n \"role\": \"sqlite_encoding_preflight\",\n \"rust_path\": \"radroots_event_store::store::validate_main_database_encoding\"\n },\n {\n \"role\": \"source_generation_history_rollback_guard\",\n \"rust_path\": \"radroots_event_store::schema::validate_rollback_preserves_source_generation_history\"\n },\n {\n \"role\": \"result_vector_executor\",\n \"rust_path\": \"source_maintenance_v1_result_vector\"\n }\n ],\n \"source_files\": [\n {\n \"role\": \"workspace_dependency_authority\",\n \"path\": \"Cargo.toml\",\n \"byte_length\": 12440,\n \"sha256\": \"8981f78d3ea85454a8cf7be156b3eef5659b399f1631d7c1068e7c336988070d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_currency_value_authority\",\n \"path\": \"crates/core/src/currency.rs\",\n \"byte_length\": 4142,\n \"sha256\": \"42e6da2d8d2fdd6955dc2d83e98dd00266e02bc910b69923b117662c05089d14\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_decimal_value_authority\",\n \"path\": \"crates/core/src/decimal.rs\",\n \"byte_length\": 7839,\n \"sha256\": \"4b1d681a92d7a9e074bee7e1f20eb1499bb05bfc6528a6c9ba69fa7d00416550\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_money_value_authority\",\n \"path\": \"crates/core/src/money.rs\",\n \"byte_length\": 8025,\n \"sha256\": \"3f30bc21e21951a62fdc5d4033736ed42a883df590e8403940775bd2edfeebc5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_percent_value_authority\",\n \"path\": \"crates/core/src/percent.rs\",\n \"byte_length\": 2652,\n \"sha256\": \"42ceab109881329f3539d06a0ee0381ab4359985fe185a18d58a9c9558c5eb7f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_value_authority\",\n \"path\": \"crates/core/src/quantity.rs\",\n \"byte_length\": 6785,\n \"sha256\": \"d14e619da3829cdaf3ca7385fb892d330c286c1e21455c135c37518cbb588b5f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_price_value_authority\",\n \"path\": \"crates/core/src/quantity_price.rs\",\n \"byte_length\": 7061,\n \"sha256\": \"d60f70377099470ed283f45868a5119d7bb46143cb250b5082a4c038ba7f6cdc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_unit_value_authority\",\n \"path\": \"crates/core/src/unit.rs\",\n \"byte_length\": 10023,\n \"sha256\": \"550e9582b6a5290aac3f637b83853b21fefcbab92c432d067c83448f4b2fe3e9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_public_surface\",\n \"path\": \"crates/blossom/src/lib.rs\",\n \"byte_length\": 510,\n \"sha256\": \"a4dfcbd193457c50c1b0fbfc91bb547981ecd3a6e23cfc6f1030edfb511dc58c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_authorization_authority\",\n \"path\": \"crates/blossom/src/authorization.rs\",\n \"byte_length\": 39360,\n \"sha256\": \"461947b30516315a342b3b5697599f701d27050888f29f67f5d7a7ad4afa4c28\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_descriptor_authority\",\n \"path\": \"crates/blossom/src/descriptor.rs\",\n \"byte_length\": 13702,\n \"sha256\": \"b2a4ffa760256e1316f70e012d200e2b5f4afd8ede771b85a5147f96b247f599\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_error_authority\",\n \"path\": \"crates/blossom/src/error.rs\",\n \"byte_length\": 17229,\n \"sha256\": \"02af55beacf437040be17d1fc3271d6e2a62915f656ec2dbe06247deef83f95a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_hash_authority\",\n \"path\": \"crates/blossom/src/hash.rs\",\n \"byte_length\": 11006,\n \"sha256\": \"45eca0d81ac0f46c305a32f81aafcdd90b14679d0614f72862289a6e5d4cb08f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_media_type_authority\",\n \"path\": \"crates/blossom/src/media_type.rs\",\n \"byte_length\": 2368,\n \"sha256\": \"69db5c0f9fcdd7dbe1f22daa499f65603ae4ce198083dab2c73a36813fa18a46\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_url_authority\",\n \"path\": \"crates/blossom/src/url.rs\",\n \"byte_length\": 14580,\n \"sha256\": \"342c995fcf620e5fb32461a7d8276f5668ba2662890bd32d12780cc9121c6451\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_public_surface\",\n \"path\": \"crates/event/src/lib.rs\",\n \"byte_length\": 1892,\n \"sha256\": \"5d609b963a9b8db18ef96a10f394617413734d2631774d3296e6d8fc029cb02c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_facade\",\n \"path\": \"crates/event/src/contract.rs\",\n \"byte_length\": 208,\n \"sha256\": \"27466bf36461071931f391c60646a13f7781d19584583166cc54c0eece76d010\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_registry_v7_authority\",\n \"path\": \"crates/event/src/contract/registry_v7.rs\",\n \"byte_length\": 145805,\n \"sha256\": \"0a62603f6fc05dc9f758561cf7da258c676ada810ceaeca7fb151364a5c83d62\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_envelope_authority\",\n \"path\": \"crates/event/src/envelope.rs\",\n \"byte_length\": 29310,\n \"sha256\": \"29f8d8c4b17c01cb5a8c7f59e4ce52e134180e0e6f37d265063d278b8f2ff26e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_verification_typestate_authority\",\n \"path\": \"crates/event/src/verification.rs\",\n \"byte_length\": 9400,\n \"sha256\": \"417acb2ce670d266b1fa4fcafd6b48a910218deab38f57fb8b942056db76f94d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_admission_typestate_authority\",\n \"path\": \"crates/event/src/admission.rs\",\n \"byte_length\": 7052,\n \"sha256\": \"62bd2ceb0f434946fdfc2b81f4efb13738676a29a6936c23a427e43aadf2d9cb\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_facade\",\n \"path\": \"crates/event/src/event_head.rs\",\n \"byte_length\": 97,\n \"sha256\": \"f761ff3e74c4f5e1e28381db00ce698c633ff048669b22984d14a587482e8e83\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_v1_authority\",\n \"path\": \"crates/event/src/event_head/v1.rs\",\n \"byte_length\": 6849,\n \"sha256\": \"9f4144d8d240023cf493ce0b538ade4c16dc44204d6b5f2797152caf6f9e7dba\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_ids_authority\",\n \"path\": \"crates/event/src/id.rs\",\n \"byte_length\": 48381,\n \"sha256\": \"a08fe3873815453a03318a706e2fa98a8a6728ec69d24368a87ec60025566fe0\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_trade_authority\",\n \"path\": \"crates/event/src/trade.rs\",\n \"byte_length\": 65549,\n \"sha256\": \"f818a7287ed82de3fb9ef1d973f0fb18d84b30eb4827ddc576ee502dd980145f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_kinds_authority\",\n \"path\": \"crates/event/src/kinds.rs\",\n \"byte_length\": 34961,\n \"sha256\": \"8b3ce6193cab1f7e1587d0c1b2880a81b0aa43c77d89671b602772db37edcebf\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_tags_authority\",\n \"path\": \"crates/event/src/tags.rs\",\n \"byte_length\": 4530,\n \"sha256\": \"cb8f12a639fc72d9238e32495d9e67e928e6627fb8c94ec0a58c5d95e7373cd6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_draft_authority\",\n \"path\": \"crates/event/src/draft.rs\",\n \"byte_length\": 51150,\n \"sha256\": \"ecc619aae28d688d13f35467398f17766b60f26c2bf3616d772ce65b7fa4fb53\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_calendar_authority\",\n \"path\": \"crates/event/src/calendar.rs\",\n \"byte_length\": 97992,\n \"sha256\": \"73e79d61ee175cb46e6123e1d28239252ddf0ad094dc1113bdb1286b63b88d57\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_classified_listing_authority\",\n \"path\": \"crates/event/src/classified_listing.rs\",\n \"byte_length\": 7956,\n \"sha256\": \"ac58484b87c7712c81f50f884d1c0dd60938571aa5f6f05d555191f529a4c2b0\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_profile_authority\",\n \"path\": \"crates/event/src/profile.rs\",\n \"byte_length\": 17011,\n \"sha256\": \"572bfe3b6f1711d109db445077f0a8453cad3f021cc0638f79201b618e16b978\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_post_authority\",\n \"path\": \"crates/event/src/post.rs\",\n \"byte_length\": 19968,\n \"sha256\": \"a822cd51eff9cbaa39db998cc5c90d117f7a983f0fe2d42d42118cb00e95982c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_comment_authority\",\n \"path\": \"crates/event/src/comment.rs\",\n \"byte_length\": 34745,\n \"sha256\": \"24b7fda13229f21cee5cef2a9941e3aaafdbc486b19ed42731b0b6ee37c28703\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_food_availability_authority\",\n \"path\": \"crates/event/src/food_availability.rs\",\n \"byte_length\": 42829,\n \"sha256\": \"52472c07eb0855d884c60755dc3a3e1a963793451d707e51f769f2d78384f318\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_deletion_authority\",\n \"path\": \"crates/event/src/deletion.rs\",\n \"byte_length\": 30022,\n \"sha256\": \"8c3f2e32407520a8e8242c1293af32613c648fb76218b8003a18929ac0b3811f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_dto_authority\",\n \"path\": \"crates/event/src/dto.rs\",\n \"byte_length\": 5038,\n \"sha256\": \"9e228c95ff6ff33f99441d8682781fd0a1c4d3f1db24284a43985dcbac3ba136\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_farm_crdt_authority\",\n \"path\": \"crates/event/src/farm_crdt.rs\",\n \"byte_length\": 21118,\n \"sha256\": \"cec265ac9c42b59a14be4eb96924d26a83477c27291f667f23e6e47a64b6b2c7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_knowledge_authority\",\n \"path\": \"crates/event/src/knowledge.rs\",\n \"byte_length\": 54624,\n \"sha256\": \"3d55ff88a4e30d5d605f9ae4b2e96b9df6978d6c14e52f9aeb0b8039cfc200d7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_operational_listing_authority\",\n \"path\": \"crates/event/src/operational_listing.rs\",\n \"byte_length\": 10307,\n \"sha256\": \"52e710db816c89c8d4b87c86541987f7447f2f7091c394c68d9cb98a27f90159\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_order_authority\",\n \"path\": \"crates/event/src/order.rs\",\n \"byte_length\": 60218,\n \"sha256\": \"4203fcc469612cac5c705884564e140b9fb076cd57079e22ed85275a8b936e50\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_reply_authority\",\n \"path\": \"crates/event/src/reply.rs\",\n \"byte_length\": 15581,\n \"sha256\": \"b0b83a1e96125c0892d932e9314519242a715fa8f46334aff765ffd248c91d9a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_trade_validation_authority\",\n \"path\": \"crates/event/src/trade_validation.rs\",\n \"byte_length\": 4669,\n \"sha256\": \"1486f79bd1d0eadea6cc1b7646ce1f7f57ccade18334a3ea37286426676b9b98\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_relay_hint_authority\",\n \"path\": \"crates/event/src/relay_hint.rs\",\n \"byte_length\": 13598,\n \"sha256\": \"fb8b026eeccf51d78f20771c44223e7b48825aa0e3c760d6b3cb90148021a674\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_media_authority\",\n \"path\": \"crates/event/src/media.rs\",\n \"byte_length\": 3455,\n \"sha256\": \"10678af3a202d5367dbcf3bcdc0bf9fdf8d8fb89b045d7d3fb96b3cc195ab6f9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_social_authority\",\n \"path\": \"crates/event/src/social.rs\",\n \"byte_length\": 6076,\n \"sha256\": \"a2dab19caad46eab14fac86e7c878a801a450d8ac374b0e728b71a5a224eef19\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_facade\",\n \"path\": \"crates/event/src/wire.rs\",\n \"byte_length\": 68,\n \"sha256\": \"cb52f6006f7ecd862707d6b048f9fc407e0cd5ebcd3091b3c54e195ffa5cba64\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_v1_authority\",\n \"path\": \"crates/event/src/wire/v1.rs\",\n \"byte_length\": 22198,\n \"sha256\": \"c818bc1f67e215948ba253c8c62b09ab788db9aeec9b6df8096014b55565cb8c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_public_surface\",\n \"path\": \"crates/event_codec/src/lib.rs\",\n \"byte_length\": 2448,\n \"sha256\": \"7d4b0040ad3971f34395b17cb1aa40617e9c2c9e1b4222676c388c3adaa47e07\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_facade\",\n \"path\": \"crates/event_codec/src/verification.rs\",\n \"byte_length\": 253,\n \"sha256\": \"b49a32df605035c87f295c0a151140d43d2e588c5e11b05183e5fc92993dae0e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_v1_authority\",\n \"path\": \"crates/event_codec/src/verification/v1.rs\",\n \"byte_length\": 6584,\n \"sha256\": \"72f64615bd6b6dc3b051579e3069b2213f3781dcc28e12f0b533c7d81b81b9b1\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_registry_v7_admission_authority\",\n \"path\": \"crates/event_codec/src/admission/registry_v7.rs\",\n \"byte_length\": 5228,\n \"sha256\": \"62da30cb6ef7d0ed2d43715a73bd529283e8ae8c12571bc5c68722cb400f17b8\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_admission_facade\",\n \"path\": \"crates/event_codec/src/admission.rs\",\n \"byte_length\": 21251,\n \"sha256\": \"25928e734e7b3688f92af806a12a13458c48fb47e94249f60f0226300d5da2b4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_inbound_facade\",\n \"path\": \"crates/event_codec/src/profile/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/profile/inbound/registry_v7.rs\",\n \"byte_length\": 10347,\n \"sha256\": \"32111c0e0592229c11a93a3a8054e7b124b039451aa696a9abcb56df2a6608d3\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_inbound_facade\",\n \"path\": \"crates/event_codec/src/post/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/post/inbound/registry_v7.rs\",\n \"byte_length\": 15985,\n \"sha256\": \"e17083b0596e3a55994c399bc6272c0ebf04cabaa513260b3d45dd546f7f50ef\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_inbound_facade\",\n \"path\": \"crates/event_codec/src/reply/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/reply/inbound/registry_v7.rs\",\n \"byte_length\": 26662,\n \"sha256\": \"d1d11116ca27801b7e2f17da60900e6a9ca0b6f27ea9ee0bf19e97dbf24c0c32\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_inbound_facade\",\n \"path\": \"crates/event_codec/src/comment/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/comment/inbound/registry_v7.rs\",\n \"byte_length\": 53311,\n \"sha256\": \"c63fe853536b17bded6073f32b53434b60fc5123f911d01c642a6b3982f09c70\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_facade\",\n \"path\": \"crates/event_codec/src/deletion/mod.rs\",\n \"byte_length\": 115,\n \"sha256\": \"17d56f82ddb0a86bc97abbcf3e037fe460ea31fff2548f527be4bf004dac3a95\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_reconciliation_v1_authority\",\n \"path\": \"crates/event_codec/src/deletion/reconciliation_v1.rs\",\n \"byte_length\": 38028,\n \"sha256\": \"c6901f559e83700610595720c47a4d062078ae8411e1fc2fb952dd215b19dd90\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_error_authority\",\n \"path\": \"crates/event_codec/src/error.rs\",\n \"byte_length\": 3666,\n \"sha256\": \"174ce982bca37fac28d016c3ab3236441c9b31b2169ec94db6c9288b36c72849\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_admission_authority\",\n \"path\": \"crates/event_codec/src/food_availability/admission.rs\",\n \"byte_length\": 5681,\n \"sha256\": \"99809859090f5295572688d06bbb30dbe50524ba2c996de7ec5b26f6dd390643\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_authored_authority\",\n \"path\": \"crates/event_codec/src/food_availability/authored.rs\",\n \"byte_length\": 9724,\n \"sha256\": \"8673ec62ed3fc47b691efd9ca828643719803971e72b756c5b4603d409d0fba5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_inbound_facade\",\n \"path\": \"crates/event_codec/src/food_availability/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/food_availability/inbound/registry_v7.rs\",\n \"byte_length\": 26037,\n \"sha256\": \"92a7e75da3293967cec17a514479144c3c948a64542577dd58c7f07992968e4f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_job_traits_authority\",\n \"path\": \"crates/event_codec/src/job/traits.rs\",\n \"byte_length\": 4946,\n \"sha256\": \"1b3558a3196744005978dceddd33d3a72ad1ab8f50fb1cbfd997dcfe98bb9e39\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_job_encode_authority\",\n \"path\": \"crates/event_codec/src/job/encode.rs\",\n \"byte_length\": 1670,\n \"sha256\": \"5d6cae6309fcdd02deb7c751b5c451d257cf1900986391cb39cbb2bfd1ddb577\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_knowledge_verification_authority\",\n \"path\": \"crates/event_codec/src/knowledge/verification.rs\",\n \"byte_length\": 6986,\n \"sha256\": \"6f8a10ed262ce37f05acd9c89a1e37ca2fa99ce7da18407891e8abe228ee2349\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_operational_listing_tags_authority\",\n \"path\": \"crates/event_codec/src/operational_listing/tags.rs\",\n \"byte_length\": 50222,\n \"sha256\": \"55b6860bc6f4699dd47a49f8336764e9db78aafb7c32849102dedeb96804b373\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_order_decode_authority\",\n \"path\": \"crates/event_codec/src/order/decode.rs\",\n \"byte_length\": 42667,\n \"sha256\": \"033d9465bc041d205eab3f820572b719a35651340dcb50bdce7c60fabee5f6e1\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_facade\",\n \"path\": \"crates/event_codec/src/profile/mod.rs\",\n \"byte_length\": 1456,\n \"sha256\": \"06b890da54580e2ec68f7e729281b7c3b650ac0a95a4fcb0db3c6cdaa591a7ef\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_tag_builders_authority\",\n \"path\": \"crates/event_codec/src/tag_builders.rs\",\n \"byte_length\": 9232,\n \"sha256\": \"bd81ccf04fd72358331b48eddcde087a95e115c5bd90c05fd9332644979ad5e6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_trade_facade\",\n \"path\": \"crates/event_codec/src/trade/mod.rs\",\n \"byte_length\": 21472,\n \"sha256\": \"10cee4b6cd6429ac9eb00327a521bcd0982fae4de98bda77e4728fda002965d3\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_dependency_authority\",\n \"path\": \"crates/event_store/Cargo.toml\",\n \"byte_length\": 1570,\n \"sha256\": \"e2116eb02eb2b18b21db7351f29a1efeffe11ce4ab9bb7c85a3f3e7f2e56aca4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_error_and_limits\",\n \"path\": \"crates/event_store/src/error.rs\",\n \"byte_length\": 19458,\n \"sha256\": \"3d87df984af6ae5decf7ca8c3a8d5422be6c647e6a05490225b6b2037bf3701b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"generated_descriptor_registration\",\n \"path\": \"crates/event_store/src/generated.rs\",\n \"byte_length\": 144,\n \"sha256\": \"6b0a8d6f249bd4fc3f878d37cb5e418680f0f1be2d9eec2518dedf03efc47121\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_surface\",\n \"path\": \"crates/event_store/src/lib.rs\",\n \"byte_length\": 3844,\n \"sha256\": \"3cd9653bcb752fb3c4442d4904b98a0a6208011a9a238125b7b7073d7f4e312b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"migration_registry\",\n \"path\": \"crates/event_store/src/migrations.rs\",\n \"byte_length\": 73585,\n \"sha256\": \"a47477d04759ec6e71d14d3d05459864eae78fce0e3c2481a1b03147f04637f7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_model_public_surface\",\n \"path\": \"crates/event_store/src/model.rs\",\n \"byte_length\": 32070,\n \"sha256\": \"2cdbf6d1a4e0fa6680f45f02758513509339a7cf3a2387e824fb73b0edf749a4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_model\",\n \"path\": \"crates/event_store/src/model/reconciliation_v1.rs\",\n \"byte_length\": 10446,\n \"sha256\": \"475b7b840bffdae7e3f7a31f5b940b9dfa579eaa1cac640729aaaeadabf83ba6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_ingest_model\",\n \"path\": \"crates/event_store/src/model/ingest_reconciliation_v1.rs\",\n \"byte_length\": 1588,\n \"sha256\": \"6117e797674c35bb1ccebffbc6a8c0108bfc38c7c9f82607066dfd802b8f0734\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_model\",\n \"path\": \"crates/event_store/src/model/addressable_transition_feed_v1.rs\",\n \"byte_length\": 22229,\n \"sha256\": \"e651952d73ed0a29d2b137076f56f699beada205ac84ed8a96834e86e343fa78\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"current_visibility_model\",\n \"path\": \"crates/event_store/src/model/current_visibility_v1.rs\",\n \"byte_length\": 5634,\n \"sha256\": \"d64429bc7985231e923c1c3e5295d94270a817dd5dc96693f35dfdf2dc398e4f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_model\",\n \"path\": \"crates/event_store/src/model/food_availability_projection_v1.rs\",\n \"byte_length\": 17108,\n \"sha256\": \"67861a966d674efbc40f0b0433db2ec006048ff923f6261df4161e2ddba717b5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_generation_rebuild_authority\",\n \"path\": \"crates/event_store/src/nip09/reconciliation_v1.rs\",\n \"byte_length\": 184833,\n \"sha256\": \"3ca802cb7a8444c8512b2be1390a019281704316a430fb9b75a8ad2cad358a07\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"nip09_successor_result_vector_executor\",\n \"path\": \"crates/event_store/tests/support/nip09_reconciliation_v1_result_vector_v2.rs\",\n \"byte_length\": 18205,\n \"sha256\": \"c632beee70dc777b8dd2a4f88cadb55296fee7aa5742e6e2c9f6d49f26ae2c78\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"schema_migration_and_reopen_authority\",\n \"path\": \"crates/event_store/src/schema.rs\",\n \"byte_length\": 146146,\n \"sha256\": \"93b060e80d3edd73f86208e4bf698fa9d53eaf1eeb04526c9261fb8b5726fb0d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_store_and_transaction_authority\",\n \"path\": \"crates/event_store/src/store.rs\",\n \"byte_length\": 393218,\n \"sha256\": \"64565c3bc043779e1c2f26d9761901b109b4acab0f48c2021102c0e4e1f1f726\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_store\",\n \"path\": \"crates/event_store/src/store/addressable_transition_feed_v1.rs\",\n \"byte_length\": 40209,\n \"sha256\": \"2cebcca9602633652a79e7041d18d3a7d3feb1388a98f4f68137b9814efcedfa\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"current_visibility_store\",\n \"path\": \"crates/event_store/src/store/current_visibility_v1.rs\",\n \"byte_length\": 15737,\n \"sha256\": \"aa5d1bff7a5368cbac2b37906bb40f54bfc8aa6906bab34369569fdd105bf899\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_store\",\n \"path\": \"crates/event_store/src/store/food_availability_projection_v1.rs\",\n \"byte_length\": 48919,\n \"sha256\": \"3a30da308ef863b806ed63d1cb65ac80f6a946a71821af84a0c595330491757e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_extension\",\n \"path\": \"crates/event_store/src/store/post_core_extensions_v1.rs\",\n \"byte_length\": 6569,\n \"sha256\": \"f5bd8ddb45e1b2144895bd8da737fc92db051be1844ce7e8047a32b47376ce37\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_storage\",\n \"path\": \"crates/event_store/src/store/post_core_storage_v1.rs\",\n \"byte_length\": 16538,\n \"sha256\": \"fcd6546c23a6cba12b70d92728d19b6ee5d43174b83495f820348b77efa33aab\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"raw_ingest_capacity_authority\",\n \"path\": \"crates/event_store/src/store/protocol_reconciliation_v1.rs\",\n \"byte_length\": 29950,\n \"sha256\": \"c72aaff06e4f35d0b4523c6625e83345879f9e15b9fe9563dccf589e5d01e277\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_protocol_storage\",\n \"path\": \"crates/event_store/src/store/protocol_storage_v1.rs\",\n \"byte_length\": 10835,\n \"sha256\": \"c82179b9f57968191f3e71dd008cc701787c62715ada74090eeecaa3b213076d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_runtime\",\n \"path\": \"crates/event_store/src/source_maintenance_v1.rs\",\n \"byte_length\": 51849,\n \"sha256\": \"db43df5849c811d767a87bfa7884ce499400d0b169734e18242542a4415b3a51\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_food_result_vector_executor\",\n \"path\": \"crates/event_store/tests/food_availability_projection_v1_result_vector.rs\",\n \"byte_length\": 34046,\n \"sha256\": \"776903c6431ff07f26c6ad6b713db5628efce1a72f34d86de6e47d4404fa3a6d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"artifact_transaction_authority\",\n \"path\": \"tools/xtask/src/contract/artifact_bundle.rs\",\n \"byte_length\": 39149,\n \"sha256\": \"3d1bba3980b80698d2a21e26caf7af6fe4d9dc4a7fbabc6e406b5d33928b457f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_successor_governance\",\n \"path\": \"tools/xtask/src/contract/food_availability_projection.rs\",\n \"byte_length\": 198991,\n \"sha256\": \"36fd3d8b5dda3b0855a06a47dae14cae7f4cc84aaca9902c31477c218859fccc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"transitive_predecessor_membership_governance\",\n \"path\": \"tools/xtask/src/contract/nip09_reconciliation.rs\",\n \"byte_length\": 842402,\n \"sha256\": \"4abb141771cfa257440dba7ebeae21f5ad1f9856cc0d5f6437ba68614d997810\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_governance\",\n \"path\": \"tools/xtask/src/contract/source_maintenance.rs\",\n \"byte_length\": 199270,\n \"sha256\": \"65b83a3ee1a700527d15c7403ca042cf2aaa4cd8935a2f8d2ab190c491a815bd\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"contract_command_authority\",\n \"path\": \"tools/xtask/src/contract.rs\",\n \"byte_length\": 508374,\n \"sha256\": \"c498f6fda5e595c7165465a9f261b45acc7ef47762e1fc04fd94026f9ecf2167\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"dto_root_generation_authority\",\n \"path\": \"tools/xtask/src/dto_roots.rs\",\n \"byte_length\": 35940,\n \"sha256\": \"a899a5695d7533c151d03477c4bd697a6e55c47a4980549724ac42046af694f5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"xtask_dispatch_and_release_preflight\",\n \"path\": \"tools/xtask/src/main.rs\",\n \"byte_length\": 16426,\n \"sha256\": \"abc24896c6c740c10811a3e003ec4be8ebdb376a7b6b01445bfa7a5889f094a7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n ],\n \"public_api\": {\n \"inherited_predecessor_symbols\": [\n \"RADROOTS_ADDRESSABLE_TRANSITION_CURSOR_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_D_TAG_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_FEED_VERSION_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_RAW_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_SCAN_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_SCOPE_KIND_MAX_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_APPLY_PAGE_LIMIT_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_VERSION_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_BYTES_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_TERMS_V1\",\n \"RadrootsAddressableTransitionCauseV1\",\n \"RadrootsAddressableTransitionCoordinateV1\",\n \"RadrootsAddressableTransitionCursorV1\",\n \"RadrootsAddressableTransitionEventReferenceV1\",\n \"RadrootsAddressableTransitionOriginV1\",\n \"RadrootsAddressableTransitionPageV1\",\n \"RadrootsAddressableTransitionRawHeadDecisionV1\",\n \"RadrootsAddressableTransitionScopeFingerprintV1\",\n \"RadrootsAddressableTransitionScopeV1\",\n \"RadrootsAddressableTransitionV1\",\n \"RadrootsAddressableTransitionVisibilityV1\",\n \"RadrootsCurrentEventVisibilityV1\",\n \"RadrootsCurrentVisibilityDecisionV1\",\n \"RadrootsFoodAvailabilitySearchQueryV1\",\n \"RadrootsFoodAvailabilityStatusFilterV1\",\n \"RadrootsNip09SuppressionEvidenceV1\",\n \"RadrootsNip09SuppressionOutcome\",\n \"RadrootsNip09SuppressionReason\",\n \"RadrootsStoreProducedCanonicalEventV1\",\n \"RadrootsStoredFoodAvailabilityImageV1\",\n \"RadrootsStoredFoodAvailabilityV1\"\n ],\n \"added_symbols\": [\n \"RADROOTS_EVENT_STORE_RAW_EVENT_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_EVENT_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RETAINED_SOURCE_GENERATION_LIMIT_V1\",\n \"RadrootsEventStoreSourceCapacityResourceV1\",\n \"RadrootsEventStoreSourceCapacityV1\"\n ],\n \"methods\": [\n \"RadrootsEventStore::source_capacity_v1\",\n \"RadrootsEventStoreSourceCapacityResourceV1::as_str\",\n \"RadrootsEventStoreSourceCapacityV1::source_generation\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_high_water_seq\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_count\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_limit\"\n ],\n \"error_variants\": [\n \"SourceCapacityExceeded\",\n \"SourceGenerationHistoryLimitReached\",\n \"PersistedEphemeralRawEvent\",\n \"SourceCapacityStateDrift\",\n \"SqliteMainDatabaseEncodingNotUtf8\",\n \"RollbackWouldDiscardSourceGenerationHistory\"\n ],\n \"removed_symbols\": [\n \"RadrootsEventStoreReconciliationResource\",\n \"RadrootsEventStoreError::ReconciliationCapacityExceeded\"\n ],\n \"breaking_replacements\": [\n {\n \"removed\": \"RadrootsEventStoreReconciliationResource\",\n \"replacement\": \"RadrootsEventStoreSourceCapacityResourceV1\"\n },\n {\n \"removed\": \"RadrootsEventStoreError::ReconciliationCapacityExceeded\",\n \"replacement\": \"RadrootsEventStoreError::SourceCapacityExceeded\"\n }\n ]\n },\n \"result_vector\": {\n \"canonical_path\": \"contracts/conformance/vectors/event_store/source_maintenance.v1.json\",\n \"mirror_path\": \"crates/event_store/tests/fixtures/source_maintenance.v1.json\",\n \"byte_length\": 16253,\n \"sha256\": \"997aba2604a2b9d199fb87dc9d07942ca50d91863aeadcf3eeacf16d191dd71f\",\n \"hash_algorithm\": \"sha256_bytes_v1\",\n \"executor_id\": \"radroots_event_store.source_maintenance_v1.result_vector_executor.v1\",\n \"executor_path\": \"crates/event_store/tests/source_maintenance_v1_result_vector.rs\",\n \"executor_test\": \"source_maintenance_v1_result_vector\",\n \"executor_byte_length\": 23510,\n \"executor_sha256\": \"a7487afdfe19fc5fc794811d0f0e6035203e1aabcf0a33a1d398f6b3555d38f3\",\n \"executor_hash_algorithm\": \"sha256_bytes_v1\"\n }\n}\n"; +pub(crate) const SOURCE_MAINTENANCE_MANIFEST_JSON: &str = "{\n \"schema_version\": 1,\n \"contract_id\": \"radroots_event_store.source_maintenance_v1\",\n \"hook_id\": \"source_maintenance_v1\",\n \"manifest_schema\": {\n \"path\": \"crates/event_store/contracts/source_maintenance_v1.manifest.schema.json\",\n \"byte_length\": 12315,\n \"sha256\": \"96ea98a5abf3348b61565954cd34f2c622411d8dd34205ef04134bbe0e3d3f2b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"predecessor\": {\n \"hook_id\": \"food_availability_projection_v1\",\n \"manifest\": {\n \"path\": \"crates/event_store/contracts/food_availability_projection_v1.manifest.json\",\n \"byte_length\": 17455,\n \"sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n },\n \"migration\": {\n \"version\": 4,\n \"name\": \"source_maintenance\",\n \"up\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.up.sql\",\n \"byte_length\": 19841,\n \"sha256\": \"ab2724188f8d08c897eebea2533a635e7c74282a25e84e4c0c37e78b08837a43\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"down\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.down.sql\",\n \"byte_length\": 5172,\n \"sha256\": \"fe44fd53c51545c08ea479b385e6781079dab70fc63da2a3c205d727a00ce860\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"schema_sha256\": \"074f85b663444ac150239ecd8441ea4a96ad83a798a55e22d2e5e2f7ee943a8c\",\n \"catalog\": {\n \"objects\": [\n \"radroots_event_store_source_capacity_delete_guard\",\n \"radroots_event_store_source_capacity_insert_guard\",\n \"radroots_event_store_source_capacity_marker_close_guard\",\n \"radroots_event_store_source_capacity_update_guard\",\n \"radroots_event_store_source_capacity_v1\",\n \"radroots_event_store_source_generation_capacity_advance\",\n \"radroots_event_store_source_generation_capacity_guard\"\n ],\n \"replaced_objects\": [\n \"radroots_event_store_food_availability_image_delete_guard\",\n \"radroots_event_store_food_availability_projection_delete_guard\",\n \"radroots_event_store_source_rebuild_marker_insert_guard\"\n ],\n \"tables\": [\n \"radroots_event_store_source_capacity_v1\"\n ],\n \"fts5_tables\": []\n }\n },\n \"source_maintenance\": {\n \"version\": 1,\n \"event_contract_registry_version\": 7,\n \"capacity_authority_id\": \"radroots_event_store_source_capacity_v1\",\n \"accounting\": {\n \"algorithm\": \"sqlite_cast_blob_octet_sum_v1\",\n \"raw_event_columns\": [\n \"event_id\",\n \"pubkey\",\n \"tags_json\",\n \"content\",\n \"sig\",\n \"raw_json\"\n ],\n \"raw_tag_columns\": [\n \"event_id\",\n \"tag_name\",\n \"tag_value\",\n \"tag_json\"\n ],\n \"nullable_raw_tag_columns\": [\n \"tag_value\"\n ]\n },\n \"limits\": {\n \"raw_events\": 25000,\n \"raw_tags\": 250000,\n \"raw_event_text_bytes\": 67108864,\n \"raw_tag_text_bytes\": 33554432,\n \"retained_source_generations\": 8\n },\n \"reopen_validation\": {\n \"mode\": \"bounded_full_raw_recount_v1\",\n \"raw_event_rejection_scan_bound\": 25001,\n \"raw_tag_rejection_scan_bound\": 250001,\n \"generation_history_validation\": \"bounded_count_plus_active_ordinal_v1\",\n \"retained_generation_rejection_scan_bound\": 9\n },\n \"rebuild_seal\": {\n \"nip09_hook_id\": \"nip09_reconciliation_v1\",\n \"nip09_manifest_sha256\": \"74af832420ffbaa9805e89df3c0b34f126a443e1598f757e3372f407f9003b77\",\n \"food_hook_id\": \"food_availability_projection_v1\",\n \"food_manifest_sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"food_scope_fingerprint_sha256\": \"8b63c5ddc48a2cc7db69295238b96d5f814dba50427c80b4d0079f061e6d3de0\",\n \"active_generation_authority\": \"radroots_event_store_source_state\",\n \"marker_close_authority\": \"radroots_event_store_source_capacity_marker_close_guard\"\n }\n },\n \"entry_points\": [\n {\n \"role\": \"migration_registry\",\n \"rust_path\": \"radroots_event_store::migrations::EVENT_STORE_MIGRATIONS[3]\"\n },\n {\n \"role\": \"migration_apply_hook\",\n \"rust_path\": \"radroots_event_store::schema::apply_migration_hook\"\n },\n {\n \"role\": \"migration_validation_hook\",\n \"rust_path\": \"radroots_event_store::schema::validate_migration_hook_state\"\n },\n {\n \"role\": \"capacity_query\",\n \"rust_path\": \"radroots_event_store::RadrootsEventStore::source_capacity_v1\"\n },\n {\n \"role\": \"raw_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_unique_raw_source_append_v1\"\n },\n {\n \"role\": \"raw_append_advance\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::advance_source_capacity_after_insert_v1\"\n },\n {\n \"role\": \"generation_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_source_generation_append_v1\"\n },\n {\n \"role\": \"generation_rebuild_bind\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::bind_source_capacity_to_generation_v1\"\n },\n {\n \"role\": \"sqlite_encoding_preflight\",\n \"rust_path\": \"radroots_event_store::store::validate_main_database_encoding\"\n },\n {\n \"role\": \"source_generation_history_rollback_guard\",\n \"rust_path\": \"radroots_event_store::schema::validate_rollback_preserves_source_generation_history\"\n },\n {\n \"role\": \"result_vector_executor\",\n \"rust_path\": \"source_maintenance_v1_result_vector\"\n }\n ],\n \"source_files\": [\n {\n \"role\": \"workspace_dependency_authority\",\n \"path\": \"Cargo.toml\",\n \"byte_length\": 12440,\n \"sha256\": \"8981f78d3ea85454a8cf7be156b3eef5659b399f1631d7c1068e7c336988070d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_currency_value_authority\",\n \"path\": \"crates/core/src/currency.rs\",\n \"byte_length\": 4142,\n \"sha256\": \"42e6da2d8d2fdd6955dc2d83e98dd00266e02bc910b69923b117662c05089d14\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_decimal_value_authority\",\n \"path\": \"crates/core/src/decimal.rs\",\n \"byte_length\": 7839,\n \"sha256\": \"4b1d681a92d7a9e074bee7e1f20eb1499bb05bfc6528a6c9ba69fa7d00416550\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_money_value_authority\",\n \"path\": \"crates/core/src/money.rs\",\n \"byte_length\": 8025,\n \"sha256\": \"3f30bc21e21951a62fdc5d4033736ed42a883df590e8403940775bd2edfeebc5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_percent_value_authority\",\n \"path\": \"crates/core/src/percent.rs\",\n \"byte_length\": 2652,\n \"sha256\": \"42ceab109881329f3539d06a0ee0381ab4359985fe185a18d58a9c9558c5eb7f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_value_authority\",\n \"path\": \"crates/core/src/quantity.rs\",\n \"byte_length\": 6785,\n \"sha256\": \"d14e619da3829cdaf3ca7385fb892d330c286c1e21455c135c37518cbb588b5f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_price_value_authority\",\n \"path\": \"crates/core/src/quantity_price.rs\",\n \"byte_length\": 7061,\n \"sha256\": \"d60f70377099470ed283f45868a5119d7bb46143cb250b5082a4c038ba7f6cdc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_unit_value_authority\",\n \"path\": \"crates/core/src/unit.rs\",\n \"byte_length\": 10023,\n \"sha256\": \"550e9582b6a5290aac3f637b83853b21fefcbab92c432d067c83448f4b2fe3e9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_public_surface\",\n \"path\": \"crates/blossom/src/lib.rs\",\n \"byte_length\": 510,\n \"sha256\": \"a4dfcbd193457c50c1b0fbfc91bb547981ecd3a6e23cfc6f1030edfb511dc58c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_authorization_authority\",\n \"path\": \"crates/blossom/src/authorization.rs\",\n \"byte_length\": 39360,\n \"sha256\": \"461947b30516315a342b3b5697599f701d27050888f29f67f5d7a7ad4afa4c28\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_descriptor_authority\",\n \"path\": \"crates/blossom/src/descriptor.rs\",\n \"byte_length\": 13702,\n \"sha256\": \"b2a4ffa760256e1316f70e012d200e2b5f4afd8ede771b85a5147f96b247f599\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_error_authority\",\n \"path\": \"crates/blossom/src/error.rs\",\n \"byte_length\": 17229,\n \"sha256\": \"02af55beacf437040be17d1fc3271d6e2a62915f656ec2dbe06247deef83f95a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_hash_authority\",\n \"path\": \"crates/blossom/src/hash.rs\",\n \"byte_length\": 11006,\n \"sha256\": \"45eca0d81ac0f46c305a32f81aafcdd90b14679d0614f72862289a6e5d4cb08f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_media_type_authority\",\n \"path\": \"crates/blossom/src/media_type.rs\",\n \"byte_length\": 2368,\n \"sha256\": \"69db5c0f9fcdd7dbe1f22daa499f65603ae4ce198083dab2c73a36813fa18a46\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_url_authority\",\n \"path\": \"crates/blossom/src/url.rs\",\n \"byte_length\": 14580,\n \"sha256\": \"342c995fcf620e5fb32461a7d8276f5668ba2662890bd32d12780cc9121c6451\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_public_surface\",\n \"path\": \"crates/event/src/lib.rs\",\n \"byte_length\": 1892,\n \"sha256\": \"5d609b963a9b8db18ef96a10f394617413734d2631774d3296e6d8fc029cb02c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_facade\",\n \"path\": \"crates/event/src/contract.rs\",\n \"byte_length\": 208,\n \"sha256\": \"27466bf36461071931f391c60646a13f7781d19584583166cc54c0eece76d010\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_registry_v7_authority\",\n \"path\": \"crates/event/src/contract/registry_v7.rs\",\n \"byte_length\": 145805,\n \"sha256\": \"0a62603f6fc05dc9f758561cf7da258c676ada810ceaeca7fb151364a5c83d62\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_envelope_authority\",\n \"path\": \"crates/event/src/envelope.rs\",\n \"byte_length\": 29310,\n \"sha256\": \"29f8d8c4b17c01cb5a8c7f59e4ce52e134180e0e6f37d265063d278b8f2ff26e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_verification_typestate_authority\",\n \"path\": \"crates/event/src/verification.rs\",\n \"byte_length\": 9400,\n \"sha256\": \"417acb2ce670d266b1fa4fcafd6b48a910218deab38f57fb8b942056db76f94d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_admission_typestate_authority\",\n \"path\": \"crates/event/src/admission.rs\",\n \"byte_length\": 7052,\n \"sha256\": \"62bd2ceb0f434946fdfc2b81f4efb13738676a29a6936c23a427e43aadf2d9cb\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_facade\",\n \"path\": \"crates/event/src/event_head.rs\",\n \"byte_length\": 97,\n \"sha256\": \"f761ff3e74c4f5e1e28381db00ce698c633ff048669b22984d14a587482e8e83\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_v1_authority\",\n \"path\": \"crates/event/src/event_head/v1.rs\",\n \"byte_length\": 6849,\n \"sha256\": \"9f4144d8d240023cf493ce0b538ade4c16dc44204d6b5f2797152caf6f9e7dba\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_ids_authority\",\n \"path\": \"crates/event/src/id.rs\",\n \"byte_length\": 48381,\n \"sha256\": \"a08fe3873815453a03318a706e2fa98a8a6728ec69d24368a87ec60025566fe0\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_trade_authority\",\n \"path\": \"crates/event/src/trade.rs\",\n \"byte_length\": 65549,\n \"sha256\": \"f818a7287ed82de3fb9ef1d973f0fb18d84b30eb4827ddc576ee502dd980145f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_kinds_authority\",\n \"path\": \"crates/event/src/kinds.rs\",\n \"byte_length\": 34961,\n \"sha256\": \"8b3ce6193cab1f7e1587d0c1b2880a81b0aa43c77d89671b602772db37edcebf\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_tags_authority\",\n \"path\": \"crates/event/src/tags.rs\",\n \"byte_length\": 4530,\n \"sha256\": \"cb8f12a639fc72d9238e32495d9e67e928e6627fb8c94ec0a58c5d95e7373cd6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_draft_authority\",\n \"path\": \"crates/event/src/draft.rs\",\n \"byte_length\": 51150,\n \"sha256\": \"ecc619aae28d688d13f35467398f17766b60f26c2bf3616d772ce65b7fa4fb53\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_calendar_authority\",\n \"path\": \"crates/event/src/calendar.rs\",\n \"byte_length\": 97992,\n \"sha256\": \"73e79d61ee175cb46e6123e1d28239252ddf0ad094dc1113bdb1286b63b88d57\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_classified_listing_authority\",\n \"path\": \"crates/event/src/classified_listing.rs\",\n \"byte_length\": 7956,\n \"sha256\": \"ac58484b87c7712c81f50f884d1c0dd60938571aa5f6f05d555191f529a4c2b0\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_profile_authority\",\n \"path\": \"crates/event/src/profile.rs\",\n \"byte_length\": 17011,\n \"sha256\": \"572bfe3b6f1711d109db445077f0a8453cad3f021cc0638f79201b618e16b978\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_post_authority\",\n \"path\": \"crates/event/src/post.rs\",\n \"byte_length\": 19968,\n \"sha256\": \"a822cd51eff9cbaa39db998cc5c90d117f7a983f0fe2d42d42118cb00e95982c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_comment_authority\",\n \"path\": \"crates/event/src/comment.rs\",\n \"byte_length\": 34745,\n \"sha256\": \"24b7fda13229f21cee5cef2a9941e3aaafdbc486b19ed42731b0b6ee37c28703\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_food_availability_authority\",\n \"path\": \"crates/event/src/food_availability.rs\",\n \"byte_length\": 42829,\n \"sha256\": \"52472c07eb0855d884c60755dc3a3e1a963793451d707e51f769f2d78384f318\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_deletion_authority\",\n \"path\": \"crates/event/src/deletion.rs\",\n \"byte_length\": 30022,\n \"sha256\": \"8c3f2e32407520a8e8242c1293af32613c648fb76218b8003a18929ac0b3811f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_dto_authority\",\n \"path\": \"crates/event/src/dto.rs\",\n \"byte_length\": 5038,\n \"sha256\": \"9e228c95ff6ff33f99441d8682781fd0a1c4d3f1db24284a43985dcbac3ba136\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_farm_crdt_authority\",\n \"path\": \"crates/event/src/farm_crdt.rs\",\n \"byte_length\": 21118,\n \"sha256\": \"cec265ac9c42b59a14be4eb96924d26a83477c27291f667f23e6e47a64b6b2c7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_knowledge_authority\",\n \"path\": \"crates/event/src/knowledge.rs\",\n \"byte_length\": 54624,\n \"sha256\": \"3d55ff88a4e30d5d605f9ae4b2e96b9df6978d6c14e52f9aeb0b8039cfc200d7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_operational_listing_authority\",\n \"path\": \"crates/event/src/operational_listing.rs\",\n \"byte_length\": 10307,\n \"sha256\": \"52e710db816c89c8d4b87c86541987f7447f2f7091c394c68d9cb98a27f90159\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_order_authority\",\n \"path\": \"crates/event/src/order.rs\",\n \"byte_length\": 60218,\n \"sha256\": \"4203fcc469612cac5c705884564e140b9fb076cd57079e22ed85275a8b936e50\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_reply_authority\",\n \"path\": \"crates/event/src/reply.rs\",\n \"byte_length\": 15581,\n \"sha256\": \"b0b83a1e96125c0892d932e9314519242a715fa8f46334aff765ffd248c91d9a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_trade_validation_authority\",\n \"path\": \"crates/event/src/trade_validation.rs\",\n \"byte_length\": 4669,\n \"sha256\": \"1486f79bd1d0eadea6cc1b7646ce1f7f57ccade18334a3ea37286426676b9b98\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_relay_hint_authority\",\n \"path\": \"crates/event/src/relay_hint.rs\",\n \"byte_length\": 13598,\n \"sha256\": \"fb8b026eeccf51d78f20771c44223e7b48825aa0e3c760d6b3cb90148021a674\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_media_authority\",\n \"path\": \"crates/event/src/media.rs\",\n \"byte_length\": 3455,\n \"sha256\": \"10678af3a202d5367dbcf3bcdc0bf9fdf8d8fb89b045d7d3fb96b3cc195ab6f9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_social_authority\",\n \"path\": \"crates/event/src/social.rs\",\n \"byte_length\": 6076,\n \"sha256\": \"a2dab19caad46eab14fac86e7c878a801a450d8ac374b0e728b71a5a224eef19\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_facade\",\n \"path\": \"crates/event/src/wire.rs\",\n \"byte_length\": 68,\n \"sha256\": \"cb52f6006f7ecd862707d6b048f9fc407e0cd5ebcd3091b3c54e195ffa5cba64\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_v1_authority\",\n \"path\": \"crates/event/src/wire/v1.rs\",\n \"byte_length\": 22198,\n \"sha256\": \"c818bc1f67e215948ba253c8c62b09ab788db9aeec9b6df8096014b55565cb8c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_public_surface\",\n \"path\": \"crates/event_codec/src/lib.rs\",\n \"byte_length\": 2448,\n \"sha256\": \"7d4b0040ad3971f34395b17cb1aa40617e9c2c9e1b4222676c388c3adaa47e07\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_facade\",\n \"path\": \"crates/event_codec/src/verification.rs\",\n \"byte_length\": 253,\n \"sha256\": \"b49a32df605035c87f295c0a151140d43d2e588c5e11b05183e5fc92993dae0e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_v1_authority\",\n \"path\": \"crates/event_codec/src/verification/v1.rs\",\n \"byte_length\": 6584,\n \"sha256\": \"72f64615bd6b6dc3b051579e3069b2213f3781dcc28e12f0b533c7d81b81b9b1\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_registry_v7_admission_authority\",\n \"path\": \"crates/event_codec/src/admission/registry_v7.rs\",\n \"byte_length\": 5228,\n \"sha256\": \"62da30cb6ef7d0ed2d43715a73bd529283e8ae8c12571bc5c68722cb400f17b8\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_admission_facade\",\n \"path\": \"crates/event_codec/src/admission.rs\",\n \"byte_length\": 21251,\n \"sha256\": \"25928e734e7b3688f92af806a12a13458c48fb47e94249f60f0226300d5da2b4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_inbound_facade\",\n \"path\": \"crates/event_codec/src/profile/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/profile/inbound/registry_v7.rs\",\n \"byte_length\": 10347,\n \"sha256\": \"32111c0e0592229c11a93a3a8054e7b124b039451aa696a9abcb56df2a6608d3\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_inbound_facade\",\n \"path\": \"crates/event_codec/src/post/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/post/inbound/registry_v7.rs\",\n \"byte_length\": 15985,\n \"sha256\": \"e17083b0596e3a55994c399bc6272c0ebf04cabaa513260b3d45dd546f7f50ef\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_inbound_facade\",\n \"path\": \"crates/event_codec/src/reply/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/reply/inbound/registry_v7.rs\",\n \"byte_length\": 26662,\n \"sha256\": \"d1d11116ca27801b7e2f17da60900e6a9ca0b6f27ea9ee0bf19e97dbf24c0c32\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_inbound_facade\",\n \"path\": \"crates/event_codec/src/comment/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/comment/inbound/registry_v7.rs\",\n \"byte_length\": 53311,\n \"sha256\": \"c63fe853536b17bded6073f32b53434b60fc5123f911d01c642a6b3982f09c70\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_facade\",\n \"path\": \"crates/event_codec/src/deletion/mod.rs\",\n \"byte_length\": 115,\n \"sha256\": \"17d56f82ddb0a86bc97abbcf3e037fe460ea31fff2548f527be4bf004dac3a95\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_reconciliation_v1_authority\",\n \"path\": \"crates/event_codec/src/deletion/reconciliation_v1.rs\",\n \"byte_length\": 38028,\n \"sha256\": \"c6901f559e83700610595720c47a4d062078ae8411e1fc2fb952dd215b19dd90\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_error_authority\",\n \"path\": \"crates/event_codec/src/error.rs\",\n \"byte_length\": 3666,\n \"sha256\": \"174ce982bca37fac28d016c3ab3236441c9b31b2169ec94db6c9288b36c72849\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_admission_authority\",\n \"path\": \"crates/event_codec/src/food_availability/admission.rs\",\n \"byte_length\": 5681,\n \"sha256\": \"99809859090f5295572688d06bbb30dbe50524ba2c996de7ec5b26f6dd390643\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_authored_authority\",\n \"path\": \"crates/event_codec/src/food_availability/authored.rs\",\n \"byte_length\": 9724,\n \"sha256\": \"8673ec62ed3fc47b691efd9ca828643719803971e72b756c5b4603d409d0fba5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_inbound_facade\",\n \"path\": \"crates/event_codec/src/food_availability/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/food_availability/inbound/registry_v7.rs\",\n \"byte_length\": 26037,\n \"sha256\": \"92a7e75da3293967cec17a514479144c3c948a64542577dd58c7f07992968e4f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_job_traits_authority\",\n \"path\": \"crates/event_codec/src/job/traits.rs\",\n \"byte_length\": 4946,\n \"sha256\": \"1b3558a3196744005978dceddd33d3a72ad1ab8f50fb1cbfd997dcfe98bb9e39\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_job_encode_authority\",\n \"path\": \"crates/event_codec/src/job/encode.rs\",\n \"byte_length\": 1670,\n \"sha256\": \"5d6cae6309fcdd02deb7c751b5c451d257cf1900986391cb39cbb2bfd1ddb577\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_knowledge_verification_authority\",\n \"path\": \"crates/event_codec/src/knowledge/verification.rs\",\n \"byte_length\": 6986,\n \"sha256\": \"6f8a10ed262ce37f05acd9c89a1e37ca2fa99ce7da18407891e8abe228ee2349\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_operational_listing_tags_authority\",\n \"path\": \"crates/event_codec/src/operational_listing/tags.rs\",\n \"byte_length\": 50222,\n \"sha256\": \"55b6860bc6f4699dd47a49f8336764e9db78aafb7c32849102dedeb96804b373\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_order_decode_authority\",\n \"path\": \"crates/event_codec/src/order/decode.rs\",\n \"byte_length\": 42667,\n \"sha256\": \"033d9465bc041d205eab3f820572b719a35651340dcb50bdce7c60fabee5f6e1\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_facade\",\n \"path\": \"crates/event_codec/src/profile/mod.rs\",\n \"byte_length\": 1456,\n \"sha256\": \"06b890da54580e2ec68f7e729281b7c3b650ac0a95a4fcb0db3c6cdaa591a7ef\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_tag_builders_authority\",\n \"path\": \"crates/event_codec/src/tag_builders.rs\",\n \"byte_length\": 9232,\n \"sha256\": \"bd81ccf04fd72358331b48eddcde087a95e115c5bd90c05fd9332644979ad5e6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_trade_facade\",\n \"path\": \"crates/event_codec/src/trade/mod.rs\",\n \"byte_length\": 21472,\n \"sha256\": \"10cee4b6cd6429ac9eb00327a521bcd0982fae4de98bda77e4728fda002965d3\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_dependency_authority\",\n \"path\": \"crates/event_store/Cargo.toml\",\n \"byte_length\": 1570,\n \"sha256\": \"e2116eb02eb2b18b21db7351f29a1efeffe11ce4ab9bb7c85a3f3e7f2e56aca4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_error_and_limits\",\n \"path\": \"crates/event_store/src/error.rs\",\n \"byte_length\": 19458,\n \"sha256\": \"3d87df984af6ae5decf7ca8c3a8d5422be6c647e6a05490225b6b2037bf3701b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"generated_descriptor_registration\",\n \"path\": \"crates/event_store/src/generated.rs\",\n \"byte_length\": 144,\n \"sha256\": \"6b0a8d6f249bd4fc3f878d37cb5e418680f0f1be2d9eec2518dedf03efc47121\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_surface\",\n \"path\": \"crates/event_store/src/lib.rs\",\n \"byte_length\": 3844,\n \"sha256\": \"3cd9653bcb752fb3c4442d4904b98a0a6208011a9a238125b7b7073d7f4e312b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"migration_registry\",\n \"path\": \"crates/event_store/src/migrations.rs\",\n \"byte_length\": 73585,\n \"sha256\": \"a47477d04759ec6e71d14d3d05459864eae78fce0e3c2481a1b03147f04637f7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_model_public_surface\",\n \"path\": \"crates/event_store/src/model.rs\",\n \"byte_length\": 32070,\n \"sha256\": \"2cdbf6d1a4e0fa6680f45f02758513509339a7cf3a2387e824fb73b0edf749a4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_model\",\n \"path\": \"crates/event_store/src/model/reconciliation_v1.rs\",\n \"byte_length\": 10446,\n \"sha256\": \"475b7b840bffdae7e3f7a31f5b940b9dfa579eaa1cac640729aaaeadabf83ba6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_ingest_model\",\n \"path\": \"crates/event_store/src/model/ingest_reconciliation_v1.rs\",\n \"byte_length\": 1588,\n \"sha256\": \"6117e797674c35bb1ccebffbc6a8c0108bfc38c7c9f82607066dfd802b8f0734\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_model\",\n \"path\": \"crates/event_store/src/model/addressable_transition_feed_v1.rs\",\n \"byte_length\": 22229,\n \"sha256\": \"e651952d73ed0a29d2b137076f56f699beada205ac84ed8a96834e86e343fa78\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"current_visibility_model\",\n \"path\": \"crates/event_store/src/model/current_visibility_v1.rs\",\n \"byte_length\": 5634,\n \"sha256\": \"d64429bc7985231e923c1c3e5295d94270a817dd5dc96693f35dfdf2dc398e4f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_model\",\n \"path\": \"crates/event_store/src/model/food_availability_projection_v1.rs\",\n \"byte_length\": 17108,\n \"sha256\": \"67861a966d674efbc40f0b0433db2ec006048ff923f6261df4161e2ddba717b5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_generation_rebuild_authority\",\n \"path\": \"crates/event_store/src/nip09/reconciliation_v1.rs\",\n \"byte_length\": 184833,\n \"sha256\": \"3ca802cb7a8444c8512b2be1390a019281704316a430fb9b75a8ad2cad358a07\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"nip09_successor_result_vector_executor\",\n \"path\": \"crates/event_store/tests/support/nip09_reconciliation_v1_result_vector_v2.rs\",\n \"byte_length\": 18205,\n \"sha256\": \"c632beee70dc777b8dd2a4f88cadb55296fee7aa5742e6e2c9f6d49f26ae2c78\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"schema_migration_and_reopen_authority\",\n \"path\": \"crates/event_store/src/schema.rs\",\n \"byte_length\": 146146,\n \"sha256\": \"93b060e80d3edd73f86208e4bf698fa9d53eaf1eeb04526c9261fb8b5726fb0d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_store_and_transaction_authority\",\n \"path\": \"crates/event_store/src/store.rs\",\n \"byte_length\": 393218,\n \"sha256\": \"64565c3bc043779e1c2f26d9761901b109b4acab0f48c2021102c0e4e1f1f726\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_store\",\n \"path\": \"crates/event_store/src/store/addressable_transition_feed_v1.rs\",\n \"byte_length\": 40209,\n \"sha256\": \"2cebcca9602633652a79e7041d18d3a7d3feb1388a98f4f68137b9814efcedfa\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"current_visibility_store\",\n \"path\": \"crates/event_store/src/store/current_visibility_v1.rs\",\n \"byte_length\": 15737,\n \"sha256\": \"aa5d1bff7a5368cbac2b37906bb40f54bfc8aa6906bab34369569fdd105bf899\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_store\",\n \"path\": \"crates/event_store/src/store/food_availability_projection_v1.rs\",\n \"byte_length\": 48919,\n \"sha256\": \"3a30da308ef863b806ed63d1cb65ac80f6a946a71821af84a0c595330491757e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_extension\",\n \"path\": \"crates/event_store/src/store/post_core_extensions_v1.rs\",\n \"byte_length\": 6569,\n \"sha256\": \"f5bd8ddb45e1b2144895bd8da737fc92db051be1844ce7e8047a32b47376ce37\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_storage\",\n \"path\": \"crates/event_store/src/store/post_core_storage_v1.rs\",\n \"byte_length\": 16538,\n \"sha256\": \"fcd6546c23a6cba12b70d92728d19b6ee5d43174b83495f820348b77efa33aab\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"raw_ingest_capacity_authority\",\n \"path\": \"crates/event_store/src/store/protocol_reconciliation_v1.rs\",\n \"byte_length\": 29950,\n \"sha256\": \"c72aaff06e4f35d0b4523c6625e83345879f9e15b9fe9563dccf589e5d01e277\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_protocol_storage\",\n \"path\": \"crates/event_store/src/store/protocol_storage_v1.rs\",\n \"byte_length\": 10835,\n \"sha256\": \"c82179b9f57968191f3e71dd008cc701787c62715ada74090eeecaa3b213076d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_runtime\",\n \"path\": \"crates/event_store/src/source_maintenance_v1.rs\",\n \"byte_length\": 51849,\n \"sha256\": \"db43df5849c811d767a87bfa7884ce499400d0b169734e18242542a4415b3a51\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_food_result_vector_executor\",\n \"path\": \"crates/event_store/tests/food_availability_projection_v1_result_vector.rs\",\n \"byte_length\": 34046,\n \"sha256\": \"776903c6431ff07f26c6ad6b713db5628efce1a72f34d86de6e47d4404fa3a6d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"artifact_transaction_authority\",\n \"path\": \"tools/xtask/src/contract/artifact_bundle.rs\",\n \"byte_length\": 39149,\n \"sha256\": \"3d1bba3980b80698d2a21e26caf7af6fe4d9dc4a7fbabc6e406b5d33928b457f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_successor_governance\",\n \"path\": \"tools/xtask/src/contract/food_availability_projection.rs\",\n \"byte_length\": 198991,\n \"sha256\": \"36fd3d8b5dda3b0855a06a47dae14cae7f4cc84aaca9902c31477c218859fccc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"transitive_predecessor_membership_governance\",\n \"path\": \"tools/xtask/src/contract/nip09_reconciliation.rs\",\n \"byte_length\": 842402,\n \"sha256\": \"4abb141771cfa257440dba7ebeae21f5ad1f9856cc0d5f6437ba68614d997810\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_governance\",\n \"path\": \"tools/xtask/src/contract/source_maintenance.rs\",\n \"byte_length\": 199270,\n \"sha256\": \"65b83a3ee1a700527d15c7403ca042cf2aaa4cd8935a2f8d2ab190c491a815bd\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"contract_command_authority\",\n \"path\": \"tools/xtask/src/contract.rs\",\n \"byte_length\": 508073,\n \"sha256\": \"26d1825a0d7a4a3bb983478f2ef87dc228cbfb68f794bb52864e34a62ef1eead\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"dto_root_generation_authority\",\n \"path\": \"tools/xtask/src/dto_roots.rs\",\n \"byte_length\": 35940,\n \"sha256\": \"a899a5695d7533c151d03477c4bd697a6e55c47a4980549724ac42046af694f5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"xtask_dispatch_and_release_preflight\",\n \"path\": \"tools/xtask/src/main.rs\",\n \"byte_length\": 16426,\n \"sha256\": \"abc24896c6c740c10811a3e003ec4be8ebdb376a7b6b01445bfa7a5889f094a7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n ],\n \"public_api\": {\n \"inherited_predecessor_symbols\": [\n \"RADROOTS_ADDRESSABLE_TRANSITION_CURSOR_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_D_TAG_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_FEED_VERSION_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_RAW_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_SCAN_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_SCOPE_KIND_MAX_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_APPLY_PAGE_LIMIT_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_VERSION_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_BYTES_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_TERMS_V1\",\n \"RadrootsAddressableTransitionCauseV1\",\n \"RadrootsAddressableTransitionCoordinateV1\",\n \"RadrootsAddressableTransitionCursorV1\",\n \"RadrootsAddressableTransitionEventReferenceV1\",\n \"RadrootsAddressableTransitionOriginV1\",\n \"RadrootsAddressableTransitionPageV1\",\n \"RadrootsAddressableTransitionRawHeadDecisionV1\",\n \"RadrootsAddressableTransitionScopeFingerprintV1\",\n \"RadrootsAddressableTransitionScopeV1\",\n \"RadrootsAddressableTransitionV1\",\n \"RadrootsAddressableTransitionVisibilityV1\",\n \"RadrootsCurrentEventVisibilityV1\",\n \"RadrootsCurrentVisibilityDecisionV1\",\n \"RadrootsFoodAvailabilitySearchQueryV1\",\n \"RadrootsFoodAvailabilityStatusFilterV1\",\n \"RadrootsNip09SuppressionEvidenceV1\",\n \"RadrootsNip09SuppressionOutcome\",\n \"RadrootsNip09SuppressionReason\",\n \"RadrootsStoreProducedCanonicalEventV1\",\n \"RadrootsStoredFoodAvailabilityImageV1\",\n \"RadrootsStoredFoodAvailabilityV1\"\n ],\n \"added_symbols\": [\n \"RADROOTS_EVENT_STORE_RAW_EVENT_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_EVENT_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RETAINED_SOURCE_GENERATION_LIMIT_V1\",\n \"RadrootsEventStoreSourceCapacityResourceV1\",\n \"RadrootsEventStoreSourceCapacityV1\"\n ],\n \"methods\": [\n \"RadrootsEventStore::source_capacity_v1\",\n \"RadrootsEventStoreSourceCapacityResourceV1::as_str\",\n \"RadrootsEventStoreSourceCapacityV1::source_generation\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_high_water_seq\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_count\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_limit\"\n ],\n \"error_variants\": [\n \"SourceCapacityExceeded\",\n \"SourceGenerationHistoryLimitReached\",\n \"PersistedEphemeralRawEvent\",\n \"SourceCapacityStateDrift\",\n \"SqliteMainDatabaseEncodingNotUtf8\",\n \"RollbackWouldDiscardSourceGenerationHistory\"\n ],\n \"removed_symbols\": [\n \"RadrootsEventStoreReconciliationResource\",\n \"RadrootsEventStoreError::ReconciliationCapacityExceeded\"\n ],\n \"breaking_replacements\": [\n {\n \"removed\": \"RadrootsEventStoreReconciliationResource\",\n \"replacement\": \"RadrootsEventStoreSourceCapacityResourceV1\"\n },\n {\n \"removed\": \"RadrootsEventStoreError::ReconciliationCapacityExceeded\",\n \"replacement\": \"RadrootsEventStoreError::SourceCapacityExceeded\"\n }\n ]\n },\n \"result_vector\": {\n \"canonical_path\": \"contracts/conformance/vectors/event_store/source_maintenance.v1.json\",\n \"mirror_path\": \"crates/event_store/tests/fixtures/source_maintenance.v1.json\",\n \"byte_length\": 16253,\n \"sha256\": \"997aba2604a2b9d199fb87dc9d07942ca50d91863aeadcf3eeacf16d191dd71f\",\n \"hash_algorithm\": \"sha256_bytes_v1\",\n \"executor_id\": \"radroots_event_store.source_maintenance_v1.result_vector_executor.v1\",\n \"executor_path\": \"crates/event_store/tests/source_maintenance_v1_result_vector.rs\",\n \"executor_test\": \"source_maintenance_v1_result_vector\",\n \"executor_byte_length\": 23510,\n \"executor_sha256\": \"a7487afdfe19fc5fc794811d0f0e6035203e1aabcf0a33a1d398f6b3555d38f3\",\n \"executor_hash_algorithm\": \"sha256_bytes_v1\"\n }\n}\n"; pub(crate) const SOURCE_MAINTENANCE_MANIFEST_BYTE_LENGTH: usize = 38397; pub(crate) const SOURCE_MAINTENANCE_MANIFEST_SHA256: &str = - "032aab678a257acd2215d631b53d4883b41c74d023725d3ccd0518d8d5858a86"; + "ef7894006bc64f8b72718708f16babe3302209c6b1e74465def57d6b1862a9b6"; pub(crate) const SOURCE_MAINTENANCE_MANIFEST_SCHEMA_VERSION: u32 = 1; pub(crate) const SOURCE_MAINTENANCE_CONTRACT_ID: &str = "radroots_event_store.source_maintenance_v1"; diff --git a/crates/net/src/nostr_client/events/post.rs b/crates/net/src/nostr_client/events/post.rs @@ -1,16 +1,15 @@ use crate::error::{NetError, Result}; use radroots_event::{post::AuthoredUpdate, post::reply::AuthoredNip10Reply}; use radroots_event_codec::{parsed::RadrootsParsedData, post::decode::LegacyPost}; -use radroots_nostr::events::post::radroots_nostr_build_update_event; -use radroots_nostr::events::post::radroots_nostr_post_events_filter; -use radroots_nostr::events::reply::radroots_nostr_build_nip10_reply_event; +use radroots_nostr::event::build_nip10_reply; +use radroots_nostr::event::build_update; +use radroots_nostr::event::post_filter; use crate::nostr_client::manager::NostrClientManager; impl NostrClientManager { pub async fn publish_update_event(&self, update: &AuthoredUpdate) -> Result<String> { - let builder = - radroots_nostr_build_update_event(update).map_err(|e| NetError::Msg(e.to_string()))?; + let builder = build_update(update).map_err(|e| NetError::Msg(e.to_string()))?; let event = builder .sign_with_keys(&self.inner.keys) .map_err(|error| NetError::Msg(error.to_string()))?; @@ -30,8 +29,7 @@ impl NostrClientManager { } pub async fn publish_nip10_reply_event(&self, reply: &AuthoredNip10Reply) -> Result<String> { - let builder = radroots_nostr_build_nip10_reply_event(reply) - .map_err(|e| NetError::Msg(e.to_string()))?; + let builder = build_nip10_reply(reply).map_err(|e| NetError::Msg(e.to_string()))?; let event = builder .sign_with_keys(&self.inner.keys) .map_err(|error| NetError::Msg(error.to_string()))?; @@ -58,7 +56,7 @@ impl NostrClientManager { limit: u16, since_unix: Option<u64>, ) -> Result<Vec<RadrootsParsedData<LegacyPost>>> { - let filter = radroots_nostr_post_events_filter(Some(limit), since_unix); + let filter = post_filter(Some(limit), since_unix); let events = self .inner .client @@ -67,7 +65,7 @@ impl NostrClientManager { .map_err(|error| NetError::Msg(error.to_string()))?; Ok(events .into_iter() - .map(|event| radroots_nostr::event_adapters::to_post_event_metadata(&event)) + .map(|event| radroots_nostr::event::to_post_event_metadata(&event)) .collect()) } diff --git a/crates/net/src/nostr_client/events/profile.rs b/crates/net/src/nostr_client/events/profile.rs @@ -33,7 +33,7 @@ impl NostrClientManager { .filter(|event| event.kind == RadrootsNostrKind::Metadata) .max_by_key(|event| event.created_at); if let Some(e) = ev { - if let Some(meta) = radroots_nostr::event_adapters::to_profile_event_metadata(&e) { + if let Some(meta) = radroots_nostr::event::to_profile_event_metadata(&e) { return Ok(Some(meta)); } return Err(NetError::Msg( diff --git a/crates/net/src/nostr_client/manager.rs b/crates/net/src/nostr_client/manager.rs @@ -4,7 +4,7 @@ use tokio::runtime::Handle; use super::inner::Inner; use nostr::Keys as RadrootsNostrKeys; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; -use radroots_nostr::events::post::radroots_nostr_post_events_filter; +use radroots_nostr::event::post_filter; #[derive(Clone)] pub struct NostrClientManager { @@ -44,7 +44,7 @@ impl NostrClientManager { let mut since = since_unix.unwrap_or_else(|| RadrootsNostrTimestamp::now().as_secs()); loop { - let filter = radroots_nostr_post_events_filter(None, Some(since)); + let filter = post_filter(None, Some(since)); let mut stream = match inner .client @@ -59,7 +59,7 @@ impl NostrClientManager { }; while let Some(event) = stream.next().await { - let meta = radroots_nostr::event_adapters::to_post_event_metadata(&event); + let meta = radroots_nostr::event::to_post_event_metadata(&event); let ts = event.created_at.as_secs(); since = ts.saturating_add(1); let _ = inner.post_events_tx.send(meta); diff --git a/crates/nostr/COMPATIBILITY.md b/crates/nostr/COMPATIBILITY.md @@ -0,0 +1,20 @@ +# Superseded surface retirement + +`radroots_nostr` remains `publish = false` while Release V1 migration is in +progress. Step 133 removed its public `error`, `events`, `types`, `util`, +`codec_adapters`, `job_adapter`, `event_adapters`, `event_verify`, and +`draft_signing` paths, the unsupported `codec` feature, and every public +`radroots_nostr_*` item. The durable surface is limited to the seven modules +and single root `Error` export in the Release V1 package charter. + +An all-first-party source search also found separate OSS capsules that still +reference the predecessor `radroots_nostr::prelude` API. Those capsules are +outside the authorized `oss/lib` and `oss/sdk` crate-surface edit boundary and +already require their own upstream cutover; no compatibility path was restored +for them here. No new consumer may adopt any retired path. + +Step 313 is the exact final pre-release audit. It must repeat the all-first-party +search, confirm every separate capsule has migrated or pinned a compatible +upstream library revision, remove this migration record, regenerate the public +API baseline, and pass the package-realistic downstream matrix before Release +V1 approval. diff --git a/crates/nostr/Cargo.toml b/crates/nostr/Cargo.toml @@ -27,13 +27,12 @@ std = [ "radroots_identity/std", ] blossom = ["std", "dep:base64", "dep:radroots_blossom"] -codec = [] events = [ "std", "radroots_event/serde", "radroots_event_codec/json", ] -nip17 = ["std", "codec", "nostr/nip44", "nostr/nip59"] +nip17 = ["events", "nostr/nip44", "nostr/nip59"] signing = [ "events", "dep:radroots_signing", @@ -80,15 +79,15 @@ required-features = ["events"] [[test]] name = "nip10_reply_profile" -required-features = ["codec", "events"] +required-features = ["events"] [[test]] name = "nip09_deletion_request_profile" -required-features = ["codec", "events"] +required-features = ["events"] [[test]] name = "nip22_comment_profile" -required-features = ["codec", "events"] +required-features = ["events"] [[test]] name = "blossom_conformance" diff --git a/crates/nostr/README.md b/crates/nostr/README.md @@ -111,7 +111,7 @@ message state. `radroots_event`, `radroots_event_codec`, or versioned `radroots_protocol` contracts. - Explicit Nostr boundary aliases use the upstream NIP-01 JSON representation. -- `RadrootsNostrExternalSigningRequest` serializes only as the standard +- `event::ExternalSigningRequest` serializes only as the standard unsigned Nostr event after reserved-kind and authoring-policy validation. - Returned externally signed events are accepted only when author, canonical event ID, and the complete NIP-01 signature verify against the request. @@ -148,9 +148,7 @@ authority, upload completion, referenced-event existence, or relay trust. | `blossom` | no | Adds BUD-11 signed HTTP authorization value creation and verification; no HTTP client or endpoint operation. | Features are additive. `--no-default-features` provides the portable -`no_std + alloc` conversion core. The manifest's `codec` feature is a -non-release compatibility switch used by older focused adapters; it is not in -the supported public feature vocabulary. +`no_std + alloc` conversion core. ## Intended consumers diff --git a/crates/nostr/src/blossom.rs b/crates/nostr/src/blossom.rs @@ -33,14 +33,14 @@ const PERMISSIVE_URL_SAFE_NO_PAD: GeneralPurpose = GeneralPurpose::new( /// A kind-24242 event minted from a strict authored Blossom upload claim. #[derive(Clone, PartialEq, Eq)] -pub struct RadrootsNostrSignedBlossomAuthorization { +pub struct SignedAuthorization { event: RadrootsNostrEvent, } -impl fmt::Debug for RadrootsNostrSignedBlossomAuthorization { +impl fmt::Debug for SignedAuthorization { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter - .debug_struct("RadrootsNostrSignedBlossomAuthorization") + .debug_struct("SignedAuthorization") .field("event_id", &self.event.id) .field("author", &self.event.pubkey) .field("created_at", &self.event.created_at) @@ -48,7 +48,7 @@ impl fmt::Debug for RadrootsNostrSignedBlossomAuthorization { } } -impl RadrootsNostrSignedBlossomAuthorization { +impl SignedAuthorization { pub fn event_id(&self) -> RadrootsNostrEventId { self.event.id } @@ -64,9 +64,9 @@ impl RadrootsNostrSignedBlossomAuthorization { /// A canonical BUD-11 HTTP `Authorization` value. #[derive(Clone, PartialEq, Eq)] -pub struct RadrootsNostrBlossomAuthorizationHeader(String); +pub struct AuthorizationHeader(String); -impl RadrootsNostrBlossomAuthorizationHeader { +impl AuthorizationHeader { pub fn as_str(&self) -> &str { &self.0 } @@ -76,16 +76,16 @@ impl RadrootsNostrBlossomAuthorizationHeader { } } -impl fmt::Debug for RadrootsNostrBlossomAuthorizationHeader { +impl fmt::Debug for AuthorizationHeader { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter - .debug_tuple("RadrootsNostrBlossomAuthorizationHeader") + .debug_tuple("AuthorizationHeader") .field(&"[REDACTED]") .finish() } } -impl AsRef<str> for RadrootsNostrBlossomAuthorizationHeader { +impl AsRef<str> for AuthorizationHeader { fn as_ref(&self) -> &str { self.as_str() } @@ -93,15 +93,15 @@ impl AsRef<str> for RadrootsNostrBlossomAuthorizationHeader { /// A signature-verified BUD-11 event whose pure claim policy also passed. #[derive(Clone, PartialEq, Eq)] -pub struct RadrootsNostrVerifiedBlossomAuthorization { +pub struct VerifiedAuthorization { event: RadrootsNostrEvent, claim: ValidatedAuthorizationClaim, } -impl fmt::Debug for RadrootsNostrVerifiedBlossomAuthorization { +impl fmt::Debug for VerifiedAuthorization { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter - .debug_struct("RadrootsNostrVerifiedBlossomAuthorization") + .debug_struct("VerifiedAuthorization") .field("event_id", &self.event.id) .field("author", &self.event.pubkey) .field("created_at", &self.event.created_at) @@ -109,7 +109,7 @@ impl fmt::Debug for RadrootsNostrVerifiedBlossomAuthorization { } } -impl RadrootsNostrVerifiedBlossomAuthorization { +impl VerifiedAuthorization { pub fn event_id(&self) -> RadrootsNostrEventId { self.event.id } @@ -130,7 +130,7 @@ impl RadrootsNostrVerifiedBlossomAuthorization { /// Failures at the signed Blossom HTTP authorization boundary. #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] -pub enum RadrootsNostrBlossomError { +pub enum AuthorizationError { InvalidHeaderWhitespace, InvalidHeaderScheme, EmptyHeaderPayload, @@ -146,7 +146,7 @@ pub enum RadrootsNostrBlossomError { BlossomClaim(Error), } -impl RadrootsNostrBlossomError { +impl AuthorizationError { pub const fn code(&self) -> &'static str { match self { Self::InvalidHeaderWhitespace => "invalid_header_whitespace", @@ -173,7 +173,7 @@ impl RadrootsNostrBlossomError { } } -impl fmt::Display for RadrootsNostrBlossomError { +impl fmt::Display for AuthorizationError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::InvalidHeaderWhitespace => { @@ -214,19 +214,19 @@ impl fmt::Display for RadrootsNostrBlossomError { } } -impl std::error::Error for RadrootsNostrBlossomError {} +impl std::error::Error for AuthorizationError {} -impl From<Error> for RadrootsNostrBlossomError { +impl From<Error> for AuthorizationError { fn from(error: Error) -> Self { Self::BlossomClaim(error) } } /// Sign a direct kind-24242 event from a strict authored BUD-11 upload claim. -pub fn radroots_nostr_sign_blossom_authorization( +pub fn sign_authorization( keys: &RadrootsNostrKeys, claim: &AuthoredUploadClaim, -) -> Result<RadrootsNostrSignedBlossomAuthorization, RadrootsNostrBlossomError> { +) -> Result<SignedAuthorization, AuthorizationError> { let wire = claim.wire_parts(); let tags = wire .tags() @@ -254,37 +254,35 @@ pub fn radroots_nostr_sign_blossom_authorization( fn finish_signed_event<E>( result: Result<RadrootsNostrEvent, E>, -) -> Result<RadrootsNostrSignedBlossomAuthorization, RadrootsNostrBlossomError> { +) -> Result<SignedAuthorization, AuthorizationError> { result - .map(|event| RadrootsNostrSignedBlossomAuthorization { event }) - .map_err(|_| RadrootsNostrBlossomError::EventSigning) + .map(|event| SignedAuthorization { event }) + .map_err(|_| AuthorizationError::EventSigning) } /// Encode a signed BUD-11 event as a canonical `Nostr` authorization value. -pub fn radroots_nostr_encode_blossom_authorization_header( - authorization: &RadrootsNostrSignedBlossomAuthorization, -) -> RadrootsNostrBlossomAuthorizationHeader { +pub fn encode_authorization_header(authorization: &SignedAuthorization) -> AuthorizationHeader { // `nostr::Event` contains no fallible serializer fields or non-string map keys. let json = serde_json::to_vec(&authorization.event) .expect("Nostr event JSON serialization is infallible"); let payload = URL_SAFE_NO_PAD.encode(json); - RadrootsNostrBlossomAuthorizationHeader(format!("{AUTHORIZATION_SCHEME}{payload}")) + AuthorizationHeader(format!("{AUTHORIZATION_SCHEME}{payload}")) } /// Decode, authenticate, parse, and validate a BUD-11 authorization value. -pub fn radroots_nostr_decode_verify_blossom_authorization_header( +pub fn decode_verify_authorization_header( header: &str, validation: &AuthorizationValidation, -) -> Result<RadrootsNostrVerifiedBlossomAuthorization, RadrootsNostrBlossomError> { +) -> Result<VerifiedAuthorization, AuthorizationError> { if header.trim_start() != header { - return Err(RadrootsNostrBlossomError::InvalidHeaderWhitespace); + return Err(AuthorizationError::InvalidHeaderWhitespace); } let bytes = header.as_bytes(); let Some(first_space) = bytes.iter().position(|byte| *byte == b' ') else { - return Err(RadrootsNostrBlossomError::InvalidHeaderScheme); + return Err(AuthorizationError::InvalidHeaderScheme); }; if !bytes[..first_space].eq_ignore_ascii_case(b"Nostr") { - return Err(RadrootsNostrBlossomError::InvalidHeaderScheme); + return Err(AuthorizationError::InvalidHeaderScheme); } let payload_start = bytes[first_space..] .iter() @@ -292,30 +290,29 @@ pub fn radroots_nostr_decode_verify_blossom_authorization_header( .map_or(bytes.len(), |offset| first_space + offset); let payload = &header[payload_start..]; if payload.is_empty() { - return Err(RadrootsNostrBlossomError::EmptyHeaderPayload); + return Err(AuthorizationError::EmptyHeaderPayload); } if payload.chars().any(char::is_whitespace) { - return Err(RadrootsNostrBlossomError::InvalidHeaderWhitespace); + return Err(AuthorizationError::InvalidHeaderWhitespace); } if payload.contains('=') { - return Err(RadrootsNostrBlossomError::HeaderPaddingForbidden); + return Err(AuthorizationError::HeaderPaddingForbidden); } let decoded = PERMISSIVE_URL_SAFE_NO_PAD .decode(payload) - .map_err(|_| RadrootsNostrBlossomError::InvalidHeaderBase64)?; + .map_err(|_| AuthorizationError::InvalidHeaderBase64)?; if URL_SAFE_NO_PAD.encode(&decoded) != payload { - return Err(RadrootsNostrBlossomError::NonCanonicalHeaderBase64); + return Err(AuthorizationError::NonCanonicalHeaderBase64); } - let json = - String::from_utf8(decoded).map_err(|_| RadrootsNostrBlossomError::InvalidHeaderUtf8)?; + let json = String::from_utf8(decoded).map_err(|_| AuthorizationError::InvalidHeaderUtf8)?; validate_raw_event_json(&json)?; let event: RadrootsNostrEvent = - serde_json::from_str(&json).map_err(|_| RadrootsNostrBlossomError::InvalidEventJson)?; + serde_json::from_str(&json).map_err(|_| AuthorizationError::InvalidEventJson)?; if !event.verify_id() { - return Err(RadrootsNostrBlossomError::InvalidEventId); + return Err(AuthorizationError::InvalidEventId); } if !event.verify_signature() { - return Err(RadrootsNostrBlossomError::InvalidEventSignature); + return Err(AuthorizationError::InvalidEventSignature); } let tags: Vec<Vec<String>> = event @@ -326,10 +323,10 @@ pub fn radroots_nostr_decode_verify_blossom_authorization_header( let claim = AuthorizationClaim::parse(&event.content, event.created_at.as_secs(), &tags)? .validate(validation)?; - Ok(RadrootsNostrVerifiedBlossomAuthorization { event, claim }) + Ok(VerifiedAuthorization { event, claim }) } -fn validate_raw_event_json(json: &str) -> Result<(), RadrootsNostrBlossomError> { +fn validate_raw_event_json(json: &str) -> Result<(), AuthorizationError> { const EVENT_FIELDS: [&str; 7] = [ "id", "pubkey", @@ -341,22 +338,22 @@ fn validate_raw_event_json(json: &str) -> Result<(), RadrootsNostrBlossomError> ]; let value: serde_json::Value = - serde_json::from_str(json).map_err(|_| RadrootsNostrBlossomError::InvalidEventJson)?; + serde_json::from_str(json).map_err(|_| AuthorizationError::InvalidEventJson)?; let object = value .as_object() - .ok_or(RadrootsNostrBlossomError::InvalidEventJson)?; + .ok_or(AuthorizationError::InvalidEventJson)?; if object.len() != EVENT_FIELDS.len() || !EVENT_FIELDS.iter().all(|field| object.contains_key(*field)) { - return Err(RadrootsNostrBlossomError::InvalidEventJson); + return Err(AuthorizationError::InvalidEventJson); } let actual_kind = object .get("kind") .and_then(serde_json::Value::as_u64) - .ok_or(RadrootsNostrBlossomError::InvalidEventJson)?; + .ok_or(AuthorizationError::InvalidEventJson)?; if actual_kind != u64::from(RADROOTS_BLOSSOM_AUTHORIZATION_EVENT_KIND) { - return Err(RadrootsNostrBlossomError::InvalidEventKind { + return Err(AuthorizationError::InvalidEventKind { actual: actual_kind, }); } @@ -370,6 +367,6 @@ mod tests { #[test] fn blossom_signing_failure_maps_to_typed_adapter_error() { let result = finish_signed_event(Err::<RadrootsNostrEvent, ()>(())); - assert_eq!(result, Err(RadrootsNostrBlossomError::EventSigning)); + assert_eq!(result, Err(AuthorizationError::EventSigning)); } } diff --git a/crates/nostr/src/draft_signing.rs b/crates/nostr/src/draft_signing.rs @@ -5,27 +5,27 @@ #![forbid(unsafe_code)] -use crate::error::RadrootsNostrError; -use crate::events::radroots_nostr_build_event_unchecked; +use crate::error::Error; +use crate::events::build_event_unchecked; use crate::types::{RadrootsNostrKeys, RadrootsNostrTimestamp}; use nostr::JsonUtil; use radroots_event::draft::{EventDraft, SignedEvent}; use radroots_event::wire::Nip01EventWire; -pub fn radroots_nostr_sign_frozen_draft( +pub fn sign_frozen_draft( keys: &RadrootsNostrKeys, draft: &EventDraft, -) -> Result<SignedEvent, RadrootsNostrError> { +) -> Result<SignedEvent, Error> { draft.validate_for_signing()?; let actual_pubkey = keys.public_key().to_hex(); if actual_pubkey != draft.expected_pubkey().to_hex() { - return Err(RadrootsNostrError::FrozenDraftPubkeyMismatch { + return Err(Error::FrozenDraftPubkeyMismatch { expected_pubkey: draft.expected_pubkey().to_hex().to_owned(), actual_pubkey, }); } - let event = radroots_nostr_build_event_unchecked( + let event = build_event_unchecked( draft.kind_u32(), draft.content().to_owned(), draft.tags_as_vec(), @@ -35,7 +35,7 @@ pub fn radroots_nostr_sign_frozen_draft( let actual_event_id = event.id.to_hex(); let expected_event_id = draft.expected_event_id_hex(); if actual_event_id != expected_event_id { - return Err(RadrootsNostrError::FrozenDraftEventIdMismatch { + return Err(Error::FrozenDraftEventIdMismatch { expected_event_id, actual_event_id, }); @@ -48,16 +48,17 @@ pub fn radroots_nostr_sign_frozen_draft( #[cfg(test)] mod tests { - use super::radroots_nostr_sign_frozen_draft; - use crate::error::RadrootsNostrError; + use super::sign_frozen_draft; + use crate::error::Error; use crate::test_fixtures::{FIXTURE_ALICE, FIXTURE_BOB}; - use crate::types::{RadrootsNostrKeys, RadrootsNostrSecretKey}; + use crate::types::RadrootsNostrKeys; use nostr::JsonUtil; + use nostr::SecretKey; use radroots_event::draft::EventDraft; use radroots_event::envelope::kind::KIND_GEOCHAT; fn fixture_keys(secret_key_hex: &str) -> RadrootsNostrKeys { - let secret_key = RadrootsNostrSecretKey::from_hex(secret_key_hex).expect("secret key"); + let secret_key = SecretKey::from_hex(secret_key_hex).expect("secret key"); RadrootsNostrKeys::new(secret_key) } @@ -77,7 +78,7 @@ mod tests { fn sign_frozen_draft_uses_fixed_created_at_and_expected_id() { let keys = fixture_keys(FIXTURE_ALICE.secret_key_hex); let draft = generic_draft(FIXTURE_ALICE.public_key_hex); - let signed = radroots_nostr_sign_frozen_draft(&keys, &draft).expect("signed event"); + let signed = sign_frozen_draft(&keys, &draft).expect("signed event"); assert_eq!(signed.id_str(), draft.expected_event_id_hex()); assert_eq!(signed.pubkey().to_hex(), draft.expected_pubkey().to_hex()); @@ -96,12 +97,9 @@ mod tests { fn sign_frozen_draft_rejects_wrong_signer() { let keys = fixture_keys(FIXTURE_BOB.secret_key_hex); let draft = generic_draft(FIXTURE_ALICE.public_key_hex); - let error = radroots_nostr_sign_frozen_draft(&keys, &draft).expect_err("wrong signer"); + let error = sign_frozen_draft(&keys, &draft).expect_err("wrong signer"); - assert!(matches!( - error, - RadrootsNostrError::FrozenDraftPubkeyMismatch { .. } - )); + assert!(matches!(error, Error::FrozenDraftPubkeyMismatch { .. })); } #[test] diff --git a/crates/nostr/src/error.rs b/crates/nostr/src/error.rs @@ -7,7 +7,7 @@ use alloc::{boxed::Box, string::String}; use thiserror::Error; #[derive(Debug, Error)] -pub enum RadrootsNostrError { +pub enum Error { #[error("invalid Nostr public key")] InvalidPublicKey, @@ -114,26 +114,26 @@ pub enum RadrootsNostrError { FilterTagError(String), } -impl From<nostr::event::Error> for RadrootsNostrError { +impl From<nostr::event::Error> for Error { fn from(error: nostr::event::Error) -> Self { Self::EventError(error) } } -impl From<nostr::event::builder::Error> for RadrootsNostrError { +impl From<nostr::event::builder::Error> for Error { fn from(error: nostr::event::builder::Error) -> Self { Self::EventBuildError(error) } } -impl From<nostr::key::Error> for RadrootsNostrError { +impl From<nostr::key::Error> for Error { fn from(error: nostr::key::Error) -> Self { Self::KeyError(error) } } #[derive(Debug, Error)] -pub enum RadrootsNostrTagsResolveError { +pub enum ResolveError { #[error("Missing public key 'p' tag in encrypted event: {0:?}")] MissingPTag(Box<nostr::Event>), diff --git a/crates/nostr/src/event.rs b/crates/nostr/src/event.rs @@ -11,7 +11,47 @@ use radroots_event::id::Nip01Coordinate; use crate::Error; #[cfg(feature = "events")] -pub use crate::types::{RadrootsNostrExternalSigningRequest, RadrootsNostrGenericEventBuilder}; +pub use crate::codec_adapters::{ + to_job_feedback_index, to_job_feedback_metadata, to_job_request_index, to_job_request_metadata, + to_job_result_index, to_job_result_metadata, +}; +#[cfg(feature = "events")] +pub use crate::event_adapters::{to_post_event_metadata, to_profile_event_metadata}; +#[cfg(feature = "events")] +pub use crate::event_verify::{ + NostrSignatureVerifier as SignatureVerifier, Verification, verify_event as verify, + verify_event_id as verify_id, +}; +#[cfg(feature = "events")] +pub use crate::events::{ + application_handler::{ + ApplicationHandlerSpec, build_application_handler_event as build_application_handler, + metadata_has_fields, + }, + comment::{Nip22CommentBuilder, build_nip22_comment_event as build_nip22_comment}, + deletion::{ + Nip09DeletionRequestBuilder, + build_nip09_deletion_request_event as build_nip09_deletion_request, + }, + food_availability::{ + FoodAvailabilityBuilder, build_food_availability_event as build_food_availability, + }, + jobs::{ + build_event_job_feedback as build_job_feedback, build_event_job_result as build_job_result, + }, + metadata::{ProfileBuilder, build_profile_event as build_profile}, + post::{ + PostBuilder, build_ask_event as build_ask, build_photo_update_event as build_photo_update, + build_update_event as build_update, post_events_filter as post_filter, + }, + reply::{Nip10ReplyBuilder, build_nip10_reply_event as build_nip10_reply}, +}; +#[cfg(feature = "events")] +pub use crate::job_adapter::EventAdapter; +#[cfg(feature = "events")] +pub use crate::types::{ExternalSigningRequest, GenericBuilder}; +#[cfg(feature = "events")] +pub use crate::util::{created_at_u32_saturating, event_created_at_u32_saturating}; /// Upstream Nostr coordinate used only at the explicit protocol boundary. pub type Coordinate = nostr::nips::nip01::Coordinate; @@ -27,9 +67,7 @@ pub type Metadata = nostr::Metadata; pub type Timestamp = nostr::Timestamp; #[cfg(feature = "events")] -pub use crate::event_convert::{ - nostr_event_from_radroots, radroots_event_from_nostr, radroots_event_ptr_from_nostr, -}; +pub use crate::event_convert::{from_nostr, pointer_from_nostr, to_nostr}; /// Converts a canonical Radroots NIP-01 coordinate to its Nostr value. pub fn coordinate_to_nostr(coordinate: &Nip01Coordinate) -> Result<Coordinate, Error> { diff --git a/crates/nostr/src/event_adapters.rs b/crates/nostr/src/event_adapters.rs @@ -22,7 +22,7 @@ use crate::types::{RadrootsNostrEvent, RadrootsNostrMetadata}; /// Adapts an event through the compatibility-only legacy post projection. /// /// This helper discards tags and does not establish product profile admission. -/// Use `verify_and_admit_post_event` over `radroots_event_from_nostr` whenever +/// Use `verify_and_admit_post_event` over `from_nostr` whenever /// the caller needs root Update, PhotoUpdate, or Ask admission. Its explicit /// thread-excluded outcome makes no Reply claim. pub fn to_post_event_metadata(e: &RadrootsNostrEvent) -> RadrootsParsedData<LegacyPost> { diff --git a/crates/nostr/src/event_convert.rs b/crates/nostr/src/event_convert.rs @@ -1,15 +1,13 @@ #![forbid(unsafe_code)] -use crate::error::RadrootsNostrError; +use crate::error::Error; use crate::types::RadrootsNostrEvent as RadrootsNostrRawEvent; use radroots_event::{ envelope::EventEnvelope, envelope::EventEnvelopeError, envelope::EventEnvelopeParts, tag::EventPtr, }; -pub fn radroots_event_from_nostr( - event: &RadrootsNostrRawEvent, -) -> Result<EventEnvelope, EventEnvelopeError> { +pub fn from_nostr(event: &RadrootsNostrRawEvent) -> Result<EventEnvelope, EventEnvelopeError> { EventEnvelope::new(EventEnvelopeParts { id: event.id.to_string(), author: event.pubkey.to_string(), @@ -25,25 +23,23 @@ pub fn radroots_event_from_nostr( /// /// This adapter performs no network access and does not imply that the event's /// identifier or signature has been verified. -pub fn nostr_event_from_radroots( - event: &EventEnvelope, -) -> Result<RadrootsNostrRawEvent, RadrootsNostrError> { - let kind = u16::try_from(event.kind_u32()).map_err(|_| RadrootsNostrError::KindOutOfRange { +pub fn to_nostr(event: &EventEnvelope) -> Result<RadrootsNostrRawEvent, Error> { + let kind = u16::try_from(event.kind_u32()).map_err(|_| Error::KindOutOfRange { kind: event.kind_u32(), max: u16::MAX, })?; let id = nostr::EventId::from_slice(event.id().as_bytes()) - .map_err(|_| RadrootsNostrError::EventConversion { field: "id" })?; + .map_err(|_| Error::EventConversion { field: "id" })?; let public_key = nostr::PublicKey::from_slice(event.author().as_bytes()) - .map_err(|_| RadrootsNostrError::EventConversion { field: "author" })?; + .map_err(|_| Error::EventConversion { field: "author" })?; let signature = nostr::secp256k1::schnorr::Signature::from_slice(event.sig().as_bytes()) - .map_err(|_| RadrootsNostrError::EventConversion { field: "signature" })?; + .map_err(|_| Error::EventConversion { field: "signature" })?; let tags = event .tags_as_vec() .into_iter() .map(nostr::Tag::parse) .collect::<Result<Vec<_>, _>>() - .map_err(|_| RadrootsNostrError::EventConversion { field: "tags" })?; + .map_err(|_| Error::EventConversion { field: "tags" })?; Ok(nostr::Event::new( id, @@ -56,7 +52,7 @@ pub fn nostr_event_from_radroots( )) } -pub fn radroots_event_ptr_from_nostr(event: &RadrootsNostrRawEvent) -> EventPtr { +pub fn pointer_from_nostr(event: &RadrootsNostrRawEvent) -> EventPtr { EventPtr { id: event.id.to_string(), relays: None, @@ -66,22 +62,22 @@ pub fn radroots_event_ptr_from_nostr(event: &RadrootsNostrRawEvent) -> EventPtr #[cfg(test)] mod tests { use super::*; - use crate::events::radroots_nostr_build_event_unchecked; + use crate::events::build_event_unchecked; use crate::test_fixtures::FIXTURE_ALICE; - use crate::types::{RadrootsNostrKeys, RadrootsNostrSecretKey, RadrootsNostrTimestamp}; + use crate::types::{RadrootsNostrKeys, RadrootsNostrTimestamp}; + use nostr::SecretKey; use radroots_event::{ envelope::EventEnvelopeParts, wire::{DEFAULT_CONTENT_MAX_BYTES, DEFAULT_TAG_TOTAL_ELEMENT_MAX_COUNT}, }; fn fixture_keys() -> RadrootsNostrKeys { - let secret_key = - RadrootsNostrSecretKey::from_hex(FIXTURE_ALICE.secret_key_hex).expect("secret key"); + let secret_key = SecretKey::from_hex(FIXTURE_ALICE.secret_key_hex).expect("secret key"); RadrootsNostrKeys::new(secret_key) } fn signed_event(content: String, tags: Vec<Vec<String>>) -> RadrootsNostrRawEvent { - radroots_nostr_build_event_unchecked(1, content, tags) + build_event_unchecked(1, content, tags) .expect("builder") .custom_created_at(RadrootsNostrTimestamp::from_secs(1_700_000_000)) .sign_with_keys(&fixture_keys()) @@ -94,9 +90,9 @@ mod tests { "harvest update".to_owned(), vec![vec!["t".to_owned(), "soil".to_owned()]], ); - let envelope = radroots_event_from_nostr(&original).expect("Radroots envelope"); + let envelope = from_nostr(&original).expect("Radroots envelope"); - let converted = nostr_event_from_radroots(&envelope).expect("Nostr event"); + let converted = to_nostr(&envelope).expect("Nostr event"); assert_eq!(converted, original); } @@ -104,7 +100,7 @@ mod tests { #[test] fn conversion_rejects_kind_outside_nostr_range() { let original = signed_event(String::new(), Vec::new()); - let envelope = radroots_event_from_nostr(&original).expect("Radroots envelope"); + let envelope = from_nostr(&original).expect("Radroots envelope"); let kind = u32::from(u16::MAX) + 1; let widened = EventEnvelope::new(EventEnvelopeParts { id: envelope.id_hex(), @@ -118,8 +114,8 @@ mod tests { .expect("wider Radroots kind"); assert!(matches!( - nostr_event_from_radroots(&widened), - Err(RadrootsNostrError::KindOutOfRange { + to_nostr(&widened), + Err(Error::KindOutOfRange { kind: actual, max: u16::MAX, }) if actual == kind @@ -132,7 +128,7 @@ mod tests { let event = signed_event(content, Vec::new()); assert_eq!( - radroots_event_from_nostr(&event), + from_nostr(&event), Err(EventEnvelopeError::ContentTooLarge { max: DEFAULT_CONTENT_MAX_BYTES, actual: DEFAULT_CONTENT_MAX_BYTES + 1, @@ -148,7 +144,7 @@ mod tests { let event = signed_event(String::new(), vec![tag]); assert_eq!( - radroots_event_from_nostr(&event), + from_nostr(&event), Err(EventEnvelopeError::TooManyTagElements { max: DEFAULT_TAG_TOTAL_ELEMENT_MAX_COUNT, actual: DEFAULT_TAG_TOTAL_ELEMENT_MAX_COUNT + 1, diff --git a/crates/nostr/src/event_verify.rs b/crates/nostr/src/event_verify.rs @@ -30,7 +30,7 @@ impl SignatureVerifier for NostrSignatureVerifier { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum RadrootsNostrEventVerification { +pub enum Verification { Verified, IdVerified, IdMismatch, @@ -38,20 +38,20 @@ pub enum RadrootsNostrEventVerification { MalformedEnvelope, } -pub fn radroots_nostr_verify_event(event: &EventEnvelope) -> RadrootsNostrEventVerification { +pub fn verify_event(event: &EventEnvelope) -> Verification { let result = validate_nostr_kind(event) .and_then(|()| verify::id(RawEvent::new(event.clone()))) .and_then(|event| verify::signature(event, &NostrSignatureVerifier)); match result { - Ok(_) => RadrootsNostrEventVerification::Verified, + Ok(_) => Verification::Verified, Err(error) => verification_error_status(&error), } } -pub fn radroots_nostr_verify_event_id(event: &EventEnvelope) -> RadrootsNostrEventVerification { +pub fn verify_event_id(event: &EventEnvelope) -> Verification { let result = validate_nostr_kind(event).and_then(|()| verify::id(RawEvent::new(event.clone()))); match result { - Ok(_) => RadrootsNostrEventVerification::IdVerified, + Ok(_) => Verification::IdVerified, Err(error) => verification_error_status(&error), } } @@ -62,37 +62,37 @@ fn validate_nostr_kind(event: &EventEnvelope) -> Result<(), VerificationError> { .map_err(|_| VerificationError::MalformedEnvelope) } -fn verification_error_status(error: &VerificationError) -> RadrootsNostrEventVerification { +fn verification_error_status(error: &VerificationError) -> Verification { match error { - VerificationError::IdMismatch { .. } => RadrootsNostrEventVerification::IdMismatch, - VerificationError::SignatureInvalid => RadrootsNostrEventVerification::SignatureInvalid, + VerificationError::IdMismatch { .. } => Verification::IdMismatch, + VerificationError::SignatureInvalid => Verification::SignatureInvalid, VerificationError::MalformedEnvelope | VerificationError::ContractValidation(_) => { - RadrootsNostrEventVerification::MalformedEnvelope + Verification::MalformedEnvelope } - _ => RadrootsNostrEventVerification::MalformedEnvelope, + _ => Verification::MalformedEnvelope, } } #[cfg(test)] mod tests { use super::*; - use crate::event_convert::radroots_event_from_nostr; - use crate::events::radroots_nostr_build_event_unchecked; + use crate::event_convert::from_nostr; + use crate::events::build_event_unchecked; use crate::test_fixtures::FIXTURE_ALICE; - use crate::types::{RadrootsNostrKeys, RadrootsNostrSecretKey, RadrootsNostrTimestamp}; + use crate::types::{RadrootsNostrKeys, RadrootsNostrTimestamp}; + use nostr::SecretKey; use radroots_event::{ envelope::EventEnvelopeParts, envelope::kind::KIND_POST, wire::compute_canonical_nip01_event_id, }; fn fixture_keys() -> RadrootsNostrKeys { - let secret_key = - RadrootsNostrSecretKey::from_hex(FIXTURE_ALICE.secret_key_hex).expect("secret key"); + let secret_key = SecretKey::from_hex(FIXTURE_ALICE.secret_key_hex).expect("secret key"); RadrootsNostrKeys::new(secret_key) } fn signed_event() -> EventEnvelope { - let raw_event = radroots_nostr_build_event_unchecked( + let raw_event = build_event_unchecked( KIND_POST, "hello", vec![vec!["t".to_owned(), "soil".to_owned()]], @@ -101,7 +101,7 @@ mod tests { .custom_created_at(RadrootsNostrTimestamp::from_secs(1_700_000_000)) .sign_with_keys(&fixture_keys()) .expect("signed event"); - radroots_event_from_nostr(&raw_event).expect("Radroots event envelope") + from_nostr(&raw_event).expect("Radroots event envelope") } fn envelope_with( @@ -126,14 +126,8 @@ mod tests { fn verifies_signed_event_id_and_signature() { let event = signed_event(); - assert_eq!( - radroots_nostr_verify_event(&event), - RadrootsNostrEventVerification::Verified - ); - assert_eq!( - radroots_nostr_verify_event_id(&event), - RadrootsNostrEventVerification::IdVerified - ); + assert_eq!(verify_event(&event), Verification::Verified); + assert_eq!(verify_event_id(&event), Verification::IdVerified); } #[test] @@ -146,10 +140,7 @@ mod tests { original.signature_hex(), ); - assert_eq!( - radroots_nostr_verify_event(&event), - RadrootsNostrEventVerification::IdMismatch - ); + assert_eq!(verify_event(&event), Verification::IdMismatch); } #[test] @@ -165,10 +156,7 @@ mod tests { sig, ); - assert_eq!( - radroots_nostr_verify_event(&event), - RadrootsNostrEventVerification::SignatureInvalid - ); + assert_eq!(verify_event(&event), Verification::SignatureInvalid); } #[test] @@ -181,14 +169,8 @@ mod tests { original.signature_hex(), ); - assert_eq!( - radroots_nostr_verify_event(&event), - RadrootsNostrEventVerification::MalformedEnvelope - ); - assert_eq!( - radroots_nostr_verify_event_id(&event), - RadrootsNostrEventVerification::MalformedEnvelope - ); + assert_eq!(verify_event(&event), Verification::MalformedEnvelope); + assert_eq!(verify_event_id(&event), Verification::MalformedEnvelope); } #[test] @@ -215,13 +197,7 @@ mod tests { }) .expect("envelope"); - assert_eq!( - radroots_nostr_verify_event(&event), - RadrootsNostrEventVerification::MalformedEnvelope - ); - assert_eq!( - radroots_nostr_verify_event_id(&event), - RadrootsNostrEventVerification::MalformedEnvelope - ); + assert_eq!(verify_event(&event), Verification::MalformedEnvelope); + assert_eq!(verify_event_id(&event), Verification::MalformedEnvelope); } } diff --git a/crates/nostr/src/events/application_handler.rs b/crates/nostr/src/events/application_handler.rs @@ -6,22 +6,22 @@ extern crate alloc; use alloc::{string::String, vec::Vec}; -use crate::error::RadrootsNostrError; -use crate::events::radroots_nostr_build_event_unchecked; -use crate::types::{RadrootsNostrGenericEventBuilder, RadrootsNostrMetadata}; +use crate::error::Error; +use crate::events::build_event_unchecked; +use crate::types::{GenericBuilder, RadrootsNostrMetadata}; use radroots_event::envelope::kind::KIND_APPLICATION_HANDLER; #[derive(Debug, Clone)] -pub struct RadrootsNostrApplicationHandlerSpec { - pub kinds: Vec<u32>, - pub identifier: Option<String>, - pub metadata: Option<RadrootsNostrMetadata>, - pub extra_tags: Vec<Vec<String>>, - pub relays: Vec<String>, - pub nostrconnect_url: Option<String>, +pub struct ApplicationHandlerSpec { + kinds: Vec<u32>, + identifier: Option<String>, + metadata: Option<RadrootsNostrMetadata>, + extra_tags: Vec<Vec<String>>, + relays: Vec<String>, + nostrconnect_url: Option<String>, } -impl RadrootsNostrApplicationHandlerSpec { +impl ApplicationHandlerSpec { pub fn new(kinds: Vec<u32>) -> Self { Self { kinds, @@ -32,13 +32,67 @@ impl RadrootsNostrApplicationHandlerSpec { nostrconnect_url: None, } } + + #[must_use] + pub fn with_identifier(mut self, identifier: impl Into<String>) -> Self { + self.identifier = Some(identifier.into()); + self + } + + #[must_use] + pub fn with_metadata(mut self, metadata: RadrootsNostrMetadata) -> Self { + self.metadata = Some(metadata); + self + } + + #[must_use] + pub fn with_extra_tags(mut self, extra_tags: Vec<Vec<String>>) -> Self { + self.extra_tags = extra_tags; + self + } + + #[must_use] + pub fn with_relays(mut self, relays: Vec<String>) -> Self { + self.relays = relays; + self + } + + #[must_use] + pub fn with_nostr_connect_url(mut self, url: impl Into<String>) -> Self { + self.nostrconnect_url = Some(url.into()); + self + } + + pub fn kinds(&self) -> &[u32] { + &self.kinds + } + + pub fn identifier(&self) -> Option<&str> { + self.identifier.as_deref() + } + + pub fn metadata(&self) -> Option<&RadrootsNostrMetadata> { + self.metadata.as_ref() + } + + pub fn extra_tags(&self) -> &[Vec<String>] { + &self.extra_tags + } + + pub fn relays(&self) -> &[String] { + &self.relays + } + + pub fn nostr_connect_url(&self) -> Option<&str> { + self.nostrconnect_url.as_deref() + } } -pub fn radroots_nostr_build_application_handler_event( - spec: &RadrootsNostrApplicationHandlerSpec, -) -> Result<RadrootsNostrGenericEventBuilder, RadrootsNostrError> { +pub fn build_application_handler_event( + spec: &ApplicationHandlerSpec, +) -> Result<GenericBuilder, Error> { if spec.kinds.is_empty() { - return Err(RadrootsNostrError::FilterTagError( + return Err(Error::FilterTagError( "application handler kinds are empty".to_string(), )); } @@ -50,7 +104,7 @@ pub fn radroots_nostr_build_application_handler_event( let mut content = String::new(); if let Some(md) = spec.metadata.as_ref() - && radroots_nostr_metadata_has_fields(md) + && metadata_has_fields(md) { content = serde_json::to_string(md).unwrap_or_default(); } @@ -80,11 +134,11 @@ pub fn radroots_nostr_build_application_handler_event( tags.push(tag.clone()); } - let builder = radroots_nostr_build_event_unchecked(KIND_APPLICATION_HANDLER, content, tags)?; - Ok(RadrootsNostrGenericEventBuilder::from_unchecked(builder)) + let builder = build_event_unchecked(KIND_APPLICATION_HANDLER, content, tags)?; + Ok(GenericBuilder::from_unchecked(builder)) } -pub fn radroots_nostr_metadata_has_fields(md: &RadrootsNostrMetadata) -> bool { +pub fn metadata_has_fields(md: &RadrootsNostrMetadata) -> bool { md.name.is_some() || md.display_name.is_some() || md.about.is_some() @@ -99,14 +153,12 @@ pub fn radroots_nostr_metadata_has_fields(md: &RadrootsNostrMetadata) -> bool { #[cfg(test)] mod tests { - use super::radroots_nostr_metadata_has_fields; + use super::metadata_has_fields; use crate::types::RadrootsNostrMetadata; #[test] fn metadata_has_fields_false_when_empty() { - assert!(!radroots_nostr_metadata_has_fields( - &RadrootsNostrMetadata::default() - )); + assert!(!metadata_has_fields(&RadrootsNostrMetadata::default())); } #[test] @@ -115,6 +167,6 @@ mod tests { about: Some("ready".to_string()), ..Default::default() }; - assert!(radroots_nostr_metadata_has_fields(&metadata)); + assert!(metadata_has_fields(&metadata)); } } diff --git a/crates/nostr/src/events/comment.rs b/crates/nostr/src/events/comment.rs @@ -1,7 +1,7 @@ //! Sealed authoring for strict NIP-22 Comment events. use crate::{ - error::RadrootsNostrError, + error::Error, types::{ RadrootsNostrEvent, RadrootsNostrEventBuilderUnchecked, RadrootsNostrKeys, RadrootsNostrTimestamp, @@ -15,43 +15,37 @@ use radroots_event_codec::encode::comment::authored_nip22_comment_to_wire_parts; /// The wrapper exposes no raw builder conversion or tag/content mutation. /// /// ```compile_fail -/// use radroots_nostr::events::comment::RadrootsNostrNip22CommentEventBuilder; +/// use radroots_nostr::event::Nip22CommentBuilder; /// -/// fn expose_raw_builder(builder: RadrootsNostrNip22CommentEventBuilder) { +/// fn expose_raw_builder(builder: Nip22CommentBuilder) { /// let _: nostr::EventBuilder = builder.into(); /// } /// ``` #[must_use = "NIP-22 Comment builders must be signed or published"] -pub struct RadrootsNostrNip22CommentEventBuilder { +pub struct Nip22CommentBuilder { inner: RadrootsNostrEventBuilderUnchecked, } -impl RadrootsNostrNip22CommentEventBuilder { +impl Nip22CommentBuilder { pub fn custom_created_at(mut self, created_at: RadrootsNostrTimestamp) -> Self { self.inner = self.inner.custom_created_at(created_at); self } - pub fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { Ok(self.inner.sign_with_keys(keys)?) } } -pub fn radroots_nostr_build_nip22_comment_event( +pub fn build_nip22_comment_event( comment: &AuthoredNip22Comment, -) -> Result<RadrootsNostrNip22CommentEventBuilder, RadrootsNostrError> { +) -> Result<Nip22CommentBuilder, Error> { builder_from_wire_parts(authored_nip22_comment_to_wire_parts(comment)) } -fn builder_from_wire_parts( - parts: Nip01EventWireParts, -) -> Result<RadrootsNostrNip22CommentEventBuilder, RadrootsNostrError> { - let inner = - crate::events::radroots_nostr_build_event_unchecked(parts.kind, parts.content, parts.tags)?; - Ok(RadrootsNostrNip22CommentEventBuilder { inner }) +fn builder_from_wire_parts(parts: Nip01EventWireParts) -> Result<Nip22CommentBuilder, Error> { + let inner = crate::events::build_event_unchecked(parts.kind, parts.content, parts.tags)?; + Ok(Nip22CommentBuilder { inner }) } #[cfg(test)] @@ -74,7 +68,7 @@ mod tests { .expect("root"); let comment = AuthoredNip22Comment::top_level_event("Comment", root).expect("comment"); let keys = RadrootsNostrKeys::generate(); - let event = radroots_nostr_build_nip22_comment_event(&comment) + let event = build_nip22_comment_event(&comment) .expect("builder") .custom_created_at(RadrootsNostrTimestamp::from_secs(1_800_000_000)) .sign_with_keys(&keys) diff --git a/crates/nostr/src/events/deletion.rs b/crates/nostr/src/events/deletion.rs @@ -1,7 +1,7 @@ //! Sealed authoring for validated NIP-09 deletion requests. use crate::{ - error::RadrootsNostrError, + error::Error, types::{ RadrootsNostrEvent, RadrootsNostrEventBuilderUnchecked, RadrootsNostrKeys, RadrootsNostrTimestamp, @@ -17,53 +17,48 @@ use radroots_event_codec::encode::deletion::authored_nip09_deletion_request_to_w /// effect. /// /// ```compile_fail -/// use radroots_nostr::events::deletion::RadrootsNostrNip09DeletionRequestEventBuilder; +/// use radroots_nostr::event::Nip09DeletionRequestBuilder; /// -/// fn expose_raw_builder(builder: RadrootsNostrNip09DeletionRequestEventBuilder) { +/// fn expose_raw_builder(builder: Nip09DeletionRequestBuilder) { /// let _: nostr::EventBuilder = builder.into(); /// } /// ``` /// /// ```compile_fail -/// use radroots_nostr::events::deletion::RadrootsNostrNip09DeletionRequestEventBuilder; -/// use radroots_nostr::tag::Tag as RadrootsNostrTag; +/// use radroots_nostr::{event::Nip09DeletionRequestBuilder, tag::Tag}; /// /// fn mutate_validated_tags( -/// builder: RadrootsNostrNip09DeletionRequestEventBuilder, -/// tag: RadrootsNostrTag, +/// builder: Nip09DeletionRequestBuilder, +/// tag: Tag, /// ) { /// let _ = builder.tag(tag); /// } /// ``` #[must_use = "NIP-09 deletion request builders must be signed or published"] -pub struct RadrootsNostrNip09DeletionRequestEventBuilder { +pub struct Nip09DeletionRequestBuilder { inner: RadrootsNostrEventBuilderUnchecked, } -impl RadrootsNostrNip09DeletionRequestEventBuilder { +impl Nip09DeletionRequestBuilder { pub fn custom_created_at(mut self, created_at: RadrootsNostrTimestamp) -> Self { self.inner = self.inner.custom_created_at(created_at); self } - pub fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { Ok(self.inner.sign_with_keys(keys)?) } } -pub fn radroots_nostr_build_nip09_deletion_request_event( +pub fn build_nip09_deletion_request_event( request: &AuthoredNip09DeletionRequest, -) -> Result<RadrootsNostrNip09DeletionRequestEventBuilder, RadrootsNostrError> { +) -> Result<Nip09DeletionRequestBuilder, Error> { builder_from_wire_parts(authored_nip09_deletion_request_to_wire_parts(request)) } fn builder_from_wire_parts( parts: Nip01EventWireParts, -) -> Result<RadrootsNostrNip09DeletionRequestEventBuilder, RadrootsNostrError> { - let inner = - crate::events::radroots_nostr_build_event_unchecked(parts.kind, parts.content, parts.tags)?; - Ok(RadrootsNostrNip09DeletionRequestEventBuilder { inner }) +) -> Result<Nip09DeletionRequestBuilder, Error> { + let inner = crate::events::build_event_unchecked(parts.kind, parts.content, parts.tags)?; + Ok(Nip09DeletionRequestBuilder { inner }) } diff --git a/crates/nostr/src/events/food_availability.rs b/crates/nostr/src/events/food_availability.rs @@ -1,7 +1,7 @@ //! Sealed authoring for focused Radroots FoodAvailability events. use crate::{ - error::RadrootsNostrError, + error::Error, types::{ RadrootsNostrEvent, RadrootsNostrEventBuilderUnchecked, RadrootsNostrKeys, RadrootsNostrTimestamp, @@ -18,34 +18,30 @@ use radroots_event_codec::encode::food_availability::authored_food_availability_ /// caller must prove successful BUD-02 upload before signing or publication. /// /// ```compile_fail -/// use radroots_nostr::events::food_availability::RadrootsNostrFoodAvailabilityEventBuilder; -/// use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; +/// use radroots_nostr::event::{FoodAvailabilityBuilder, Timestamp}; /// -/// fn replace_validated_timestamp(builder: RadrootsNostrFoodAvailabilityEventBuilder) { -/// let _ = builder.custom_created_at(RadrootsNostrTimestamp::from_secs(1)); +/// fn replace_validated_timestamp(builder: FoodAvailabilityBuilder) { +/// let _ = builder.custom_created_at(Timestamp::from_secs(1)); /// } /// ``` /// /// ```compile_fail -/// use radroots_nostr::events::food_availability::RadrootsNostrFoodAvailabilityEventBuilder; +/// use radroots_nostr::event::FoodAvailabilityBuilder; /// -/// fn expose_raw_builder(builder: RadrootsNostrFoodAvailabilityEventBuilder) { +/// fn expose_raw_builder(builder: FoodAvailabilityBuilder) { /// let _: nostr::EventBuilder = builder.into(); /// } /// ``` #[must_use = "FoodAvailability event builders must be signed or published"] -pub struct RadrootsNostrFoodAvailabilityEventBuilder { +pub struct FoodAvailabilityBuilder { inner: RadrootsNostrEventBuilderUnchecked, } -impl RadrootsNostrFoodAvailabilityEventBuilder { +impl FoodAvailabilityBuilder { /// Signs the validated event directly with local keys. /// /// Media-bearing callers must prove successful BUD-02 upload first. - pub fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { Ok(self.inner.sign_with_keys(keys)?) } } @@ -53,12 +49,12 @@ impl RadrootsNostrFoodAvailabilityEventBuilder { /// Builds a sealed Nostr builder from strict FoodAvailability details. /// /// This validates media descriptors but does not attest BUD-02 upload. -pub fn radroots_nostr_build_food_availability_event( +pub fn build_food_availability_event( details: &FoodAvailabilityDetails, created_at: RadrootsNostrTimestamp, -) -> Result<RadrootsNostrFoodAvailabilityEventBuilder, RadrootsNostrError> { +) -> Result<FoodAvailabilityBuilder, Error> { let parts = authored_food_availability_to_wire_parts(details, created_at.as_secs())?; - let inner = super::radroots_nostr_build_event_unchecked(parts.kind, parts.content, parts.tags)? + let inner = super::build_event_unchecked(parts.kind, parts.content, parts.tags)? .custom_created_at(created_at); - Ok(RadrootsNostrFoodAvailabilityEventBuilder { inner }) + Ok(FoodAvailabilityBuilder { inner }) } diff --git a/crates/nostr/src/events/jobs.rs b/crates/nostr/src/events/jobs.rs @@ -4,19 +4,18 @@ use alloc::{string::String, vec::Vec}; use nostr::nips::nip90::{DataVendingMachineStatus, JobFeedbackData}; -use crate::error::RadrootsNostrError; +use crate::error::Error; use crate::types::{ - RadrootsNostrEvent, RadrootsNostrEventBuilderUnchecked, RadrootsNostrGenericEventBuilder, - RadrootsNostrTag, + GenericBuilder, RadrootsNostrEvent, RadrootsNostrEventBuilderUnchecked, RadrootsNostrTag, }; -pub fn radroots_nostr_build_event_job_result( +pub fn build_event_job_result( job_request: &RadrootsNostrEvent, payload: impl Into<String>, millisats: u64, bolt11: Option<String>, tags: Option<Vec<RadrootsNostrTag>>, -) -> Result<RadrootsNostrGenericEventBuilder, RadrootsNostrError> { +) -> Result<GenericBuilder, Error> { let builder = RadrootsNostrEventBuilderUnchecked::job_result( job_request.clone(), payload, @@ -25,15 +24,15 @@ pub fn radroots_nostr_build_event_job_result( )? .tags(tags.unwrap_or_default()) .allow_self_tagging(); - Ok(RadrootsNostrGenericEventBuilder::from_unchecked(builder)) + Ok(GenericBuilder::from_unchecked(builder)) } -pub fn radroots_nostr_build_event_job_feedback( +pub fn build_event_job_feedback( job_request: &RadrootsNostrEvent, status: &str, extra_info: Option<String>, tags: Option<Vec<RadrootsNostrTag>>, -) -> Result<RadrootsNostrGenericEventBuilder, RadrootsNostrError> { +) -> Result<GenericBuilder, Error> { let status = status .parse::<DataVendingMachineStatus>() .unwrap_or(DataVendingMachineStatus::Error); @@ -42,5 +41,5 @@ pub fn radroots_nostr_build_event_job_feedback( let builder = RadrootsNostrEventBuilderUnchecked::job_feedback(feedback_data) .tags(tags.unwrap_or_default()) .allow_self_tagging(); - Ok(RadrootsNostrGenericEventBuilder::from_unchecked(builder)) + Ok(GenericBuilder::from_unchecked(builder)) } diff --git a/crates/nostr/src/events/metadata.rs b/crates/nostr/src/events/metadata.rs @@ -1,7 +1,7 @@ //! Sealed authoring for validated NIP-01 profile metadata events. #[cfg(feature = "events")] -use crate::error::RadrootsNostrError; +use crate::error::Error; #[cfg(feature = "events")] use crate::types::RadrootsNostrEvent; #[cfg(feature = "events")] @@ -18,12 +18,12 @@ use radroots_event_codec::encode::profile::authored_profile_to_wire_parts; /// BUD-02 upload completion before signing or publication. #[cfg(feature = "events")] #[must_use = "Profile event builders must be signed or published"] -pub struct RadrootsNostrProfileEventBuilder { +pub struct ProfileBuilder { inner: RadrootsNostrEventBuilderUnchecked, } #[cfg(feature = "events")] -impl RadrootsNostrProfileEventBuilder { +impl ProfileBuilder { /// Sets the event timestamp without changing the validated Profile shape. pub fn custom_created_at(mut self, created_at: RadrootsNostrTimestamp) -> Self { self.inner = self.inner.custom_created_at(created_at); @@ -31,21 +31,15 @@ impl RadrootsNostrProfileEventBuilder { } /// Signs the validated Profile directly with local keys. - pub fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { Ok(self.inner.sign_with_keys(keys)?) } } /// Builds a sealed kind-0 event from the strict authored Profile contract. #[cfg(feature = "events")] -pub fn radroots_nostr_build_profile_event( - profile: &AuthoredProfile, -) -> Result<RadrootsNostrProfileEventBuilder, RadrootsNostrError> { +pub fn build_profile_event(profile: &AuthoredProfile) -> Result<ProfileBuilder, Error> { let parts = authored_profile_to_wire_parts(profile)?; - let inner = - crate::events::radroots_nostr_build_event_unchecked(parts.kind, parts.content, parts.tags)?; - Ok(RadrootsNostrProfileEventBuilder { inner }) + let inner = crate::events::build_event_unchecked(parts.kind, parts.content, parts.tags)?; + Ok(ProfileBuilder { inner }) } diff --git a/crates/nostr/src/events/mod.rs b/crates/nostr/src/events/mod.rs @@ -23,19 +23,19 @@ extern crate alloc; use alloc::{string::String, vec::Vec}; #[cfg(any(feature = "events", test))] -use crate::error::RadrootsNostrError; +use crate::error::Error; #[cfg(any(feature = "events", test))] use crate::types::{ RadrootsNostrEventBuilderUnchecked, RadrootsNostrKind, RadrootsNostrTag, RadrootsNostrTagKind, }; #[cfg(any(feature = "events", test))] -pub(crate) fn radroots_nostr_build_event_unchecked( +pub(crate) fn build_event_unchecked( kind_u32: u32, content: impl Into<String>, tag_slices: Vec<Vec<String>>, -) -> Result<RadrootsNostrEventBuilderUnchecked, RadrootsNostrError> { - let kind = u16::try_from(kind_u32).map_err(|_| RadrootsNostrError::KindOutOfRange { +) -> Result<RadrootsNostrEventBuilderUnchecked, Error> { + let kind = u16::try_from(kind_u32).map_err(|_| Error::KindOutOfRange { kind: kind_u32, max: u16::MAX, })?; @@ -62,8 +62,8 @@ pub(crate) fn radroots_nostr_build_event_unchecked( mod tests { use alloc::{vec, vec::Vec}; - use super::radroots_nostr_build_event_unchecked; - use crate::error::RadrootsNostrError; + use super::build_event_unchecked; + use crate::error::Error; use crate::test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX; use crate::types::{RadrootsNostrPublicKey, RadrootsNostrTagKind}; @@ -76,7 +76,7 @@ mod tests { vec!["p".to_string(), pubkey_hex.to_string()], ]; - let builder = radroots_nostr_build_event_unchecked(1, "test", tags).expect("builder"); + let builder = build_event_unchecked(1, "test", tags).expect("builder"); let event = builder.build(pubkey); let has_self_tag = event.tags.iter().any(|tag| { @@ -93,7 +93,7 @@ mod tests { #[test] fn build_event_accepts_maximum_nip01_kind() { - let builder = radroots_nostr_build_event_unchecked(u32::from(u16::MAX), "test", Vec::new()) + let builder = build_event_unchecked(u32::from(u16::MAX), "test", Vec::new()) .expect("maximum NIP-01 kind"); let event = builder .build(RadrootsNostrPublicKey::from_hex(FIXTURE_ALICE_PUBLIC_KEY_HEX).expect("pubkey")); @@ -104,8 +104,8 @@ mod tests { fn build_event_rejects_kind_overflow() { let kind = u32::from(u16::MAX) + 1; assert!(matches!( - radroots_nostr_build_event_unchecked(kind, "test", Vec::new()), - Err(RadrootsNostrError::KindOutOfRange { + build_event_unchecked(kind, "test", Vec::new()), + Err(Error::KindOutOfRange { kind: actual, max: u16::MAX }) if actual == kind diff --git a/crates/nostr/src/events/post.rs b/crates/nostr/src/events/post.rs @@ -1,7 +1,7 @@ //! Typed authoring and filtering for supported Radroots social root events. #[cfg(feature = "events")] -use crate::error::RadrootsNostrError; +use crate::error::Error; #[cfg(feature = "events")] use crate::types::RadrootsNostrEventBuilderUnchecked; #[cfg(feature = "events")] @@ -23,12 +23,12 @@ use radroots_event_codec::encode::post::{ /// mutation. Construct it through one of the typed post authoring functions. #[cfg(feature = "events")] #[must_use = "post event builders must be signed or published"] -pub struct RadrootsNostrPostEventBuilder { +pub struct PostBuilder { inner: RadrootsNostrEventBuilderUnchecked, } #[cfg(feature = "events")] -impl RadrootsNostrPostEventBuilder { +impl PostBuilder { /// Sets the event timestamp without changing the validated post shape. pub fn custom_created_at(mut self, created_at: RadrootsNostrTimestamp) -> Self { self.inner = self.inner.custom_created_at(created_at); @@ -36,39 +36,27 @@ impl RadrootsNostrPostEventBuilder { } /// Signs the validated post directly with local keys. - pub fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { Ok(self.inner.sign_with_keys(keys)?) } } #[cfg(feature = "events")] -pub fn radroots_nostr_build_update_event( - update: &AuthoredUpdate, -) -> Result<RadrootsNostrPostEventBuilder, RadrootsNostrError> { +pub fn build_update_event(update: &AuthoredUpdate) -> Result<PostBuilder, Error> { builder_from_wire_parts(authored_update_to_wire_parts(update)) } #[cfg(feature = "events")] -pub fn radroots_nostr_build_photo_update_event( - photo: &AuthoredPhotoUpdate, -) -> Result<RadrootsNostrPostEventBuilder, RadrootsNostrError> { +pub fn build_photo_update_event(photo: &AuthoredPhotoUpdate) -> Result<PostBuilder, Error> { builder_from_wire_parts(authored_photo_update_to_wire_parts(photo)) } #[cfg(feature = "events")] -pub fn radroots_nostr_build_ask_event( - ask: &AuthoredAsk, -) -> Result<RadrootsNostrPostEventBuilder, RadrootsNostrError> { +pub fn build_ask_event(ask: &AuthoredAsk) -> Result<PostBuilder, Error> { builder_from_wire_parts(authored_ask_to_wire_parts(ask)) } -pub fn radroots_nostr_post_events_filter( - limit: Option<u16>, - since_unix: Option<u64>, -) -> RadrootsNostrFilter { +pub fn post_events_filter(limit: Option<u16>, since_unix: Option<u64>) -> RadrootsNostrFilter { let mut filter = RadrootsNostrFilter::new().kind(RadrootsNostrKind::TextNote); if let Some(limit) = limit { filter = filter.limit(limit.into()); @@ -80,10 +68,7 @@ pub fn radroots_nostr_post_events_filter( } #[cfg(feature = "events")] -fn builder_from_wire_parts( - parts: Nip01EventWireParts, -) -> Result<RadrootsNostrPostEventBuilder, RadrootsNostrError> { - let inner = - crate::events::radroots_nostr_build_event_unchecked(parts.kind, parts.content, parts.tags)?; - Ok(RadrootsNostrPostEventBuilder { inner }) +fn builder_from_wire_parts(parts: Nip01EventWireParts) -> Result<PostBuilder, Error> { + let inner = crate::events::build_event_unchecked(parts.kind, parts.content, parts.tags)?; + Ok(PostBuilder { inner }) } diff --git a/crates/nostr/src/events/reply.rs b/crates/nostr/src/events/reply.rs @@ -1,7 +1,7 @@ //! Sealed authoring for strict marked NIP-10 Reply events. use crate::{ - error::RadrootsNostrError, + error::Error, types::{ RadrootsNostrEvent, RadrootsNostrEventBuilderUnchecked, RadrootsNostrKeys, RadrootsNostrTimestamp, @@ -15,42 +15,34 @@ use radroots_event_codec::encode::reply::authored_nip10_reply_to_wire_parts; /// The wrapper exposes no raw builder conversion or tag/content mutation. /// /// ```compile_fail -/// use radroots_nostr::events::reply::RadrootsNostrNip10ReplyEventBuilder; +/// use radroots_nostr::event::Nip10ReplyBuilder; /// -/// fn expose_raw_builder(builder: RadrootsNostrNip10ReplyEventBuilder) { +/// fn expose_raw_builder(builder: Nip10ReplyBuilder) { /// let _: nostr::EventBuilder = builder.into(); /// } /// ``` #[must_use = "NIP-10 Reply builders must be signed or published"] -pub struct RadrootsNostrNip10ReplyEventBuilder { +pub struct Nip10ReplyBuilder { inner: RadrootsNostrEventBuilderUnchecked, } -impl RadrootsNostrNip10ReplyEventBuilder { +impl Nip10ReplyBuilder { pub fn custom_created_at(mut self, created_at: RadrootsNostrTimestamp) -> Self { self.inner = self.inner.custom_created_at(created_at); self } - pub fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { Ok(self.inner.sign_with_keys(keys)?) } } -pub fn radroots_nostr_build_nip10_reply_event( - reply: &AuthoredNip10Reply, -) -> Result<RadrootsNostrNip10ReplyEventBuilder, RadrootsNostrError> { +pub fn build_nip10_reply_event(reply: &AuthoredNip10Reply) -> Result<Nip10ReplyBuilder, Error> { let parts = authored_nip10_reply_to_wire_parts(reply); builder_from_wire_parts(parts) } -fn builder_from_wire_parts( - parts: Nip01EventWireParts, -) -> Result<RadrootsNostrNip10ReplyEventBuilder, RadrootsNostrError> { - let inner = - crate::events::radroots_nostr_build_event_unchecked(parts.kind, parts.content, parts.tags)?; - Ok(RadrootsNostrNip10ReplyEventBuilder { inner }) +fn builder_from_wire_parts(parts: Nip01EventWireParts) -> Result<Nip10ReplyBuilder, Error> { + let inner = crate::events::build_event_unchecked(parts.kind, parts.content, parts.tags)?; + Ok(Nip10ReplyBuilder { inner }) } diff --git a/crates/nostr/src/filter.rs b/crates/nostr/src/filter.rs @@ -3,7 +3,7 @@ //! Filters are passive protocol values. Constructing one does not subscribe, //! contact a relay, install a clock, or retain runtime state. -use crate::error::RadrootsNostrError; +use crate::Error; use crate::event::Kind; #[cfg(feature = "std")] use crate::event::Timestamp; @@ -12,34 +12,30 @@ use alloc::{string::String, string::ToString, vec::Vec}; /// Upstream Nostr filter used only at the explicit protocol boundary. pub type Filter = nostr::Filter; -pub fn radroots_nostr_filter_tag( - filter: Filter, - tag: &str, - values: Vec<String>, -) -> Result<Filter, RadrootsNostrError> { +pub fn with_tag(filter: Filter, tag: &str, values: Vec<String>) -> Result<Filter, Error> { let mut chars = tag.chars(); let tag_char = chars .next() - .ok_or_else(|| RadrootsNostrError::FilterTagError("tag is empty".to_string()))?; + .ok_or_else(|| Error::FilterTagError("tag is empty".to_string()))?; if chars.next().is_some() { - return Err(RadrootsNostrError::FilterTagError( + return Err(Error::FilterTagError( "tag must be a single letter".to_string(), )); } let tag_key = nostr::filter::SingleLetterTag::from_char(tag_char) - .map_err(|err| RadrootsNostrError::FilterTagError(err.to_string()))?; + .map_err(|err| Error::FilterTagError(err.to_string()))?; Ok(filter.custom_tags(tag_key, values)) } -pub fn radroots_nostr_kind(kind: u16) -> Kind { +pub fn kind(kind: u16) -> Kind { Kind::Custom(kind) } -pub fn radroots_nostr_filter_kind(kind: u16) -> Filter { +pub fn for_kind(kind: u16) -> Filter { Filter::new().kind(Kind::Custom(kind)) } #[cfg(feature = "std")] -pub fn radroots_nostr_filter_new_events(filter: Filter) -> Filter { +pub fn since_now(filter: Filter) -> Filter { filter.since(Timestamp::now()) } diff --git a/crates/nostr/src/job_adapter.rs b/crates/nostr/src/job_adapter.rs @@ -10,13 +10,13 @@ use radroots_event::envelope::kind::KIND_PROFILE; use radroots_event_codec::decode::job::{JobEventBorrow, JobEventLike}; #[derive(Clone, Debug)] -pub struct RadrootsNostrEventAdapter<'a> { +pub struct EventAdapter<'a> { evt: &'a RadrootsNostrEvent, id_hex: String, author_hex: String, } -impl<'a> RadrootsNostrEventAdapter<'a> { +impl<'a> EventAdapter<'a> { #[inline] pub fn new(evt: &'a RadrootsNostrEvent) -> Self { Self { @@ -36,7 +36,7 @@ impl<'a> RadrootsNostrEventAdapter<'a> { } } -impl<'a> JobEventBorrow<'a> for RadrootsNostrEventAdapter<'a> { +impl<'a> JobEventBorrow<'a> for EventAdapter<'a> { #[inline] fn raw_id(&'a self) -> String { self.id_hex.clone() @@ -58,7 +58,7 @@ impl<'a> JobEventBorrow<'a> for RadrootsNostrEventAdapter<'a> { } } -impl JobEventLike for RadrootsNostrEventAdapter<'_> { +impl JobEventLike for EventAdapter<'_> { fn raw_id(&self) -> String { self.id_hex.clone() } diff --git a/crates/nostr/src/lib.rs b/crates/nostr/src/lib.rs @@ -9,26 +9,28 @@ extern crate core as std; #[cfg(feature = "blossom")] pub mod blossom; -pub mod error; +mod error; pub mod event; -pub mod events; +#[cfg(feature = "events")] +mod events; pub mod filter; pub mod key; pub mod tag; mod tags; -pub mod types; -pub mod util; +mod types; +#[cfg(feature = "events")] +mod util; -pub use error::RadrootsNostrError as Error; +pub use error::Error; #[cfg(test)] mod test_fixtures; -#[cfg(feature = "codec")] -pub mod codec_adapters; +#[cfg(feature = "events")] +mod codec_adapters; -#[cfg(feature = "codec")] -pub mod job_adapter; +#[cfg(feature = "events")] +mod job_adapter; #[cfg(feature = "nip17")] pub mod nip17; @@ -37,11 +39,11 @@ pub mod nip17; pub mod signing; #[cfg(feature = "events")] -pub mod event_adapters; +mod event_adapters; -#[cfg(feature = "events")] -pub mod draft_signing; +#[cfg(feature = "signing")] +mod draft_signing; #[cfg(feature = "events")] mod event_convert; #[cfg(feature = "events")] -pub mod event_verify; +mod event_verify; diff --git a/crates/nostr/src/nip17.rs b/crates/nostr/src/nip17.rs @@ -27,7 +27,7 @@ use radroots_event_codec::encode::{EventEncodeError, message as message_encode}; /// Stable, source-redacted failures from the focused NIP-17 adapter. #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] -pub enum RadrootsNip17Error { +pub enum Error { MessageEncode, MessageDecode, GiftWrap, @@ -36,7 +36,7 @@ pub enum RadrootsNip17Error { UnsupportedRumorKind { kind: u32 }, } -impl RadrootsNip17Error { +impl Error { /// Returns a stable machine-readable failure code. #[must_use] pub const fn code(&self) -> &'static str { @@ -51,7 +51,7 @@ impl RadrootsNip17Error { } } -impl core::fmt::Display for RadrootsNip17Error { +impl core::fmt::Display for Error { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::MessageEncode => formatter.write_str("failed to encode NIP-17 message"), @@ -66,71 +66,71 @@ impl core::fmt::Display for RadrootsNip17Error { } } -impl core::error::Error for RadrootsNip17Error {} +impl core::error::Error for Error {} -impl From<EventEncodeError> for RadrootsNip17Error { +impl From<EventEncodeError> for Error { fn from(_: EventEncodeError) -> Self { Self::MessageEncode } } -impl From<EventParseError> for RadrootsNip17Error { +impl From<EventParseError> for Error { fn from(_: EventParseError) -> Self { Self::MessageDecode } } -impl From<nip59::Error> for RadrootsNip17Error { +impl From<nip59::Error> for Error { fn from(_: nip59::Error) -> Self { Self::GiftWrap } } -impl From<nostr::event::builder::Error> for RadrootsNip17Error { +impl From<nostr::event::builder::Error> for Error { fn from(_: nostr::event::builder::Error) -> Self { Self::GiftWrap } } -impl From<nostr::signer::SignerError> for RadrootsNip17Error { +impl From<nostr::signer::SignerError> for Error { fn from(_: nostr::signer::SignerError) -> Self { Self::Signer } } -impl From<nostr::key::Error> for RadrootsNip17Error { +impl From<nostr::key::Error> for Error { fn from(_: nostr::key::Error) -> Self { Self::InvalidRecipient } } #[derive(Clone)] -pub enum RadrootsNip17Rumor { +pub enum Rumor { Message(RadrootsParsedData<Message>), MessageFile(Box<RadrootsParsedData<MessageFile>>), } -impl core::fmt::Debug for RadrootsNip17Rumor { +impl core::fmt::Debug for Rumor { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Message(_) => formatter - .debug_struct("RadrootsNip17Rumor::Message") + .debug_struct("Rumor::Message") .finish_non_exhaustive(), Self::MessageFile(_) => formatter - .debug_struct("RadrootsNip17Rumor::MessageFile") + .debug_struct("Rumor::MessageFile") .finish_non_exhaustive(), } } } #[derive(Clone, Debug)] -pub struct RadrootsNip17WrapOptions { - pub include_sender: bool, - pub rumor_created_at: Option<u64>, - pub gift_wrap_tags: Vec<Vec<String>>, +pub struct WrapOptions { + include_sender: bool, + rumor_created_at: Option<u64>, + gift_wrap_tags: Vec<Vec<String>>, } -impl Default for RadrootsNip17WrapOptions { +impl Default for WrapOptions { fn default() -> Self { Self { include_sender: true, @@ -140,6 +140,38 @@ impl Default for RadrootsNip17WrapOptions { } } +impl WrapOptions { + #[must_use] + pub fn include_sender(mut self, include_sender: bool) -> Self { + self.include_sender = include_sender; + self + } + + #[must_use] + pub fn with_rumor_created_at(mut self, created_at: u64) -> Self { + self.rumor_created_at = Some(created_at); + self + } + + #[must_use] + pub fn with_gift_wrap_tags(mut self, tags: Vec<Vec<String>>) -> Self { + self.gift_wrap_tags = tags; + self + } + + pub const fn includes_sender(&self) -> bool { + self.include_sender + } + + pub const fn rumor_created_at(&self) -> Option<u64> { + self.rumor_created_at + } + + pub fn gift_wrap_tags(&self) -> &[Vec<String>] { + &self.gift_wrap_tags + } +} + fn tags_from_slices(tag_slices: &[Vec<String>]) -> Vec<Tag> { let mut tags = Vec::with_capacity(tag_slices.len()); for slice in tag_slices { @@ -157,9 +189,9 @@ fn rumor_from_parts( parts: Nip01EventWireParts, author: PublicKey, created_at: Option<u64>, -) -> Result<UnsignedEvent, RadrootsNip17Error> { - let kind = u16::try_from(parts.kind) - .map_err(|_| RadrootsNip17Error::UnsupportedRumorKind { kind: parts.kind })?; +) -> Result<UnsignedEvent, Error> { + let kind = + u16::try_from(parts.kind).map_err(|_| Error::UnsupportedRumorKind { kind: parts.kind })?; let tags = tags_from_slices(&parts.tags); let timestamp = match created_at { Some(ts) => Timestamp::from_secs(ts), @@ -172,7 +204,7 @@ fn rumor_from_parts( fn parse_recipients( recipients: &[radroots_event::social::message::MessageRecipient], -) -> Result<Vec<PublicKey>, RadrootsNip17Error> { +) -> Result<Vec<PublicKey>, Error> { let mut out = Vec::with_capacity(recipients.len()); for recipient in recipients { out.push(recipient.public_key.parse::<PublicKey>()?); @@ -191,8 +223,8 @@ async fn wrap_rumor<T>( signer: &T, rumor: UnsignedEvent, mut recipients: Vec<PublicKey>, - options: &RadrootsNip17WrapOptions, -) -> Result<Vec<Event>, RadrootsNip17Error> + options: &WrapOptions, +) -> Result<Vec<Event>, Error> where T: NostrSigner, { @@ -211,11 +243,11 @@ where Ok(out) } -pub async fn radroots_nostr_wrap_message<T>( +pub async fn wrap_message<T>( signer: &T, message: &Message, - options: RadrootsNip17WrapOptions, -) -> Result<Vec<Event>, RadrootsNip17Error> + options: WrapOptions, +) -> Result<Vec<Event>, Error> where T: NostrSigner, { @@ -226,11 +258,11 @@ where wrap_rumor(signer, rumor, recipients, &options).await } -pub async fn radroots_nostr_wrap_message_file<T>( +pub async fn wrap_message_file<T>( signer: &T, message: &MessageFile, - options: RadrootsNip17WrapOptions, -) -> Result<Vec<Event>, RadrootsNip17Error> + options: WrapOptions, +) -> Result<Vec<Event>, Error> where T: NostrSigner, { @@ -241,10 +273,7 @@ where wrap_rumor(signer, rumor, recipients, &options).await } -pub async fn radroots_nostr_unwrap_gift_wrap<T>( - signer: &T, - gift_wrap: &Event, -) -> Result<RadrootsNip17Rumor, RadrootsNip17Error> +pub async fn unwrap_gift_wrap<T>(signer: &T, gift_wrap: &Event) -> Result<Rumor, Error> where T: NostrSigner, { @@ -266,7 +295,7 @@ where KIND_MESSAGE => { let metadata = message_decode::data_from_event(id, author, published_at, kind, content, tags)?; - Ok(RadrootsNip17Rumor::Message(metadata)) + Ok(Rumor::Message(metadata)) } KIND_MESSAGE_FILE => { let metadata = message_file_decode::data_from_event( @@ -277,9 +306,9 @@ where content, tags, )?; - Ok(RadrootsNip17Rumor::MessageFile(Box::new(metadata))) + Ok(Rumor::MessageFile(Box::new(metadata))) } - other => Err(RadrootsNip17Error::UnsupportedRumorKind { kind: other }), + other => Err(Error::UnsupportedRumorKind { kind: other }), } } @@ -325,25 +354,22 @@ mod tests { author, Some(1_700_000_000), ), - Err(RadrootsNip17Error::UnsupportedRumorKind { kind }) if kind == overflow + Err(Error::UnsupportedRumorKind { kind }) if kind == overflow )); } #[test] fn adapter_error_codes_are_stable_and_source_redacted() { let errors = [ - RadrootsNip17Error::MessageEncode, - RadrootsNip17Error::MessageDecode, - RadrootsNip17Error::GiftWrap, - RadrootsNip17Error::Signer, - RadrootsNip17Error::InvalidRecipient, - RadrootsNip17Error::UnsupportedRumorKind { kind: 70_000 }, + Error::MessageEncode, + Error::MessageDecode, + Error::GiftWrap, + Error::Signer, + Error::InvalidRecipient, + Error::UnsupportedRumorKind { kind: 70_000 }, ]; assert_eq!( - errors - .iter() - .map(RadrootsNip17Error::code) - .collect::<Vec<_>>(), + errors.iter().map(Error::code).collect::<Vec<_>>(), vec![ "message_encode", "message_decode", @@ -373,22 +399,16 @@ mod tests { reply_to: None, subject: None, }; - let options = RadrootsNip17WrapOptions { - include_sender: false, - rumor_created_at: Some(1700000000), - gift_wrap_tags: Vec::new(), - }; + let options = WrapOptions::default() + .include_sender(false) + .with_rumor_created_at(1_700_000_000); - let events = radroots_nostr_wrap_message(&sender, &message, options) - .await - .unwrap(); + let events = wrap_message(&sender, &message, options).await.unwrap(); assert_eq!(events.len(), 1); - let rumor = radroots_nostr_unwrap_gift_wrap(&receiver, &events[0]) - .await - .unwrap(); + let rumor = unwrap_gift_wrap(&receiver, &events[0]).await.unwrap(); match rumor { - RadrootsNip17Rumor::Message(metadata) => { + Rumor::Message(metadata) => { assert_eq!(metadata.data.content, "hello"); assert_eq!(metadata.data.recipients.len(), 1); } @@ -420,20 +440,14 @@ mod tests { thumb: None, fallbacks: Vec::new(), }; - let options = RadrootsNip17WrapOptions { - include_sender: false, - rumor_created_at: Some(1700000001), - gift_wrap_tags: Vec::new(), - }; + let options = WrapOptions::default() + .include_sender(false) + .with_rumor_created_at(1_700_000_001); - let events = radroots_nostr_wrap_message_file(&sender, &message, options) - .await - .unwrap(); + let events = wrap_message_file(&sender, &message, options).await.unwrap(); assert_eq!(events.len(), 1); - let rumor = radroots_nostr_unwrap_gift_wrap(&receiver, &events[0]) - .await - .unwrap(); + let rumor = unwrap_gift_wrap(&receiver, &events[0]).await.unwrap(); let rendered = format!("{rumor:?}"); for private_value in [ message.file_url.as_str(), @@ -444,7 +458,7 @@ mod tests { assert!(!rendered.contains(private_value)); } match rumor { - RadrootsNip17Rumor::MessageFile(metadata) => { + Rumor::MessageFile(metadata) => { assert_eq!(metadata.data.file_url, message.file_url); assert_eq!(metadata.data.encrypted_hash, message.encrypted_hash); } diff --git a/crates/nostr/src/signing.rs b/crates/nostr/src/signing.rs @@ -17,11 +17,11 @@ use radroots_signing::{ status::{SignProgress, SignProgressStage, SignerAvailability}, }; -use crate::{ - draft_signing::radroots_nostr_sign_frozen_draft, error::RadrootsNostrError, key::SecretKey, -}; +use crate::{Error as NostrError, key::SecretKey}; use radroots_identity::PublicKey; +pub use crate::draft_signing::sign_frozen_draft; + type Clock = fn() -> Result<u64, SigningError>; /// A local Nostr key-backed signer adapter. @@ -97,8 +97,8 @@ impl Signer for LocalSigner { &SignProgress::stage(SignProgressStage::Validating) .expect("validating progress never requires a challenge"), ); - let signed_event = radroots_nostr_sign_frozen_draft(&self.keys, request.draft()) - .map_err(normalize_nostr_error)?; + let signed_event = + sign_frozen_draft(&self.keys, request.draft()).map_err(normalize_nostr_error)?; request.report_progress( &SignProgress::stage(SignProgressStage::VerifyingOutput) .expect("verification progress never requires a challenge"), @@ -125,10 +125,10 @@ fn system_time_unix() -> Result<u64, SigningError> { .map_err(|source| SigningError::with_source(Kind::InternalError, source)) } -fn normalize_nostr_error(source: RadrootsNostrError) -> SigningError { +fn normalize_nostr_error(source: NostrError) -> SigningError { let kind = match &source { - RadrootsNostrError::FrozenDraftPubkeyMismatch { .. } => Kind::AuthorizationDenied, - RadrootsNostrError::FrozenDraftEventIdMismatch { .. } => Kind::SignerOutputInvalid, + NostrError::FrozenDraftPubkeyMismatch { .. } => Kind::AuthorizationDenied, + NostrError::FrozenDraftEventIdMismatch { .. } => Kind::SignerOutputInvalid, _ => Kind::InternalError, }; SigningError::with_source(kind, source) diff --git a/crates/nostr/src/tag.rs b/crates/nostr/src/tag.rs @@ -14,12 +14,13 @@ pub type TagKind<'a> = nostr::TagKind<'a>; /// Upstream standardized Nostr tag used only at the explicit protocol boundary. pub type TagStandard = nostr::TagStandard; +pub use crate::error::ResolveError; pub use crate::tags::{ - radroots_nostr_tag_at_value, radroots_nostr_tag_first_value, radroots_nostr_tag_match_geohash, - radroots_nostr_tag_match_l, radroots_nostr_tag_match_location, - radroots_nostr_tag_match_summary, radroots_nostr_tag_match_title, - radroots_nostr_tag_relays_parse, radroots_nostr_tag_slice, radroots_nostr_tags_match, - radroots_nostr_tags_resolve, + tag_at_value as value_at, tag_first_value as first_value, tag_match_geohash as match_geohash, + tag_match_l as match_location_coordinate, tag_match_location as match_location, + tag_match_summary as match_summary, tag_match_title as match_title, + tag_relays_parse as relay_urls, tag_slice as values_from, tags_match as match_parts, + tags_resolve as resolve, }; /// Parses canonical tag parts into the explicit Nostr tag boundary value. diff --git a/crates/nostr/src/tags.rs b/crates/nostr/src/tags.rs @@ -7,13 +7,13 @@ use alloc::{ use nostr::nips::nip04; -use crate::error::RadrootsNostrTagsResolveError; +use crate::error::ResolveError; use crate::types::{ RadrootsNostrEvent, RadrootsNostrKeys, RadrootsNostrPublicKey, RadrootsNostrRelayUrl, RadrootsNostrTag, RadrootsNostrTagKind, RadrootsNostrTagStandard, }; -pub fn radroots_nostr_tag_first_value(tag: &RadrootsNostrTag, key: &str) -> Option<String> { +pub fn tag_first_value(tag: &RadrootsNostrTag, key: &str) -> Option<String> { if tag.kind() == RadrootsNostrTagKind::custom(key) { tag.content().map(|v| v.to_string()) } else { @@ -21,31 +21,29 @@ pub fn radroots_nostr_tag_first_value(tag: &RadrootsNostrTag, key: &str) -> Opti } } -pub fn radroots_nostr_tag_at_value(tag: &RadrootsNostrTag, index: usize) -> Option<String> { +pub fn tag_at_value(tag: &RadrootsNostrTag, index: usize) -> Option<String> { tag.as_slice().get(index).cloned() } -pub fn radroots_nostr_tag_slice(tag: &RadrootsNostrTag, start: usize) -> Option<Vec<String>> { +pub fn tag_slice(tag: &RadrootsNostrTag, start: usize) -> Option<Vec<String>> { tag.as_slice().get(start..).map(|s| s.to_vec()) } -pub fn radroots_nostr_tag_relays_parse( - tag: &RadrootsNostrTag, -) -> Option<&Vec<RadrootsNostrRelayUrl>> { +pub fn tag_relays_parse(tag: &RadrootsNostrTag) -> Option<&Vec<RadrootsNostrRelayUrl>> { match tag.as_standardized()? { RadrootsNostrTagStandard::Relays(urls) => Some(urls), _ => None, } } -pub fn radroots_nostr_tags_match(tag: &RadrootsNostrTag) -> Option<(&str, &[String])> { +pub fn tags_match(tag: &RadrootsNostrTag) -> Option<(&str, &[String])> { let values = tag.as_slice(); values .split_first() .map(|(key, tag_values)| (key.as_str(), tag_values)) } -pub fn radroots_nostr_tag_match_l(tag: &RadrootsNostrTag) -> Option<(&str, f64)> { +pub fn tag_match_l(tag: &RadrootsNostrTag) -> Option<(&str, f64)> { let values = tag.as_slice(); if values.len() >= 3 && values[0].eq_ignore_ascii_case("l") @@ -56,7 +54,7 @@ pub fn radroots_nostr_tag_match_l(tag: &RadrootsNostrTag) -> Option<(&str, f64)> None } -pub fn radroots_nostr_tag_match_location(tag: &RadrootsNostrTag) -> Option<(&str, &str, &str)> { +pub fn tag_match_location(tag: &RadrootsNostrTag) -> Option<(&str, &str, &str)> { let values = tag.as_slice(); if values.len() >= 4 && values[0] == "location" { Some((values[1].as_str(), values[2].as_str(), values[3].as_str())) @@ -65,31 +63,31 @@ pub fn radroots_nostr_tag_match_location(tag: &RadrootsNostrTag) -> Option<(&str } } -pub fn radroots_nostr_tag_match_geohash(tag: &RadrootsNostrTag) -> Option<String> { +pub fn tag_match_geohash(tag: &RadrootsNostrTag) -> Option<String> { match tag.as_standardized()? { RadrootsNostrTagStandard::Geohash(geohash) => Some(geohash.clone()), _ => None, } } -pub fn radroots_nostr_tag_match_title(tag: &RadrootsNostrTag) -> Option<String> { +pub fn tag_match_title(tag: &RadrootsNostrTag) -> Option<String> { match tag.as_standardized()? { RadrootsNostrTagStandard::Title(title) => Some(title.clone()), _ => None, } } -pub fn radroots_nostr_tag_match_summary(tag: &RadrootsNostrTag) -> Option<String> { +pub fn tag_match_summary(tag: &RadrootsNostrTag) -> Option<String> { match tag.as_standardized()? { RadrootsNostrTagStandard::Summary(summary) => Some(summary.clone()), _ => None, } } -pub fn radroots_nostr_tags_resolve( +pub fn tags_resolve( event: &RadrootsNostrEvent, keys: &RadrootsNostrKeys, -) -> Result<Vec<RadrootsNostrTag>, RadrootsNostrTagsResolveError> { +) -> Result<Vec<RadrootsNostrTag>, ResolveError> { if !event .tags .iter() @@ -107,12 +105,12 @@ pub fn radroots_nostr_tags_resolve( None } }) - .ok_or_else(|| RadrootsNostrTagsResolveError::MissingPTag(Box::new(event.clone())))?; + .ok_or_else(|| ResolveError::MissingPTag(Box::new(event.clone())))?; if recipient != keys.public_key() { - return Err(RadrootsNostrTagsResolveError::NotRecipient); + return Err(ResolveError::NotRecipient); } let cleartext = nip04::decrypt(keys.secret_key(), &event.pubkey, &event.content) - .map_err(|e| RadrootsNostrTagsResolveError::DecryptionError(e.to_string()))?; + .map_err(|e| ResolveError::DecryptionError(e.to_string()))?; let decrypted_tags: nostr::event::tag::list::Tags = serde_json::from_str(&cleartext)?; Ok(decrypted_tags.to_vec()) } diff --git a/crates/nostr/src/types.rs b/crates/nostr/src/types.rs @@ -6,31 +6,31 @@ #![forbid(unsafe_code)] -#[cfg(feature = "std")] -use crate::error::RadrootsNostrError; -#[cfg(feature = "std")] +#[cfg(all(feature = "events", feature = "std"))] +use crate::error::Error; +#[cfg(all(feature = "events", feature = "std"))] use radroots_event::listing::classified::{ ClassifiedListingPartition, classify_classified_listing_marker_names, }; +pub(crate) use crate::event::Event as RadrootsNostrEvent; #[cfg(feature = "events")] pub(crate) use crate::event::Metadata as RadrootsNostrMetadata; +#[cfg(feature = "events")] pub(crate) use crate::event::{ - Event as RadrootsNostrEvent, EventId as RadrootsNostrEventId, Kind as RadrootsNostrKind, - Timestamp as RadrootsNostrTimestamp, + EventId as RadrootsNostrEventId, Kind as RadrootsNostrKind, Timestamp as RadrootsNostrTimestamp, }; +#[cfg(feature = "events")] pub(crate) use crate::filter::Filter as RadrootsNostrFilter; pub(crate) use crate::tag::{ Tag as RadrootsNostrTag, TagKind as RadrootsNostrTagKind, TagStandard as RadrootsNostrTagStandard, }; +#[cfg(feature = "events")] pub(crate) type RadrootsNostrEventBuilderUnchecked = nostr::EventBuilder; -pub type RadrootsNostrKeys = nostr::Keys; -pub type RadrootsNostrPublicKey = nostr::PublicKey; -pub type RadrootsNostrRelayUrl = nostr::RelayUrl; -pub type RadrootsNostrSecretKey = nostr::SecretKey; -pub type RadrootsNostrSubscriptionId = nostr::SubscriptionId; -pub type RadrootsNostrUrl = nostr::Url; +pub(crate) type RadrootsNostrKeys = nostr::Keys; +pub(crate) type RadrootsNostrPublicKey = nostr::PublicKey; +pub(crate) type RadrootsNostrRelayUrl = nostr::RelayUrl; /// A checked generic event prepared for an external signer. /// @@ -40,19 +40,21 @@ pub type RadrootsNostrUrl = nostr::Url; /// deserialization boundary. /// /// ```compile_fail -/// use radroots_nostr::types::RadrootsNostrExternalSigningRequest; +/// use radroots_nostr::event::ExternalSigningRequest; /// -/// let _: RadrootsNostrExternalSigningRequest = +/// let _: ExternalSigningRequest = /// serde_json::from_str("{}").expect("request"); /// ``` #[must_use = "external signing requests must be completed by a signer"] -pub struct RadrootsNostrExternalSigningRequest { +#[cfg(feature = "events")] +pub struct ExternalSigningRequest { unsigned_event: nostr::UnsignedEvent, expected_event_id: RadrootsNostrEventId, expected_public_key: RadrootsNostrPublicKey, } -impl RadrootsNostrExternalSigningRequest { +#[cfg(feature = "events")] +impl ExternalSigningRequest { pub fn expected_event_id(&self) -> RadrootsNostrEventId { self.expected_event_id } @@ -64,39 +66,32 @@ impl RadrootsNostrExternalSigningRequest { /// Accepts an external signing result only when it is the exact requested /// event and its NIP-01 identifier and signature are valid. #[cfg(feature = "std")] - pub fn complete( - self, - event: RadrootsNostrEvent, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn complete(self, event: RadrootsNostrEvent) -> Result<RadrootsNostrEvent, Error> { if event.pubkey != self.expected_public_key { - return Err(RadrootsNostrError::ExternalSigningAuthorMismatch { + return Err(Error::ExternalSigningAuthorMismatch { expected: self.expected_public_key, actual: event.pubkey, }); } if event.id != self.expected_event_id { - return Err(RadrootsNostrError::ExternalSigningEventIdMismatch { + return Err(Error::ExternalSigningEventIdMismatch { expected: self.expected_event_id, actual: event.id, }); } - event - .verify() - .map_err(RadrootsNostrError::ExternalSigningEventInvalid)?; + event.verify().map_err(Error::ExternalSigningEventInvalid)?; Ok(event) } #[cfg(feature = "std")] - fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { let event = self.unsigned_event.clone().sign_with_keys(keys)?; self.complete(event) } } -impl serde::Serialize for RadrootsNostrExternalSigningRequest { +#[cfg(feature = "events")] +impl serde::Serialize for ExternalSigningRequest { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer, @@ -117,45 +112,44 @@ impl serde::Serialize for RadrootsNostrExternalSigningRequest { /// The upstream unsigned builder is intentionally inaccessible: /// /// ```compile_fail -/// use radroots_nostr::types::RadrootsNostrGenericEventBuilder; -/// use radroots_nostr::event::Kind as RadrootsNostrKind; +/// use radroots_nostr::event::{GenericBuilder, Kind}; /// -/// let builder = RadrootsNostrGenericEventBuilder::new( -/// RadrootsNostrKind::Custom(30_001), +/// let builder = GenericBuilder::new( +/// Kind::Custom(30_001), /// "content", /// ); /// let _: nostr::EventBuilder = builder.into(); /// ``` /// /// ```compile_fail -/// use radroots_nostr::types::RadrootsNostrGenericEventBuilder; -/// use radroots_nostr::event::Kind as RadrootsNostrKind; +/// use radroots_nostr::event::{GenericBuilder, Kind}; /// -/// let builder = RadrootsNostrGenericEventBuilder::new( -/// RadrootsNostrKind::Custom(30_001), +/// let builder = GenericBuilder::new( +/// Kind::Custom(30_001), /// "content", /// ); /// let _raw: nostr::EventBuilder = builder.into_inner(); /// ``` /// /// ```compile_fail -/// use radroots_nostr::types::RadrootsNostrGenericEventBuilder; -/// use radroots_nostr::types::RadrootsNostrKeys; -/// use radroots_nostr::event::Kind as RadrootsNostrKind; +/// use nostr::Keys; +/// use radroots_nostr::event::{GenericBuilder, Kind}; /// -/// let builder = RadrootsNostrGenericEventBuilder::new( -/// RadrootsNostrKind::Custom(30_001), +/// let builder = GenericBuilder::new( +/// Kind::Custom(30_001), /// "content", /// ); -/// let keys = RadrootsNostrKeys::generate(); +/// let keys = Keys::generate(); /// let _unsigned = builder.build(keys.public_key()); /// ``` #[must_use = "generic event builders must be signed or published"] -pub struct RadrootsNostrGenericEventBuilder { +#[cfg(feature = "events")] +pub struct GenericBuilder { inner: RadrootsNostrEventBuilderUnchecked, } -impl RadrootsNostrGenericEventBuilder { +#[cfg(feature = "events")] +impl GenericBuilder { pub fn new(kind: RadrootsNostrKind, content: impl Into<alloc::string::String>) -> Self { Self::from_unchecked(RadrootsNostrEventBuilderUnchecked::new(kind, content)) } @@ -199,10 +193,7 @@ impl RadrootsNostrGenericEventBuilder { /// Signs a generic event after enforcing typed-authoring reservations. #[cfg(feature = "std")] - pub fn sign_with_keys( - self, - keys: &RadrootsNostrKeys, - ) -> Result<RadrootsNostrEvent, RadrootsNostrError> { + pub fn sign_with_keys(self, keys: &RadrootsNostrKeys) -> Result<RadrootsNostrEvent, Error> { self.into_external_signing_request(keys.public_key())? .sign_with_keys(keys) } @@ -213,11 +204,11 @@ impl RadrootsNostrGenericEventBuilder { pub fn into_external_signing_request( self, public_key: RadrootsNostrPublicKey, - ) -> Result<RadrootsNostrExternalSigningRequest, RadrootsNostrError> { + ) -> Result<ExternalSigningRequest, Error> { self.validate_generic_authoring_policy()?; let mut unsigned_event = self.inner.build(public_key); let expected_event_id = unsigned_event.id(); - Ok(RadrootsNostrExternalSigningRequest { + Ok(ExternalSigningRequest { unsigned_event, expected_event_id, expected_public_key: public_key, @@ -229,7 +220,7 @@ impl RadrootsNostrGenericEventBuilder { } #[cfg(feature = "std")] - fn validate_generic_authoring_policy(&self) -> Result<(), RadrootsNostrError> { + fn validate_generic_authoring_policy(&self) -> Result<(), Error> { // Inspect an unsigned clone so rejection never consults a signer. PoW // is irrelevant to kind/tag policy and must not delay the check. let mut inspection = self.inner.clone(); @@ -269,18 +260,13 @@ impl RadrootsNostrGenericEventBuilder { || is_reserved_comment || is_reserved_focused_listing { - return Err(RadrootsNostrError::TypedAuthoringRequired { kind }); + return Err(Error::TypedAuthoringRequired { kind }); } Ok(()) } } -pub use nostr::nips::nip19::{ - FromBech32 as RadrootsNostrFromBech32, ToBech32 as RadrootsNostrToBech32, -}; -pub use nostr::secp256k1::SecretKey as RadrootsNostrSecp256k1SecretKey; - -#[cfg(test)] +#[cfg(all(test, feature = "events"))] mod tests { use super::*; @@ -294,15 +280,15 @@ mod tests { for (builder, expected_kind) in [ ( - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Metadata, "{}"), + GenericBuilder::new(RadrootsNostrKind::Metadata, "{}"), RadrootsNostrKind::Metadata.as_u16(), ), ( - RadrootsNostrGenericEventBuilder::text_note("root post"), + GenericBuilder::text_note("root post"), RadrootsNostrKind::TextNote.as_u16(), ), ( - RadrootsNostrGenericEventBuilder::new( + GenericBuilder::new( RadrootsNostrKind::Custom( radroots_event::envelope::kind::KIND_DELETION_REQUEST as u16, ), @@ -311,7 +297,7 @@ mod tests { radroots_event::envelope::kind::KIND_DELETION_REQUEST as u16, ), ( - RadrootsNostrGenericEventBuilder::new( + GenericBuilder::new( RadrootsNostrKind::Custom(radroots_event::envelope::kind::KIND_COMMENT as u16), "Comment", ), @@ -320,7 +306,7 @@ mod tests { ] { assert!(matches!( builder.sign_with_keys(&keys), - Err(RadrootsNostrError::TypedAuthoringRequired { kind }) + Err(Error::TypedAuthoringRequired { kind }) if kind == expected_kind )); } @@ -328,24 +314,23 @@ mod tests { #[test] fn generic_direct_signing_rejects_thread_kind_one() { - let error = RadrootsNostrGenericEventBuilder::text_note("reply") + let error = GenericBuilder::text_note("reply") .tag(RadrootsNostrTag::event(RadrootsNostrEventId::all_zeros())) .sign_with_keys(&keys()) .expect_err("all kind-1 authoring is typed"); assert!(matches!( error, - RadrootsNostrError::TypedAuthoringRequired { kind } + Error::TypedAuthoringRequired { kind } if kind == RadrootsNostrKind::TextNote.as_u16() )); } #[test] fn generic_direct_signing_allows_non_reserved_kind() { - let event = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(30_001), "generic") - .sign_with_keys(&keys()) - .expect("generic kind signs"); + let event = GenericBuilder::new(RadrootsNostrKind::Custom(30_001), "generic") + .sign_with_keys(&keys()) + .expect("generic kind signs"); assert_eq!(event.kind.as_u16(), 30_001); } @@ -353,11 +338,10 @@ mod tests { #[test] fn external_signing_request_serializes_as_canonical_unsigned_event() { let keys = keys(); - let request = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") - .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) - .into_external_signing_request(keys.public_key()) - .expect("checked request"); + let request = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") + .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) + .into_external_signing_request(keys.public_key()) + .expect("checked request"); let expected_event_id = request.expected_event_id(); let encoded = serde_json::to_vec(&request).expect("serialize request"); @@ -374,7 +358,7 @@ mod tests { #[test] fn external_signing_request_rejects_reserved_authoring_before_finalization() { - let error = match RadrootsNostrGenericEventBuilder::text_note("reserved") + let error = match GenericBuilder::text_note("reserved") .into_external_signing_request(keys().public_key()) { Ok(_) => panic!("kind 1 remains typed-only"), @@ -383,7 +367,7 @@ mod tests { assert!(matches!( error, - RadrootsNostrError::TypedAuthoringRequired { kind } + Error::TypedAuthoringRequired { kind } if kind == RadrootsNostrKind::TextNote.as_u16() )); } @@ -391,11 +375,10 @@ mod tests { #[test] fn external_signing_request_accepts_only_the_exact_valid_event() { let keys = keys(); - let request = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") - .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) - .into_external_signing_request(keys.public_key()) - .expect("checked request"); + let request = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") + .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) + .into_external_signing_request(keys.public_key()) + .expect("checked request"); let unsigned_event: nostr::UnsignedEvent = serde_json::from_value(serde_json::to_value(&request).expect("request value")) .expect("unsigned event"); @@ -403,28 +386,25 @@ mod tests { .sign_with_keys(&keys) .expect("valid signing result"); - let wrong_author = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") - .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) - .sign_with_keys(&RadrootsNostrKeys::generate()) - .expect("other author event"); + let wrong_author = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") + .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) + .sign_with_keys(&RadrootsNostrKeys::generate()) + .expect("other author event"); assert!(matches!( request.complete(wrong_author), - Err(RadrootsNostrError::ExternalSigningAuthorMismatch { .. }) + Err(Error::ExternalSigningAuthorMismatch { .. }) )); - let request = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") - .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) - .into_external_signing_request(keys.public_key()) - .expect("checked request"); - let wrong_event_id = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(24_133), "different") - .sign_with_keys(&keys) - .expect("different event"); + let request = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") + .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) + .into_external_signing_request(keys.public_key()) + .expect("checked request"); + let wrong_event_id = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "different") + .sign_with_keys(&keys) + .expect("different event"); assert!(matches!( request.complete(wrong_event_id), - Err(RadrootsNostrError::ExternalSigningEventIdMismatch { .. }) + Err(Error::ExternalSigningEventIdMismatch { .. }) )); for mutate in [ @@ -439,36 +419,31 @@ mod tests { )]); }, ] { - let request = RadrootsNostrGenericEventBuilder::new( - RadrootsNostrKind::Custom(24_133), - "protocol", - ) - .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) - .into_external_signing_request(keys.public_key()) - .expect("checked request"); + let request = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") + .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) + .into_external_signing_request(keys.public_key()) + .expect("checked request"); let mut tampered = valid_event.clone(); mutate(&mut tampered); assert!(matches!( request.complete(tampered), - Err(RadrootsNostrError::ExternalSigningEventInvalid(_)) + Err(Error::ExternalSigningEventInvalid(_)) )); } - let other_signature = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(24_133), "different") - .sign_with_keys(&keys) - .expect("other event") - .sig; - let request = - RadrootsNostrGenericEventBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") - .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) - .into_external_signing_request(keys.public_key()) - .expect("checked request"); + let other_signature = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "different") + .sign_with_keys(&keys) + .expect("other event") + .sig; + let request = GenericBuilder::new(RadrootsNostrKind::Custom(24_133), "protocol") + .custom_created_at(RadrootsNostrTimestamp::from_secs(1_234)) + .into_external_signing_request(keys.public_key()) + .expect("checked request"); let mut invalid_signature = valid_event; invalid_signature.sig = other_signature; assert!(matches!( request.complete(invalid_signature), - Err(RadrootsNostrError::ExternalSigningEventInvalid(_)) + Err(Error::ExternalSigningEventInvalid(_)) )); } } diff --git a/crates/nostr/tests/blossom_conformance.rs b/crates/nostr/tests/blossom_conformance.rs @@ -1,6 +1,7 @@ #![cfg(feature = "blossom")] use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD}; +use nostr::Keys as RadrootsNostrKeys; use radroots_blossom::{ Sha256, authorization::{ @@ -11,15 +12,14 @@ use radroots_blossom::{ }, }; use radroots_nostr::blossom::{ - RadrootsNostrBlossomError, radroots_nostr_decode_verify_blossom_authorization_header, - radroots_nostr_encode_blossom_authorization_header, radroots_nostr_sign_blossom_authorization, + AuthorizationError, decode_verify_authorization_header, encode_authorization_header, + sign_authorization, }; use radroots_nostr::{ event::{ Event as RadrootsNostrEvent, Kind as RadrootsNostrKind, Timestamp as RadrootsNostrTimestamp, }, tag::Tag as RadrootsNostrTag, - types::RadrootsNostrKeys, }; use serde::Deserialize; use serde_json::Value; @@ -94,11 +94,9 @@ fn execute_vector(vector: &Vector) { let validation = vector_validation(vector); match vector.kind.as_str() { "blossom.bud11.nostr.decode_verify.valid" => { - let verified = radroots_nostr_decode_verify_blossom_authorization_header( - input_str(vector, "header"), - &validation, - ) - .unwrap_or_else(|error| panic!("{} failed: {error}", vector.id)); + let verified = + decode_verify_authorization_header(input_str(vector, "header"), &validation) + .unwrap_or_else(|error| panic!("{} failed: {error}", vector.id)); assert_eq!( verified.event_id().to_string(), expected_str(vector, "event_id"), @@ -159,16 +157,14 @@ fn execute_vector(vector: &Vector) { ); } "blossom.bud11.nostr.decode_verify.invalid" => { - let error = radroots_nostr_decode_verify_blossom_authorization_header( - input_str(vector, "header"), - &validation, - ) - .expect_err("invalid BUD-11 Nostr vector must fail"); + let error = + decode_verify_authorization_header(input_str(vector, "header"), &validation) + .expect_err("invalid BUD-11 Nostr vector must fail"); assert_eq!(error.code(), expected_str(vector, "error"), "{}", vector.id); if let Some(actual_kind) = vector.expected.get("actual_kind") { assert_eq!( error, - RadrootsNostrBlossomError::InvalidEventKind { + AuthorizationError::InvalidEventKind { actual: actual_kind.as_u64().expect("actual_kind must be u64"), }, "{}", @@ -366,11 +362,10 @@ fn sign_raw(kind: u16, content: &str, tags: Vec<RadrootsNostrTag>) -> RadrootsNo #[test] fn blossom_authored_claim_signs_and_roundtrips_without_signature_assumptions() { let claim = authored_claim(); - let signed = radroots_nostr_sign_blossom_authorization(&keys(), &claim) - .expect("sign authored authorization"); + let signed = sign_authorization(&keys(), &claim).expect("sign authored authorization"); let wire = claim.wire_parts(); - let header = radroots_nostr_encode_blossom_authorization_header(&signed); + let header = encode_authorization_header(&signed); let event = event_from_header(header.as_str()); assert_eq!(event.kind.as_u16(), wire.kind()); @@ -397,8 +392,7 @@ fn blossom_authored_claim_signs_and_roundtrips_without_signature_assumptions() { assert!(!format!("{signed:?}").contains(&event.sig.to_string())); let verified = - radroots_nostr_decode_verify_blossom_authorization_header(header.as_str(), &validation()) - .expect("verify header"); + decode_verify_authorization_header(header.as_str(), &validation()).expect("verify header"); assert_eq!(verified.event_id(), event.id); assert_eq!(verified.author(), keys().public_key()); assert_eq!(verified.created_at(), event.created_at); @@ -413,61 +407,49 @@ fn blossom_authored_claim_signs_and_roundtrips_without_signature_assumptions() { #[test] fn blossom_header_rejects_noncanonical_and_malformed_encodings() { - let signed = radroots_nostr_sign_blossom_authorization(&keys(), &authored_claim()) - .expect("sign authored authorization"); - let valid = radroots_nostr_encode_blossom_authorization_header(&signed).into_string(); + let signed = + sign_authorization(&keys(), &authored_claim()).expect("sign authored authorization"); + let valid = encode_authorization_header(&signed).into_string(); let policy = validation(); for accepted in [ valid.replacen("Nostr ", "nostr ", 1), valid.replacen("Nostr ", "NOSTR ", 1), ] { - radroots_nostr_decode_verify_blossom_authorization_header(&accepted, &policy) + decode_verify_authorization_header(&accepted, &policy) .expect("auth-scheme is case-insensitive and accepts 1*SP"); } let cases = [ ( format!(" {valid}"), - RadrootsNostrBlossomError::InvalidHeaderWhitespace, + AuthorizationError::InvalidHeaderWhitespace, ), ( "Nostr e 30".to_owned(), - RadrootsNostrBlossomError::InvalidHeaderWhitespace, - ), - ( - "Nostr".to_owned(), - RadrootsNostrBlossomError::InvalidHeaderScheme, - ), - ( - "Nostr ".to_owned(), - RadrootsNostrBlossomError::EmptyHeaderPayload, + AuthorizationError::InvalidHeaderWhitespace, ), + ("Nostr".to_owned(), AuthorizationError::InvalidHeaderScheme), + ("Nostr ".to_owned(), AuthorizationError::EmptyHeaderPayload), ( format!("{valid}="), - RadrootsNostrBlossomError::HeaderPaddingForbidden, + AuthorizationError::HeaderPaddingForbidden, ), ( "Nostr +".to_owned(), - RadrootsNostrBlossomError::InvalidHeaderBase64, + AuthorizationError::InvalidHeaderBase64, ), ( "Nostr Zh".to_owned(), - RadrootsNostrBlossomError::NonCanonicalHeaderBase64, - ), - ( - "Nostr _w".to_owned(), - RadrootsNostrBlossomError::InvalidHeaderUtf8, - ), - ( - "Nostr e30".to_owned(), - RadrootsNostrBlossomError::InvalidEventJson, + AuthorizationError::NonCanonicalHeaderBase64, ), + ("Nostr _w".to_owned(), AuthorizationError::InvalidHeaderUtf8), + ("Nostr e30".to_owned(), AuthorizationError::InvalidEventJson), ]; for (header, expected) in cases { assert_eq!( - radroots_nostr_decode_verify_blossom_authorization_header(&header, &policy), + decode_verify_authorization_header(&header, &policy), Err(expected), "{header}" ); @@ -476,9 +458,9 @@ fn blossom_header_rejects_noncanonical_and_malformed_encodings() { #[test] fn blossom_header_rejects_kind_narrowing_and_json_shape_laundering() { - let signed = radroots_nostr_sign_blossom_authorization(&keys(), &authored_claim()) - .expect("sign authored authorization"); - let encoded = radroots_nostr_encode_blossom_authorization_header(&signed); + let signed = + sign_authorization(&keys(), &authored_claim()).expect("sign authored authorization"); + let encoded = encode_authorization_header(&signed); let event_json = serde_json::to_string(&event_from_header(encoded.as_str())).expect("event JSON"); let policy = validation(); @@ -486,37 +468,34 @@ fn blossom_header_rejects_kind_narrowing_and_json_shape_laundering() { let cases = [ ( event_json.replacen("\"kind\":24242", "\"kind\":89778", 1), - RadrootsNostrBlossomError::InvalidEventKind { actual: 89_778 }, + AuthorizationError::InvalidEventKind { actual: 89_778 }, ), ( format!( "{},\"unknown\":true}}", event_json.strip_suffix('}').unwrap() ), - RadrootsNostrBlossomError::InvalidEventJson, + AuthorizationError::InvalidEventJson, ), ( event_json.replacen("\"content\":", "\"unknown\":", 1), - RadrootsNostrBlossomError::InvalidEventJson, + AuthorizationError::InvalidEventJson, ), ( event_json.replacen("\"kind\":24242", "\"kind\":24242,\"kind\":24242", 1), - RadrootsNostrBlossomError::InvalidEventJson, + AuthorizationError::InvalidEventJson, ), ( event_json.replacen("\"kind\":24242", "\"kind\":\"24242\"", 1), - RadrootsNostrBlossomError::InvalidEventJson, + AuthorizationError::InvalidEventJson, ), - ("[]".to_owned(), RadrootsNostrBlossomError::InvalidEventJson), - ("{".to_owned(), RadrootsNostrBlossomError::InvalidEventJson), + ("[]".to_owned(), AuthorizationError::InvalidEventJson), + ("{".to_owned(), AuthorizationError::InvalidEventJson), ]; for (json, expected) in cases { assert_eq!( - radroots_nostr_decode_verify_blossom_authorization_header( - &raw_json_header(&json), - &policy, - ), + decode_verify_authorization_header(&raw_json_header(&json), &policy,), Err(expected), "{json}" ); @@ -529,19 +508,16 @@ fn blossom_header_authenticates_before_claim_parsing() { let wrong_kind = sign_raw(1, "", Vec::new()); assert_eq!( - radroots_nostr_decode_verify_blossom_authorization_header( - &raw_header(&wrong_kind), - &policy - ), - Err(RadrootsNostrBlossomError::InvalidEventKind { actual: 1 }) + decode_verify_authorization_header(&raw_header(&wrong_kind), &policy), + Err(AuthorizationError::InvalidEventKind { actual: 1 }) ); let malformed_claim = sign_raw(RADROOTS_BLOSSOM_AUTHORIZATION_EVENT_KIND, "", Vec::new()); let mut bad_id = malformed_claim.clone(); bad_id.content.push('x'); assert_eq!( - radroots_nostr_decode_verify_blossom_authorization_header(&raw_header(&bad_id), &policy), - Err(RadrootsNostrBlossomError::InvalidEventId) + decode_verify_authorization_header(&raw_header(&bad_id), &policy), + Err(AuthorizationError::InvalidEventId) ); let mut bad_signature = malformed_claim.clone(); @@ -554,27 +530,21 @@ fn blossom_header_authenticates_before_claim_parsing() { assert!(bad_signature.verify_id()); assert!(!bad_signature.verify_signature()); assert_eq!( - radroots_nostr_decode_verify_blossom_authorization_header( - &raw_header(&bad_signature), - &policy - ), - Err(RadrootsNostrBlossomError::InvalidEventSignature) + decode_verify_authorization_header(&raw_header(&bad_signature), &policy), + Err(AuthorizationError::InvalidEventSignature) ); let raw_tags: Vec<Vec<String>> = Vec::new(); let pure_error = AuthorizationClaim::parse("", CREATED_AT, &raw_tags) .expect_err("empty content is not a claim"); - let adapter_error = radroots_nostr_decode_verify_blossom_authorization_header( - &raw_header(&malformed_claim), - &policy, - ) - .expect_err("authenticated malformed claim must fail"); + let adapter_error = decode_verify_authorization_header(&raw_header(&malformed_claim), &policy) + .expect_err("authenticated malformed claim must fail"); assert_eq!(adapter_error.code(), pure_error.code()); assert_eq!(adapter_error.blossom_claim_error(), Some(&pure_error)); assert_eq!(adapter_error.to_string(), pure_error.to_string()); - let signed = radroots_nostr_sign_blossom_authorization(&keys(), &authored_claim()) - .expect("sign authored authorization"); + let signed = + sign_authorization(&keys(), &authored_claim()).expect("sign authored authorization"); let media_policy = AuthorizationValidation::new( AuthorizationTarget::Media(hash()), server(), @@ -583,8 +553,8 @@ fn blossom_header_authenticates_before_claim_parsing() { RADROOTS_BLOSSOM_AUTH_MAX_CREATED_AGE_SECONDS, ) .expect("media validation policy"); - let validation_error = radroots_nostr_decode_verify_blossom_authorization_header( - radroots_nostr_encode_blossom_authorization_header(&signed).as_str(), + let validation_error = decode_verify_authorization_header( + encode_authorization_header(&signed).as_str(), &media_policy, ) .expect_err("upload claim must not authorize media endpoint"); @@ -594,22 +564,22 @@ fn blossom_header_authenticates_before_claim_parsing() { #[test] fn blossom_adapter_error_codes_are_stable_and_distinct() { let errors = [ - RadrootsNostrBlossomError::InvalidHeaderWhitespace, - RadrootsNostrBlossomError::InvalidHeaderScheme, - RadrootsNostrBlossomError::EmptyHeaderPayload, - RadrootsNostrBlossomError::HeaderPaddingForbidden, - RadrootsNostrBlossomError::InvalidHeaderBase64, - RadrootsNostrBlossomError::NonCanonicalHeaderBase64, - RadrootsNostrBlossomError::InvalidHeaderUtf8, - RadrootsNostrBlossomError::InvalidEventJson, - RadrootsNostrBlossomError::InvalidEventKind { actual: 1 }, - RadrootsNostrBlossomError::InvalidEventId, - RadrootsNostrBlossomError::InvalidEventSignature, - RadrootsNostrBlossomError::EventSigning, + AuthorizationError::InvalidHeaderWhitespace, + AuthorizationError::InvalidHeaderScheme, + AuthorizationError::EmptyHeaderPayload, + AuthorizationError::HeaderPaddingForbidden, + AuthorizationError::InvalidHeaderBase64, + AuthorizationError::NonCanonicalHeaderBase64, + AuthorizationError::InvalidHeaderUtf8, + AuthorizationError::InvalidEventJson, + AuthorizationError::InvalidEventKind { actual: 1 }, + AuthorizationError::InvalidEventId, + AuthorizationError::InvalidEventSignature, + AuthorizationError::EventSigning, ]; let mut codes = errors .iter() - .map(RadrootsNostrBlossomError::code) + .map(AuthorizationError::code) .collect::<Vec<_>>(); let before = codes.len(); codes.sort_unstable(); diff --git a/crates/nostr/tests/coverage.rs b/crates/nostr/tests/coverage.rs @@ -3,33 +3,28 @@ mod test_fixtures; use std::borrow::Cow; -use nostr::nips::nip04; +use nostr::{Keys as RadrootsNostrKeys, RelayUrl as RadrootsNostrRelayUrl, nips::nip04}; #[cfg(feature = "events")] use radroots_event::post::reply::{AuthoredNip10Reply, Nip10ReplyReference}; -use radroots_nostr::error::RadrootsNostrTagsResolveError; -use radroots_nostr::events::jobs::{ - radroots_nostr_build_event_job_feedback, radroots_nostr_build_event_job_result, -}; -use radroots_nostr::events::post::radroots_nostr_post_events_filter; #[cfg(feature = "events")] -use radroots_nostr::events::reply::radroots_nostr_build_nip10_reply_event; +use radroots_nostr::event::build_nip10_reply as build_nip10_reply_event; +use radroots_nostr::event::{Kind as RadrootsNostrKind, Timestamp as RadrootsNostrTimestamp}; +use radroots_nostr::event::{ + build_job_feedback as build_event_job_feedback, build_job_result as build_event_job_result, + created_at_u32_saturating, event_created_at_u32_saturating, post_filter as post_events_filter, +}; use radroots_nostr::filter::{ - radroots_nostr_filter_kind, radroots_nostr_filter_new_events, radroots_nostr_filter_tag, - radroots_nostr_kind, + for_kind as filter_kind, kind, since_now as filter_new_events, with_tag as filter_tag, }; use radroots_nostr::key::{parse_public_key, public_key_from_nostr, public_key_to_npub}; use radroots_nostr::tag::{ - Tag as RadrootsNostrTag, TagKind as RadrootsNostrTagKind, - TagStandard as RadrootsNostrTagStandard, radroots_nostr_tag_at_value, - radroots_nostr_tag_first_value, radroots_nostr_tag_match_geohash, radroots_nostr_tag_match_l, - radroots_nostr_tag_match_location, radroots_nostr_tag_match_summary, - radroots_nostr_tag_match_title, radroots_nostr_tag_relays_parse, radroots_nostr_tag_slice, - radroots_nostr_tags_match, radroots_nostr_tags_resolve, -}; -use radroots_nostr::util::{created_at_u32_saturating, event_created_at_u32_saturating}; -use radroots_nostr::{ - event::{Kind as RadrootsNostrKind, Timestamp as RadrootsNostrTimestamp}, - types::{RadrootsNostrKeys, RadrootsNostrRelayUrl}, + ResolveError, Tag as RadrootsNostrTag, TagKind as RadrootsNostrTagKind, + TagStandard as RadrootsNostrTagStandard, first_value as tag_first_value, + match_geohash as tag_match_geohash, match_location as tag_match_location, + match_location_coordinate as tag_match_l, match_parts as tags_match, + match_summary as tag_match_summary, match_title as tag_match_title, + relay_urls as tag_relays_parse, resolve as tags_resolve, value_at as tag_at_value, + values_from as tag_slice, }; use test_fixtures::RELAY_PRIMARY_WSS; @@ -71,7 +66,7 @@ fn job_event_builders_are_callable() { .sign_with_keys(&keys) .expect("non-job request"); - let job_result = radroots_nostr_build_event_job_result( + let job_result = build_event_job_result( &job_request, "ok", 1, @@ -83,7 +78,7 @@ fn job_event_builders_are_callable() { .sign_with_keys(&keys) .expect("job result signs through the generic boundary"); - let feedback_ok = radroots_nostr_build_event_job_feedback( + let feedback_ok = build_event_job_feedback( &job_request, "success", Some("extra".to_string()), @@ -94,14 +89,13 @@ fn job_event_builders_are_callable() { .sign_with_keys(&keys) .expect("job feedback signs through the generic boundary"); - let feedback_invalid = - radroots_nostr_build_event_job_feedback(&job_request, "invalid-status", None, None) - .expect("job feedback fallback builder"); + let feedback_invalid = build_event_job_feedback(&job_request, "invalid-status", None, None) + .expect("job feedback fallback builder"); let _ = feedback_invalid .sign_with_keys(&keys) .expect("fallback job feedback signs through the generic boundary"); - let invalid_job_result = radroots_nostr_build_event_job_result( + let invalid_job_result = build_event_job_result( &non_job_request, "ok", 1, @@ -113,8 +107,8 @@ fn job_event_builders_are_callable() { #[test] fn post_helpers_cover_success_and_error_paths() { - let _ = radroots_nostr_post_events_filter(None, None); - let _ = radroots_nostr_post_events_filter(Some(10), Some(1_700_000_000)); + let _ = post_events_filter(None, None); + let _ = post_events_filter(Some(10), Some(1_700_000_000)); #[cfg(feature = "events")] { @@ -132,8 +126,7 @@ fn post_helpers_cover_success_and_error_paths() { .expect("root reference"); let direct = AuthoredNip10Reply::direct("direct reply", root_reference.clone()) .expect("direct reply"); - let direct_builder = - radroots_nostr_build_nip10_reply_event(&direct).expect("direct reply builder"); + let direct_builder = build_nip10_reply_event(&direct).expect("direct reply builder"); let _ = direct_builder .sign_with_keys(&keys) .expect("direct reply signs through the typed boundary"); @@ -142,8 +135,7 @@ fn post_helpers_cover_success_and_error_paths() { .expect("parent reference"); let nested = AuthoredNip10Reply::nested("nested reply", root_reference, parent_reference) .expect("nested reply"); - let nested_builder = - radroots_nostr_build_nip10_reply_event(&nested).expect("nested reply builder"); + let nested_builder = build_nip10_reply_event(&nested).expect("nested reply builder"); let _ = nested_builder .sign_with_keys(&keys) .expect("nested reply signs through the typed boundary"); @@ -164,24 +156,21 @@ fn post_helpers_cover_success_and_error_paths() { #[test] fn filter_helpers_cover_all_paths() { - let filter = radroots_nostr_filter_kind(1); - let filtered = radroots_nostr_filter_tag(filter, "p", vec!["x".to_string()]); + let filter = filter_kind(1); + let filtered = filter_tag(filter, "p", vec!["x".to_string()]); assert!(filtered.is_ok()); - let empty_tag = - radroots_nostr_filter_tag(radroots_nostr_filter_kind(1), "", vec!["x".to_string()]); + let empty_tag = filter_tag(filter_kind(1), "", vec!["x".to_string()]); assert!(empty_tag.is_err()); - let multi_tag = - radroots_nostr_filter_tag(radroots_nostr_filter_kind(1), "pp", vec!["x".to_string()]); + let multi_tag = filter_tag(filter_kind(1), "pp", vec!["x".to_string()]); assert!(multi_tag.is_err()); - let invalid_tag = - radroots_nostr_filter_tag(radroots_nostr_filter_kind(1), "1", vec!["x".to_string()]); + let invalid_tag = filter_tag(filter_kind(1), "1", vec!["x".to_string()]); assert!(invalid_tag.is_err()); - let _ = radroots_nostr_kind(30000); - let _ = radroots_nostr_filter_new_events(radroots_nostr_filter_kind(1)); + let _ = kind(30000); + let _ = filter_new_events(filter_kind(1)); } #[test] @@ -207,50 +196,44 @@ fn tag_helpers_cover_matchers_and_resolve_paths() { RadrootsNostrTagKind::Custom(Cow::Borrowed("x")), vec!["v1".to_string(), "v2".to_string()], ); + assert_eq!(tag_first_value(&custom_tag, "x"), Some("v1".to_string())); + assert_eq!(tag_first_value(&custom_tag, "y"), None); + assert_eq!(tag_at_value(&custom_tag, 0), Some("x".to_string())); + assert_eq!(tag_at_value(&custom_tag, 9), None); assert_eq!( - radroots_nostr_tag_first_value(&custom_tag, "x"), - Some("v1".to_string()) - ); - assert_eq!(radroots_nostr_tag_first_value(&custom_tag, "y"), None); - assert_eq!( - radroots_nostr_tag_at_value(&custom_tag, 0), - Some("x".to_string()) - ); - assert_eq!(radroots_nostr_tag_at_value(&custom_tag, 9), None); - assert_eq!( - radroots_nostr_tag_slice(&custom_tag, 1), + tag_slice(&custom_tag, 1), Some(vec!["v1".to_string(), "v2".to_string()]) ); - assert_eq!(radroots_nostr_tag_slice(&custom_tag, 9), None); - let matched = radroots_nostr_tags_match(&custom_tag).expect("custom match"); + assert_eq!(tag_slice(&custom_tag, 9), None); + let matched = tags_match(&custom_tag).expect("custom match"); assert_eq!(matched.0, "x"); assert_eq!(matched.1, ["v1".to_string(), "v2".to_string()]); let relays_tag = RadrootsNostrTag::from_standardized(RadrootsNostrTagStandard::Relays(vec![ RadrootsNostrRelayUrl::parse(RELAY_PRIMARY_WSS).expect("relay"), ])); - assert!(radroots_nostr_tag_relays_parse(&relays_tag).is_some()); + assert!(tag_relays_parse(&relays_tag).is_some()); let relays_non_match = RadrootsNostrTag::from_standardized(RadrootsNostrTagStandard::Title("x".to_string())); - assert!(radroots_nostr_tag_relays_parse(&relays_non_match).is_none()); - assert!(radroots_nostr_tag_relays_parse(&custom_tag).is_none()); + assert!(tag_relays_parse(&relays_non_match).is_none()); + assert!(tag_relays_parse(&custom_tag).is_none()); let l_tag = RadrootsNostrTag::custom( RadrootsNostrTagKind::Custom(Cow::Borrowed("l")), vec!["12.5".to_string(), "kg".to_string()], ); - assert_eq!(radroots_nostr_tag_match_l(&l_tag), Some(("kg", 12.5))); + assert_eq!(tag_match_l(&l_tag), Some(("kg", 12.5))); let bad_l_tag = RadrootsNostrTag::custom( RadrootsNostrTagKind::Custom(Cow::Borrowed("l")), vec!["abc".to_string(), "kg".to_string()], ); - assert_eq!(radroots_nostr_tag_match_l(&bad_l_tag), None); - assert_eq!(radroots_nostr_tag_match_l(&custom_tag), None); + assert_eq!(tag_match_l(&bad_l_tag), None); + assert_eq!(tag_match_l(&custom_tag), None); let short_l_tag = RadrootsNostrTag::custom( RadrootsNostrTagKind::Custom(Cow::Borrowed("l")), vec!["12.5".to_string()], ); - assert_eq!(radroots_nostr_tag_match_l(&short_l_tag), None); + assert_eq!(tag_match_l(&short_l_tag), None); let location_tag = RadrootsNostrTag::custom( RadrootsNostrTagKind::Custom(Cow::Borrowed("location")), @@ -261,7 +244,7 @@ fn tag_helpers_cover_matchers_and_resolve_paths() { ], ); assert_eq!( - radroots_nostr_tag_match_location(&location_tag), + tag_match_location(&location_tag), Some(("se", "stockholm", "city")) ); let location_non_match = RadrootsNostrTag::custom( @@ -272,36 +255,27 @@ fn tag_helpers_cover_matchers_and_resolve_paths() { "city".to_string(), ], ); - assert_eq!(radroots_nostr_tag_match_location(&location_non_match), None); - assert_eq!(radroots_nostr_tag_match_location(&custom_tag), None); + assert_eq!(tag_match_location(&location_non_match), None); + assert_eq!(tag_match_location(&custom_tag), None); let geohash_tag = RadrootsNostrTag::from_standardized(RadrootsNostrTagStandard::Geohash("u4pr".to_string())); - assert_eq!( - radroots_nostr_tag_match_geohash(&geohash_tag), - Some("u4pr".to_string()) - ); + assert_eq!(tag_match_geohash(&geohash_tag), Some("u4pr".to_string())); let title_tag = RadrootsNostrTag::from_standardized(RadrootsNostrTagStandard::Title("title".to_string())); - assert_eq!(radroots_nostr_tag_match_geohash(&title_tag), None); - assert_eq!(radroots_nostr_tag_match_geohash(&custom_tag), None); + assert_eq!(tag_match_geohash(&title_tag), None); + assert_eq!(tag_match_geohash(&custom_tag), None); - assert_eq!( - radroots_nostr_tag_match_title(&title_tag), - Some("title".to_string()) - ); + assert_eq!(tag_match_title(&title_tag), Some("title".to_string())); let summary_tag = RadrootsNostrTag::from_standardized(RadrootsNostrTagStandard::Summary( "summary".to_string(), )); - assert_eq!(radroots_nostr_tag_match_title(&summary_tag), None); - assert_eq!(radroots_nostr_tag_match_title(&custom_tag), None); + assert_eq!(tag_match_title(&summary_tag), None); + assert_eq!(tag_match_title(&custom_tag), None); - assert_eq!( - radroots_nostr_tag_match_summary(&summary_tag), - Some("summary".to_string()) - ); - assert_eq!(radroots_nostr_tag_match_summary(&geohash_tag), None); - assert_eq!(radroots_nostr_tag_match_summary(&custom_tag), None); + assert_eq!(tag_match_summary(&summary_tag), Some("summary".to_string())); + assert_eq!(tag_match_summary(&geohash_tag), None); + assert_eq!(tag_match_summary(&custom_tag), None); let clear_event = text_event_with_tags( &keys, @@ -310,7 +284,7 @@ fn tag_helpers_cover_matchers_and_resolve_paths() { vec!["x".to_string(), "v".to_string()], )], ); - let resolved = radroots_nostr_tags_resolve(&clear_event, &keys).expect("clear tags"); + let resolved = tags_resolve(&clear_event, &keys).expect("clear tags"); assert_eq!(resolved.len(), 1); let encrypted_missing_p = text_event_with_tags( @@ -320,19 +294,13 @@ fn tag_helpers_cover_matchers_and_resolve_paths() { vec!["encrypted".to_string()], )], ); - let missing_p = radroots_nostr_tags_resolve(&encrypted_missing_p, &keys); - assert!(matches!( - missing_p, - Err(RadrootsNostrTagsResolveError::MissingPTag(_)) - )); + let missing_p = tags_resolve(&encrypted_missing_p, &keys); + assert!(matches!(missing_p, Err(ResolveError::MissingPTag(_)))); let sender = make_keys(); let encrypted_invalid_p = encrypted_event_with_p_tag(&sender, "cipher", "not-a-pubkey"); - let invalid_p = radroots_nostr_tags_resolve(&encrypted_invalid_p, &keys); - assert!(matches!( - invalid_p, - Err(RadrootsNostrTagsResolveError::MissingPTag(_)) - )); + let invalid_p = tags_resolve(&encrypted_invalid_p, &keys); + assert!(matches!(invalid_p, Err(ResolveError::MissingPTag(_)))); let encrypted_empty_p_content = nostr::EventBuilder::new(RadrootsNostrKind::TextNote, "cipher") .tags(vec![ @@ -344,45 +312,32 @@ fn tag_helpers_cover_matchers_and_resolve_paths() { ]) .sign_with_keys(&sender) .expect("sign encrypted event with empty p tag"); - let empty_p_content = radroots_nostr_tags_resolve(&encrypted_empty_p_content, &keys); - assert!(matches!( - empty_p_content, - Err(RadrootsNostrTagsResolveError::MissingPTag(_)) - )); + let empty_p_content = tags_resolve(&encrypted_empty_p_content, &keys); + assert!(matches!(empty_p_content, Err(ResolveError::MissingPTag(_)))); let encrypted_not_recipient = encrypted_event_with_p_tag(&sender, "cipher", &other.public_key().to_hex()); - let not_recipient = radroots_nostr_tags_resolve(&encrypted_not_recipient, &keys); - assert!(matches!( - not_recipient, - Err(RadrootsNostrTagsResolveError::NotRecipient) - )); + let not_recipient = tags_resolve(&encrypted_not_recipient, &keys); + assert!(matches!(not_recipient, Err(ResolveError::NotRecipient))); let encrypted_bad_cipher = encrypted_event_with_p_tag(&sender, "not-ciphertext", &keys.public_key().to_hex()); - let bad_cipher = radroots_nostr_tags_resolve(&encrypted_bad_cipher, &keys); - assert!(matches!( - bad_cipher, - Err(RadrootsNostrTagsResolveError::DecryptionError(_)) - )); + let bad_cipher = tags_resolve(&encrypted_bad_cipher, &keys); + assert!(matches!(bad_cipher, Err(ResolveError::DecryptionError(_)))); let encrypted_cleartext = nip04::encrypt(sender.secret_key(), &keys.public_key(), "[]") .expect("encrypt cleartext tags"); let encrypted_ok = encrypted_event_with_p_tag(&sender, encrypted_cleartext, &keys.public_key().to_hex()); - let resolved_encrypted = - radroots_nostr_tags_resolve(&encrypted_ok, &keys).expect("resolve tags"); + let resolved_encrypted = tags_resolve(&encrypted_ok, &keys).expect("resolve tags"); assert!(resolved_encrypted.is_empty()); let encrypted_bad_json = nip04::encrypt(sender.secret_key(), &keys.public_key(), "not-json") .expect("encrypt invalid tags payload"); let encrypted_bad_json_event = encrypted_event_with_p_tag(&sender, encrypted_bad_json, &keys.public_key().to_hex()); - let bad_json = radroots_nostr_tags_resolve(&encrypted_bad_json_event, &keys); - assert!(matches!( - bad_json, - Err(RadrootsNostrTagsResolveError::ParseError(_)) - )); + let bad_json = tags_resolve(&encrypted_bad_json_event, &keys); + assert!(matches!(bad_json, Err(ResolveError::ParseError(_)))); } #[test] diff --git a/crates/nostr/tests/food_availability_profile.rs b/crates/nostr/tests/food_availability_profile.rs @@ -1,3 +1,4 @@ +use nostr::{Keys as RadrootsNostrKeys, SecretKey as RadrootsNostrSecretKey}; use radroots_blossom::{BlobDescriptor, BlobUrl, MediaType, Sha256}; use radroots_event::food::availability::{ FoodAvailabilityDetails, FoodAvailabilityDetailsParts, FoodAvailabilityImage, @@ -8,15 +9,13 @@ use radroots_event::media::AuthoredImage; use radroots_event_codec::admission::food_availability::{ RadrootsFoodAvailabilityAdmissionOutcome, verify_and_admit_food_availability_event, }; -use radroots_nostr::error::RadrootsNostrError; +use radroots_nostr::Error; +use radroots_nostr::event::GenericBuilder; use radroots_nostr::event::Kind as RadrootsNostrKind; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; -use radroots_nostr::event::radroots_event_from_nostr; -use radroots_nostr::events::food_availability::radroots_nostr_build_food_availability_event; +use radroots_nostr::event::build_food_availability as build_food_availability_event; +use radroots_nostr::event::from_nostr; use radroots_nostr::tag::Tag as RadrootsNostrTag; -use radroots_nostr::types::RadrootsNostrGenericEventBuilder; -use radroots_nostr::types::RadrootsNostrKeys; -use radroots_nostr::types::RadrootsNostrSecretKey; use radroots_test_fixtures::FIXTURE_ALICE_SECRET_KEY_HEX; const CREATED_AT: u64 = 1_784_347_200; @@ -25,7 +24,7 @@ const CREATED_AT: u64 = 1_784_347_200; fn typed_food_builder_signs_the_exact_strict_profile() { let keys = fixture_keys(); let created_at = RadrootsNostrTimestamp::from_secs(CREATED_AT); - let event = radroots_nostr_build_food_availability_event(&details(), created_at) + let event = build_food_availability_event(&details(), created_at) .expect("typed FoodAvailability builder") .sign_with_keys(&keys) .expect("signed FoodAvailability event"); @@ -58,7 +57,7 @@ fn typed_food_builder_signs_the_exact_strict_profile() { ); event.verify().expect("valid NIP-01 event"); - let envelope = radroots_event_from_nostr(&event).expect("Radroots event adapter"); + let envelope = from_nostr(&event).expect("Radroots event adapter"); assert!(matches!( verify_and_admit_food_availability_event(envelope) .expect("verified FoodAvailability admission"), @@ -68,24 +67,19 @@ fn typed_food_builder_signs_the_exact_strict_profile() { #[test] fn typed_food_builder_keeps_timestamp_validation_inside_construction() { - let error = radroots_nostr_build_food_availability_event( - &details(), - RadrootsNostrTimestamp::from_secs(1_784_347_000), - ) - .err() - .expect("created_at before published_at must fail"); + let error = + build_food_availability_event(&details(), RadrootsNostrTimestamp::from_secs(1_784_347_000)) + .err() + .expect("created_at before published_at must fail"); - assert!(matches!( - error, - RadrootsNostrError::FoodAvailabilityEncode(_) - )); + assert!(matches!(error, Error::FoodAvailabilityEncode(_))); } #[test] fn typed_food_builder_preserves_a_byte_verified_blossom_image_tuple() { let image = blossom_image(); let image_url = image.url().to_owned(); - let event = radroots_nostr_build_food_availability_event( + let event = build_food_availability_event( &details_with_images(vec![image]), RadrootsNostrTimestamp::from_secs(CREATED_AT), ) @@ -125,10 +119,10 @@ fn generic_builder_reserves_focused_and_ambiguous_listing_profiles() { ], ] { assert!(matches!( - RadrootsNostrGenericEventBuilder::new(kind, "reserved") + GenericBuilder::new(kind, "reserved") .tags(tags) .sign_with_keys(&keys), - Err(RadrootsNostrError::TypedAuthoringRequired { kind: 30_402 }) + Err(Error::TypedAuthoringRequired { kind: 30_402 }) )); } } @@ -148,7 +142,7 @@ fn generic_builder_retains_marker_free_and_operational_nip99_compatibility() { RadrootsNostrTag::parse(["radroots:primary_bin", "bin-1"]).expect("operational marker"), ], ] { - let event = RadrootsNostrGenericEventBuilder::new(kind, "compatible") + let event = GenericBuilder::new(kind, "compatible") .tags(tags) .custom_created_at(RadrootsNostrTimestamp::from_secs(CREATED_AT)) .sign_with_keys(&keys) diff --git a/crates/nostr/tests/generic_builder_boundary.rs b/crates/nostr/tests/generic_builder_boundary.rs @@ -30,15 +30,15 @@ fn public_source_does_not_expose_the_upstream_event_builder() { } for forbidden in [ - "impl Deref for RadrootsNostrGenericEventBuilder", - "impl AsRef<nostr::EventBuilder> for RadrootsNostrGenericEventBuilder", - "impl From<RadrootsNostrGenericEventBuilder> for nostr::EventBuilder", - "impl Into<nostr::EventBuilder> for RadrootsNostrGenericEventBuilder", - "impl Deref for RadrootsNostrExternalSigningRequest", - "impl AsRef<nostr::UnsignedEvent> for RadrootsNostrExternalSigningRequest", - "impl From<RadrootsNostrExternalSigningRequest> for nostr::UnsignedEvent", - "impl Into<nostr::UnsignedEvent> for RadrootsNostrExternalSigningRequest", - "impl Deserialize for RadrootsNostrExternalSigningRequest", + "impl Deref for GenericBuilder", + "impl AsRef<nostr::EventBuilder> for GenericBuilder", + "impl From<GenericBuilder> for nostr::EventBuilder", + "impl Into<nostr::EventBuilder> for GenericBuilder", + "impl Deref for ExternalSigningRequest", + "impl AsRef<nostr::UnsignedEvent> for ExternalSigningRequest", + "impl From<ExternalSigningRequest> for nostr::UnsignedEvent", + "impl Into<nostr::UnsignedEvent> for ExternalSigningRequest", + "impl Deserialize for ExternalSigningRequest", "fn into_unsigned_event", "fn as_unsigned_event", "fn unsigned_event_mut", diff --git a/crates/nostr/tests/nip09_deletion_request_profile.rs b/crates/nostr/tests/nip09_deletion_request_profile.rs @@ -1,3 +1,4 @@ +use nostr::{Keys as RadrootsNostrKeys, SecretKey as RadrootsNostrSecretKey}; use radroots_event::{ envelope::kind::KIND_DELETION_REQUEST, post::deletion::{ @@ -5,14 +6,13 @@ use radroots_event::{ }, }; use radroots_event_codec::admission::deletion::verify_and_admit_nip09_deletion_request_event; -use radroots_nostr::error::RadrootsNostrError; +use radroots_nostr::Error; use radroots_nostr::event::Kind as RadrootsNostrKind; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; -use radroots_nostr::event::radroots_event_from_nostr; -use radroots_nostr::events::deletion::radroots_nostr_build_nip09_deletion_request_event; -use radroots_nostr::types::RadrootsNostrGenericEventBuilder; -use radroots_nostr::types::RadrootsNostrKeys; -use radroots_nostr::types::RadrootsNostrSecretKey; +use radroots_nostr::event::from_nostr; +use radroots_nostr::event::{ + GenericBuilder, build_nip09_deletion_request as build_nip09_deletion_request_event, +}; use radroots_test_fixtures::{FIXTURE_ALICE_SECRET_KEY_HEX, FIXTURE_BOB_PUBLIC_KEY_HEX}; const CREATED_AT: u64 = 1_784_347_200; @@ -33,7 +33,7 @@ fn typed_nip09_deletion_request_signs_exact_tags_and_admits() { tag(&["k", "30402"]), ]; - let event = radroots_nostr_build_nip09_deletion_request_event(&request) + let event = build_nip09_deletion_request_event(&request) .expect("typed NIP-09 builder") .custom_created_at(created_at) .sign_with_keys(&fixture_keys()) @@ -46,7 +46,7 @@ fn typed_nip09_deletion_request_signs_exact_tags_and_admits() { event.verify().expect("valid deletion-request signature"); let admitted = verify_and_admit_nip09_deletion_request_event( - radroots_event_from_nostr(&event).expect("deletion-request event adapter"), + from_nostr(&event).expect("deletion-request event adapter"), ) .expect("deletion-request admission"); assert_eq!( @@ -70,7 +70,7 @@ fn typed_nip09_deletion_request_signs_exact_tags_and_admits() { #[test] fn generic_kind_five_builder_cannot_bypass_typed_deletion_authoring() { - let error = RadrootsNostrGenericEventBuilder::new( + let error = GenericBuilder::new( RadrootsNostrKind::Custom(KIND_DELETION_REQUEST as u16), "Raw deletion request", ) @@ -79,7 +79,7 @@ fn generic_kind_five_builder_cannot_bypass_typed_deletion_authoring() { assert!(matches!( error, - RadrootsNostrError::TypedAuthoringRequired { kind } + Error::TypedAuthoringRequired { kind } if kind == KIND_DELETION_REQUEST as u16 )); } diff --git a/crates/nostr/tests/nip10_reply_profile.rs b/crates/nostr/tests/nip10_reply_profile.rs @@ -1,3 +1,4 @@ +use nostr::{Keys as RadrootsNostrKeys, SecretKey as RadrootsNostrSecretKey}; use radroots_event::post::reply::{AuthoredNip10Reply, Nip10ReplyReference}; use radroots_event_codec::{ admission::{ @@ -6,15 +7,13 @@ use radroots_event_codec::{ }, decode::reply::RadrootsNip10ReplyStyle, }; -use radroots_nostr::error::RadrootsNostrError; +use radroots_nostr::Error; +use radroots_nostr::event::GenericBuilder; use radroots_nostr::event::Kind as RadrootsNostrKind; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; -use radroots_nostr::event::radroots_event_from_nostr; -use radroots_nostr::events::reply::radroots_nostr_build_nip10_reply_event; +use radroots_nostr::event::build_nip10_reply as build_nip10_reply_event; +use radroots_nostr::event::from_nostr; use radroots_nostr::tag::Tag as RadrootsNostrTag; -use radroots_nostr::types::RadrootsNostrGenericEventBuilder; -use radroots_nostr::types::RadrootsNostrKeys; -use radroots_nostr::types::RadrootsNostrSecretKey; use radroots_test_fixtures::{ FIXTURE_ALICE_SECRET_KEY_HEX, FIXTURE_BOB_PUBLIC_KEY_HEX, FIXTURE_CAROL_PUBLIC_KEY_HEX, RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS, @@ -36,7 +35,7 @@ fn typed_nip10_reply_builders_sign_exact_marked_direct_and_nested_profiles() { let direct = AuthoredNip10Reply::direct("Direct reply", root.clone()).expect("authored direct reply"); - let direct_event = radroots_nostr_build_nip10_reply_event(&direct) + let direct_event = build_nip10_reply_event(&direct) .expect("typed direct Reply builder") .custom_created_at(created_at) .sign_with_keys(&keys) @@ -60,7 +59,7 @@ fn typed_nip10_reply_builders_sign_exact_marked_direct_and_nested_profiles() { ); let nested = AuthoredNip10Reply::nested("Nested reply", root, parent).expect("authored nested reply"); - let nested_event = radroots_nostr_build_nip10_reply_event(&nested) + let nested_event = build_nip10_reply_event(&nested) .expect("typed nested Reply builder") .custom_created_at(created_at) .sign_with_keys(&keys) @@ -77,7 +76,7 @@ fn typed_nip10_reply_builders_sign_exact_marked_direct_and_nested_profiles() { ); nested_event.verify().expect("valid nested Reply signature"); let admitted = verify_and_admit_nip10_reply_event( - radroots_event_from_nostr(&nested_event).expect("nested Reply adapter"), + from_nostr(&nested_event).expect("nested Reply adapter"), ) .expect("nested Reply admission"); assert!(!admitted.projection().is_direct()); @@ -103,12 +102,12 @@ fn signed_nip10_reply_is_thread_excluded_before_semantic_reply_admission() { ), ) .expect("authored direct reply"); - let event = radroots_nostr_build_nip10_reply_event(&reply) + let event = build_nip10_reply_event(&reply) .expect("typed Reply builder") .custom_created_at(RadrootsNostrTimestamp::from_secs(CREATED_AT)) .sign_with_keys(&fixture_keys()) .expect("signed Reply"); - let envelope = radroots_event_from_nostr(&event).expect("Radroots event adapter"); + let envelope = from_nostr(&event).expect("Radroots event adapter"); let candidate = match verify_and_admit_post_event(envelope).expect("post admission") { RadrootsPostAdmissionOutcome::ThreadExcluded(candidate) => candidate, @@ -143,7 +142,7 @@ fn verified_legacy_positional_nip10_reply_remains_tolerated_inbound() { .custom_created_at(RadrootsNostrTimestamp::from_secs(CREATED_AT)) .sign_with_keys(&keys) .expect("signed inbound fixture"); - let envelope = radroots_event_from_nostr(&event).expect("Radroots event adapter"); + let envelope = from_nostr(&event).expect("Radroots event adapter"); let admitted = verify_and_admit_nip10_reply_event(envelope).expect("legacy positional Reply admission"); @@ -161,19 +160,16 @@ fn verified_legacy_positional_nip10_reply_remains_tolerated_inbound() { #[test] fn generic_kind_one_builder_cannot_bypass_typed_nip10_reply_authoring() { let keys = fixture_keys(); - let marked_reply = RadrootsNostrGenericEventBuilder::text_note("Raw marked reply").tags([ + let marked_reply = GenericBuilder::text_note("Raw marked reply").tags([ RadrootsNostrTag::parse(["e", ROOT_EVENT_ID, RELAY_PRIMARY_WSS, "root"]) .expect("root reference"), RadrootsNostrTag::parse(["p", FIXTURE_BOB_PUBLIC_KEY_HEX]).expect("root author reference"), ]); - for builder in [ - RadrootsNostrGenericEventBuilder::text_note("Raw root"), - marked_reply, - ] { + for builder in [GenericBuilder::text_note("Raw root"), marked_reply] { assert!(matches!( builder.sign_with_keys(&keys), - Err(RadrootsNostrError::TypedAuthoringRequired { kind }) + Err(Error::TypedAuthoringRequired { kind }) if kind == RadrootsNostrKind::TextNote.as_u16() )); } diff --git a/crates/nostr/tests/nip17_conformance.rs b/crates/nostr/tests/nip17_conformance.rs @@ -4,8 +4,7 @@ use nostr::{Keys, SecretKey}; use radroots_event::social::message::{Message, MessageRecipient}; use radroots_event::social::message_file::{MessageFile, MessageFileDimensions}; use radroots_nostr::nip17::{ - RadrootsNip17Rumor, RadrootsNip17WrapOptions, radroots_nostr_unwrap_gift_wrap, - radroots_nostr_wrap_message, radroots_nostr_wrap_message_file, + Rumor, WrapOptions, unwrap_gift_wrap, wrap_message, wrap_message_file, }; use radroots_test_fixtures::{ FIXTURE_ALICE_PUBLIC_KEY_HEX, FIXTURE_ALICE_SECRET_KEY_HEX, FIXTURE_BOB_PUBLIC_KEY_HEX, @@ -96,12 +95,12 @@ async fn execute_message_roundtrip(vector: &Vector) { reply_to: None, subject: Some(input_str(vector, "subject").to_owned()), }; - let events = radroots_nostr_wrap_message(&sender, &message, options(vector)) + let events = wrap_message(&sender, &message, options(vector)) .await .unwrap_or_else(|error| panic!("{} failed: {error}", vector.id)); assert_eq!(events.len(), expected_u64(vector, "event_count") as usize); - let rumor = radroots_nostr_unwrap_gift_wrap(&receiver, &events[0]) + let rumor = unwrap_gift_wrap(&receiver, &events[0]) .await .unwrap_or_else(|error| panic!("{} failed: {error}", vector.id)); let rendered = format!("{rumor:?}"); @@ -113,7 +112,7 @@ async fn execute_message_roundtrip(vector: &Vector) { assert!(!rendered.contains(private_value), "{}", vector.id); } match rumor { - RadrootsNip17Rumor::Message(metadata) => { + Rumor::Message(metadata) => { assert_eq!( metadata.author, expected_str(vector, "author"), @@ -179,12 +178,12 @@ async fn execute_message_file_roundtrip(vector: &Vector) { thumb: None, fallbacks: Vec::new(), }; - let events = radroots_nostr_wrap_message_file(&sender, &message, options(vector)) + let events = wrap_message_file(&sender, &message, options(vector)) .await .unwrap_or_else(|error| panic!("{} failed: {error}", vector.id)); assert_eq!(events.len(), expected_u64(vector, "event_count") as usize); - let rumor = radroots_nostr_unwrap_gift_wrap(&receiver, &events[0]) + let rumor = unwrap_gift_wrap(&receiver, &events[0]) .await .unwrap_or_else(|error| panic!("{} failed: {error}", vector.id)); let rendered = format!("{rumor:?}"); @@ -199,7 +198,7 @@ async fn execute_message_file_roundtrip(vector: &Vector) { assert!(!rendered.contains(private_value), "{}", vector.id); } match rumor { - RadrootsNip17Rumor::MessageFile(metadata) => { + Rumor::MessageFile(metadata) => { assert_eq!( metadata.author, expected_str(vector, "author"), @@ -262,7 +261,7 @@ async fn execute_invalid_recipient(vector: &Vector) { reply_to: None, subject: None, }; - let error = radroots_nostr_wrap_message(&sender, &message, options(vector)) + let error = wrap_message(&sender, &message, options(vector)) .await .expect_err("invalid recipient vector must fail"); assert_eq!(error.code(), expected_str(vector, "error"), "{}", vector.id); @@ -271,12 +270,10 @@ async fn execute_invalid_recipient(vector: &Vector) { assert!(!rendered.contains(&message.content), "{}", vector.id); } -fn options(vector: &Vector) -> RadrootsNip17WrapOptions { - RadrootsNip17WrapOptions { - include_sender: false, - rumor_created_at: Some(input_u64(vector, "created_at")), - gift_wrap_tags: Vec::new(), - } +fn options(vector: &Vector) -> WrapOptions { + WrapOptions::default() + .include_sender(false) + .with_rumor_created_at(input_u64(vector, "created_at")) } fn sender_keys() -> Keys { diff --git a/crates/nostr/tests/nip22_comment_profile.rs b/crates/nostr/tests/nip22_comment_profile.rs @@ -1,3 +1,4 @@ +use nostr::{Keys as RadrootsNostrKeys, SecretKey as RadrootsNostrSecretKey}; use radroots_event::{ envelope::kind::{ KIND_CALENDAR_DATE_EVENT, KIND_CALENDAR_TIME_EVENT, KIND_CLASSIFIED_LISTING, KIND_COMMENT, @@ -11,14 +12,11 @@ use radroots_event_codec::{ admission::comment::verify_and_admit_nip22_comment_event, decode::comment::RadrootsInboundNip22CommentPosition, }; -use radroots_nostr::error::RadrootsNostrError; +use radroots_nostr::Error; use radroots_nostr::event::Kind as RadrootsNostrKind; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; -use radroots_nostr::event::radroots_event_from_nostr; -use radroots_nostr::events::comment::radroots_nostr_build_nip22_comment_event; -use radroots_nostr::types::RadrootsNostrGenericEventBuilder; -use radroots_nostr::types::RadrootsNostrKeys; -use radroots_nostr::types::RadrootsNostrSecretKey; +use radroots_nostr::event::from_nostr; +use radroots_nostr::event::{GenericBuilder, build_nip22_comment as build_nip22_comment_event}; use radroots_test_fixtures::{ FIXTURE_ALICE_SECRET_KEY_HEX, FIXTURE_BOB_PUBLIC_KEY_HEX, FIXTURE_CAROL_PUBLIC_KEY_HEX, RELAY_PRIMARY_WSS, RELAY_SECONDARY_WSS, @@ -136,7 +134,7 @@ fn typed_nip22_comment_builders_sign_and_admit_all_exact_shapes() { (nested_event, nested_event_tags, "nested"), (nested_address, nested_address_tags, "nested"), ] { - let event = radroots_nostr_build_nip22_comment_event(&comment) + let event = build_nip22_comment_event(&comment) .expect("typed Comment builder") .custom_created_at(created_at) .sign_with_keys(&keys) @@ -147,7 +145,7 @@ fn typed_nip22_comment_builders_sign_and_admit_all_exact_shapes() { event.verify().expect("valid Comment signature"); let admitted = verify_and_admit_nip22_comment_event( - radroots_event_from_nostr(&event).expect("Comment event adapter"), + from_nostr(&event).expect("Comment event adapter"), ) .expect("Comment admission"); assert_eq!( @@ -160,13 +158,13 @@ fn typed_nip22_comment_builders_sign_and_admit_all_exact_shapes() { #[test] fn generic_kind_1111_builder_cannot_bypass_typed_comment_authoring() { let kind = RadrootsNostrKind::Custom(KIND_COMMENT as u16); - let error = RadrootsNostrGenericEventBuilder::new(kind, "Raw Comment") + let error = GenericBuilder::new(kind, "Raw Comment") .sign_with_keys(&fixture_keys()) .expect_err("generic kind 1111 must be reserved"); assert!(matches!( error, - RadrootsNostrError::TypedAuthoringRequired { kind: actual } + Error::TypedAuthoringRequired { kind: actual } if actual == KIND_COMMENT as u16 )); } diff --git a/crates/nostr/tests/package_boundary.rs b/crates/nostr/tests/package_boundary.rs @@ -22,6 +22,8 @@ const README: &str = include_str!("../README.md"); const SIGNING_MODULE: &str = include_str!("../src/signing.rs"); const TAG_MODULE: &str = include_str!("../src/tag.rs"); const TYPES_MODULE: &str = include_str!("../src/types.rs"); +const COMPATIBILITY: &str = include_str!("../COMPATIBILITY.md"); +const PUBLIC_API: &str = include_str!("../../../docs/api/radroots_nostr.txt"); const IDENTITY_MANIFEST: &str = include_str!("../../identity/Cargo.toml"); const IDENTITY_KEY_MODULE: &str = include_str!("../../identity/src/key.rs"); const TRANSPORT_MANIFEST: &str = include_str!("../../transport_nostr/Cargo.toml"); @@ -102,12 +104,11 @@ fn manifest_has_final_identity_features_and_radroots_dependencies() { } let features = table_keys(MANIFEST, "[features]"); - for required in ["default", "std", "events", "signing", "nip17", "blossom"] { - assert!( - features.contains(required), - "manifest is missing supported feature `{required}`" - ); - } + assert_eq!( + features, + BTreeSet::from(["blossom", "default", "events", "nip17", "signing", "std"]), + "manifest feature vocabulary must match the Release V1 charter" + ); for feature in features { let declaration = table_value(MANIFEST, "[features]", feature) .unwrap_or_else(|| panic!("missing feature declaration `{feature}`")); @@ -145,13 +146,29 @@ fn crate_root_establishes_the_final_public_module_skeleton() { .collect::<Vec<_>>(); assert_eq!( root_reexports, - ["pub use error::RadrootsNostrError as Error;"], + ["pub use error::Error;"], "the crate root must re-export only the canonical Error alias" ); assert!( !ROOT.contains("pub mod prelude"), "lower-level Nostr crate must not publish a broad prelude" ); + for retired in [ + "codec_adapters", + "draft_signing", + "error", + "event_adapters", + "event_verify", + "events", + "job_adapter", + "types", + "util", + ] { + assert!( + !ROOT.contains(&format!("pub mod {retired};")), + "superseded module remains public: `{retired}`" + ); + } } #[test] @@ -375,7 +392,7 @@ fn local_signer_consumes_only_the_opaque_secret_boundary() { fn focused_nip_and_blossom_features_own_no_network_operations() { for required in [ "blossom = [\"std\", \"dep:base64\", \"dep:radroots_blossom\"]", - "nip17 = [\"std\", \"codec\", \"nostr/nip44\", \"nostr/nip59\"]", + "nip17 = [\"events\", \"nostr/nip44\", \"nostr/nip59\"]", ] { assert!( MANIFEST.contains(required), @@ -383,9 +400,9 @@ fn focused_nip_and_blossom_features_own_no_network_operations() { ); } for required in [ - "pub async fn radroots_nostr_wrap_message<T>(", - "pub async fn radroots_nostr_wrap_message_file<T>(", - "pub async fn radroots_nostr_unwrap_gift_wrap<T>(", + "pub async fn wrap_message<T>(", + "pub async fn wrap_message_file<T>(", + "pub async fn unwrap_gift_wrap<T>(", "pub const fn code(&self) -> &'static str", ] { assert!( @@ -394,9 +411,9 @@ fn focused_nip_and_blossom_features_own_no_network_operations() { ); } for required in [ - "pub fn radroots_nostr_sign_blossom_authorization(", - "pub fn radroots_nostr_encode_blossom_authorization_header(", - "pub fn radroots_nostr_decode_verify_blossom_authorization_header(", + "pub fn sign_authorization(", + "pub fn encode_authorization_header(", + "pub fn decode_verify_authorization_header(", ] { assert!( BLOSSOM_MODULE.contains(required), @@ -495,9 +512,16 @@ fn workspace_consumers_do_not_use_superseded_nostr_alias_paths() { let source = fs::read_to_string(&source_path) .unwrap_or_else(|error| panic!("failed to read {}: {error}", source_path.display())); for forbidden in [ + "radroots_nostr::codec_adapters::", + "radroots_nostr::draft_signing::", "radroots_nostr::error::", + "radroots_nostr::event_adapters::", + "radroots_nostr::event_verify::", + "radroots_nostr::events::", + "radroots_nostr::job_adapter::", "radroots_nostr::prelude", "radroots_nostr::types::", + "radroots_nostr::util::", ] { assert!( !source.contains(forbidden), @@ -508,6 +532,62 @@ fn workspace_consumers_do_not_use_superseded_nostr_alias_paths() { } } +#[test] +fn superseded_surface_retirement_is_explicit_and_release_bounded() { + assert!(!MANIFEST.contains("codec = []")); + for forbidden in ["pub fn radroots_nostr_", "pub async fn radroots_nostr_"] { + for source_path in rust_sources(&PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src")) { + let source = fs::read_to_string(&source_path).unwrap_or_else(|error| { + panic!("failed to read {}: {error}", source_path.display()) + }); + assert!( + !source.contains(forbidden), + "{} retains prefixed public item `{forbidden}`", + source_path.display() + ); + } + } + for required in [ + "publish = false", + "outside the authorized `oss/lib` and `oss/sdk` crate-surface edit boundary", + "no compatibility path was restored", + "Step 313 is the exact final pre-release audit", + ] { + let authority = if required == "publish = false" { + MANIFEST + } else { + COMPATIBILITY + }; + assert!( + authority.contains(required), + "retirement contract is missing `{required}`" + ); + } + + let public_modules = PUBLIC_API + .lines() + .filter_map(|line| line.strip_prefix("pub mod radroots_nostr::")) + .collect::<BTreeSet<_>>(); + assert_eq!( + public_modules, + BTreeSet::from([ + "blossom", "event", "filter", "key", "nip17", "signing", "tag" + ]), + "reviewed API baseline must expose only chartered modules" + ); + for forbidden in [ + "::RadrootsNostr", + "::radroots_nostr_", + "pub radroots_nostr::event::ApplicationHandlerSpec::", + "pub radroots_nostr::nip17::WrapOptions::", + ] { + assert!( + !PUBLIC_API.contains(forbidden), + "reviewed API baseline retains forbidden surface `{forbidden}`" + ); + } +} + fn rust_sources(root: &Path) -> Vec<PathBuf> { let mut pending = vec![root.to_path_buf()]; let mut sources = Vec::new(); diff --git a/crates/nostr/tests/post_profile.rs b/crates/nostr/tests/post_profile.rs @@ -1,6 +1,7 @@ #[path = "../src/test_fixtures.rs"] mod test_fixtures; +use nostr::{Keys as RadrootsNostrKeys, SecretKey as RadrootsNostrSecretKey}; use radroots_blossom::{BlobDescriptor, BlobUrl, MediaType, Sha256}; use radroots_event::{ media::AuthoredImage, @@ -8,13 +9,9 @@ use radroots_event::{ AuthoredAsk, AuthoredPhotoUpdate, AuthoredPostImage, AuthoredUpdate, PostImageDimensions, }, }; -use radroots_nostr::{ - event::Timestamp as RadrootsNostrTimestamp, - events::post::{ - radroots_nostr_build_ask_event, radroots_nostr_build_photo_update_event, - radroots_nostr_build_update_event, - }, - types::{RadrootsNostrKeys, RadrootsNostrSecretKey}, +use radroots_nostr::event::{ + Timestamp as RadrootsNostrTimestamp, build_ask as build_ask_event, + build_photo_update as build_photo_update_event, build_update as build_update_event, }; #[test] @@ -24,7 +21,7 @@ fn typed_post_builders_preserve_strict_wire_profiles() { ); let created_at = RadrootsNostrTimestamp::from_secs(1_784_347_200); let update = AuthoredUpdate::new("Farm update").unwrap(); - let event = radroots_nostr_build_update_event(&update) + let event = build_update_event(&update) .unwrap() .custom_created_at(created_at) .sign_with_keys(&keys) @@ -37,7 +34,7 @@ fn typed_post_builders_preserve_strict_wire_profiles() { let image = authored_image(); let photo = AuthoredPhotoUpdate::new(format!("Harvest {}", image.url()), vec![image.clone()]).unwrap(); - let event = radroots_nostr_build_photo_update_event(&photo) + let event = build_photo_update_event(&photo) .unwrap() .custom_created_at(created_at) .sign_with_keys(&keys) @@ -47,7 +44,7 @@ fn typed_post_builders_preserve_strict_wire_profiles() { assert!(event.verify().is_ok()); let ask = AuthoredAsk::new(format!("Is this ready? {}", image.url()), vec![image]).unwrap(); - let event = radroots_nostr_build_ask_event(&ask) + let event = build_ask_event(&ask) .unwrap() .custom_created_at(created_at) .sign_with_keys(&keys) diff --git a/crates/nostr/tests/profile_event_builder.rs b/crates/nostr/tests/profile_event_builder.rs @@ -1,11 +1,10 @@ #[path = "../src/test_fixtures.rs"] mod test_fixtures; +use nostr::{Keys as RadrootsNostrKeys, SecretKey as RadrootsNostrSecretKey}; use radroots_event::profile::AuthoredProfile; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; -use radroots_nostr::events::metadata::radroots_nostr_build_profile_event; -use radroots_nostr::types::RadrootsNostrKeys; -use radroots_nostr::types::RadrootsNostrSecretKey; +use radroots_nostr::event::build_profile as build_profile_event; #[test] fn typed_profile_builder_preserves_the_strict_replacement_snapshot() { @@ -19,7 +18,7 @@ fn typed_profile_builder_preserves_the_strict_replacement_snapshot() { .with_about("Tree fruit") .with_bot(false); - let event = radroots_nostr_build_profile_event(&profile) + let event = build_profile_event(&profile) .unwrap() .custom_created_at(created_at) .sign_with_keys(&keys) diff --git a/crates/nostr_runtime/src/types.rs b/crates/nostr_runtime/src/types.rs @@ -1,10 +1,10 @@ use alloc::string::String; use nostr::PublicKey as RadrootsNostrPublicKey; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; -use radroots_nostr::events::post::radroots_nostr_post_events_filter; +use radroots_nostr::event::post_filter; #[cfg(feature = "nostr-client")] use radroots_nostr::filter::Filter as RadrootsNostrFilter; -use radroots_nostr::filter::radroots_nostr_kind; +use radroots_nostr::filter::kind as nostr_kind; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RadrootsNostrSubscriptionPolicy { @@ -59,7 +59,7 @@ impl RadrootsNostrSubscriptionSpec { since_unix: Option<u64>, policy: RadrootsNostrSubscriptionPolicy, ) -> Self { - Self::streaming(radroots_nostr_post_events_filter(limit, since_unix)).with_policy(policy) + Self::streaming(post_filter(limit, since_unix)).with_policy(policy) } #[cfg(feature = "nostr-client")] @@ -69,7 +69,7 @@ impl RadrootsNostrSubscriptionSpec { since_unix: Option<u64>, policy: RadrootsNostrSubscriptionPolicy, ) -> Self { - let mut filter = RadrootsNostrFilter::new().kind(radroots_nostr_kind(kind)); + let mut filter = RadrootsNostrFilter::new().kind(nostr_kind(kind)); if let Some(limit) = limit { filter = filter.limit(limit.into()); } diff --git a/crates/nostr_signer/src/nip46.rs b/crates/nostr_signer/src/nip46.rs @@ -5,8 +5,8 @@ use nostr::{ }; use radroots_identity::PublicIdentity; use radroots_nostr::event::Event as RadrootsNostrEvent; +use radroots_nostr::event::GenericBuilder; use radroots_nostr::event::Kind as RadrootsNostrKind; -use radroots_nostr::event::RadrootsNostrGenericEventBuilder; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; use radroots_nostr::filter::Filter as RadrootsNostrFilter; use radroots_nostr::tag::Tag as RadrootsNostrTag; @@ -182,12 +182,12 @@ impl<S: RadrootsNostrSignerNip46Signer> RadrootsNostrSignerNip46Codec<S> { client_public_key: RadrootsNostrPublicKey, request_id: impl Into<String>, response: RadrootsNostrConnectResponse, - ) -> Result<RadrootsNostrGenericEventBuilder, RadrootsNostrSignerError> { + ) -> Result<GenericBuilder, RadrootsNostrSignerError> { let envelope = response.into_envelope(request_id.into())?; let payload = serde_json::to_string(&envelope).map_err(RadrootsNostrConnectError::from)?; let ciphertext = self.signer.encrypt_response(&client_public_key, &payload)?; - Ok(RadrootsNostrGenericEventBuilder::new( + Ok(GenericBuilder::new( RadrootsNostrKind::Custom(RADROOTS_NOSTR_CONNECT_RPC_KIND), ciphertext, ) @@ -317,7 +317,7 @@ where client_public_key: RadrootsNostrPublicKey, request_id: impl Into<String>, response: RadrootsNostrConnectResponse, - ) -> Result<RadrootsNostrGenericEventBuilder, RadrootsNostrSignerError> { + ) -> Result<GenericBuilder, RadrootsNostrSignerError> { self.codec .build_response_event(client_public_key, request_id, response) } @@ -860,8 +860,8 @@ mod tests { use nostr::{Keys, SecretKey, Timestamp, UnsignedEvent}; use radroots_identity::{PublicIdentity, PublicKey as IdentityPublicKey}; use radroots_nostr::event::Event as RadrootsNostrEvent; + use radroots_nostr::event::GenericBuilder; use radroots_nostr::event::Kind as RadrootsNostrKind; - use radroots_nostr::event::RadrootsNostrGenericEventBuilder; use radroots_nostr::tag::TagKind as RadrootsNostrTagKind; use radroots_nostr_connect::prelude::{ RADROOTS_NOSTR_CONNECT_RPC_KIND, RadrootsNostrConnectMethod, @@ -1222,7 +1222,7 @@ mod tests { let client_public_key = fixture_carol_public_key(); let request = request_message("req-parse", RadrootsNostrConnectRequest::Ping); let raw = serde_json::to_string(&request).expect("serialize request"); - let event = RadrootsNostrGenericEventBuilder::new( + let event = GenericBuilder::new( RadrootsNostrKind::Custom(RADROOTS_NOSTR_CONNECT_RPC_KIND), raw, ) diff --git a/crates/outbox/Cargo.toml b/crates/outbox/Cargo.toml @@ -42,6 +42,7 @@ radroots_identity = { workspace = true, default-features = false, features = [ radroots_nostr = { workspace = true, default-features = false, features = [ "std", "events", + "signing", ] } tempfile = { workspace = true } tokio = { workspace = true, features = ["macros", "rt"] } diff --git a/crates/outbox/src/store.rs b/crates/outbox/src/store.rs @@ -3406,7 +3406,7 @@ mod tests { canonical_trade_mutation_content, }; use radroots_identity::PublicKey; - use radroots_nostr::draft_signing::radroots_nostr_sign_frozen_draft; + use radroots_nostr::signing::sign_frozen_draft; const FIXTURE_ALICE_SECRET_KEY_HEX: &str = "10c5304d6c9ae3a1a16f7860f1cc8f5e3a76225a2663b3a989a0d775919b7df5"; @@ -3589,8 +3589,7 @@ mod tests { fn signed_trade_mutation(canonical: &TradeCanonicalMutationV1) -> (EventDraft, SignedEvent) { let draft = trade_mutation_draft(canonical); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed trade event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed trade event"); (draft, signed_event) } @@ -4286,8 +4285,8 @@ mod tests { .expect("pool outbox"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "preflight"); - let signed_event = radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft) - .expect("signed preflight event"); + let signed_event = + sign_frozen_draft(&fixture_keys(), &draft).expect("signed preflight event"); let input = signed_operation_input(draft.clone(), signed_event.clone(), 1_000) .with_idempotency_key("preflight-idem"); outbox @@ -4312,8 +4311,8 @@ mod tests { .expect("matching existing preflight"); let changed_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "preflight changed"); - let changed_signed = radroots_nostr_sign_frozen_draft(&fixture_keys(), &changed_draft) - .expect("changed signed event"); + let changed_signed = + sign_frozen_draft(&fixture_keys(), &changed_draft).expect("changed signed event"); let conflict = signed_operation_input(changed_draft, changed_signed, 1_100) .with_idempotency_key("preflight-idem"); assert!(matches!( @@ -4324,9 +4323,8 @@ mod tests { )); let transaction_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "transaction"); - let transaction_signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &transaction_draft) - .expect("transaction signed event"); + let transaction_signed = sign_frozen_draft(&fixture_keys(), &transaction_draft) + .expect("transaction signed event"); let transaction_input = signed_operation_input(transaction_draft.clone(), transaction_signed, 2_000) .with_idempotency_key("transaction-idem"); @@ -4343,9 +4341,8 @@ mod tests { let transaction_changed = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "transaction changed"); - let transaction_changed_signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &transaction_changed) - .expect("transaction changed signed event"); + let transaction_changed_signed = sign_frozen_draft(&fixture_keys(), &transaction_changed) + .expect("transaction changed signed event"); let transaction_conflict = signed_operation_input(transaction_changed, transaction_changed_signed, 2_100) .with_idempotency_key("transaction-idem"); @@ -4465,8 +4462,8 @@ mod tests { async fn defensive_storage_decoding_and_remaining_idempotency_edges_are_explicit() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "defensive storage"); - let signed_event = radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft) - .expect("signed defensive event"); + let signed_event = + sign_frozen_draft(&fixture_keys(), &draft).expect("signed defensive event"); let signed_receipt = outbox .enqueue_signed_operation(signed_operation_input( draft.clone(), @@ -4477,8 +4474,8 @@ mod tests { .expect("signed insert without idempotency key"); let keyed_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "keyed public insert"); - let keyed_signed = radroots_nostr_sign_frozen_draft(&fixture_keys(), &keyed_draft) - .expect("keyed signed event"); + let keyed_signed = + sign_frozen_draft(&fixture_keys(), &keyed_draft).expect("keyed signed event"); outbox .enqueue_signed_operation( signed_operation_input(keyed_draft, keyed_signed, 1_100) @@ -4487,8 +4484,8 @@ mod tests { .await .expect("keyed public signed insert"); let changed_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "keyed public conflict"); - let changed_signed = radroots_nostr_sign_frozen_draft(&fixture_keys(), &changed_draft) - .expect("changed signed event"); + let changed_signed = + sign_frozen_draft(&fixture_keys(), &changed_draft).expect("changed signed event"); assert!(matches!( outbox .enqueue_signed_operation( @@ -4504,9 +4501,8 @@ mod tests { FIXTURE_ALICE_PUBLIC_KEY_HEX, "not a semantic trade mutation", ); - let invalid_trade_signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &invalid_trade_draft) - .expect("invalid trade draft still forms a valid signed event"); + let invalid_trade_signed = sign_frozen_draft(&fixture_keys(), &invalid_trade_draft) + .expect("invalid trade draft still forms a valid signed event"); assert!(matches!( outbox .preflight_signed_trade_mutation_idempotency(&signed_trade_mutation_input( @@ -4567,9 +4563,8 @@ mod tests { .expect("trade insert without idempotency key"); let transaction_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "transaction no key"); - let transaction_signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &transaction_draft) - .expect("transaction signed event"); + let transaction_signed = sign_frozen_draft(&fixture_keys(), &transaction_draft) + .expect("transaction signed event"); let mut transaction = outbox.pool().begin().await.expect("begin transaction"); outbox .enqueue_signed_operation_in_transaction( @@ -4911,8 +4906,7 @@ mod tests { )); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "plan lifecycle"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("sign plan lifecycle"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("sign plan lifecycle"); let first = outbox .enqueue_signed_operation( RadrootsOutboxSignedOperationInput::new( @@ -5085,8 +5079,7 @@ mod tests { .enqueue_operation(operation_input(draft.clone(), 1_000)) .await .expect("enqueue unsigned"); - let signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("sign queued event"); + let signed = sign_frozen_draft(&fixture_keys(), &draft).expect("sign queued event"); let claimed = outbox .claim_next_ready_event("signer", "sign-claim", 2_000, 1_000) .await @@ -5106,8 +5099,8 @@ mod tests { )); let other_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "different event"); - let other_signed = radroots_nostr_sign_frozen_draft(&fixture_keys(), &other_draft) - .expect("sign different event"); + let other_signed = + sign_frozen_draft(&fixture_keys(), &other_draft).expect("sign different event"); assert!(matches!( outbox .complete_signing(receipt.outbox_event_id, "sign-claim", other_signed, 1_020,) @@ -5266,8 +5259,8 @@ mod tests { let signed_outbox = RadrootsOutbox::open_memory().await.expect("open signed"); let signed_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "signed race"); - let signed_event = radroots_nostr_sign_frozen_draft(&fixture_keys(), &signed_draft) - .expect("sign race event"); + let signed_event = + sign_frozen_draft(&fixture_keys(), &signed_draft).expect("sign race event"); signed_outbox .enqueue_signed_operation(signed_operation_input(signed_draft, signed_event, 1_000)) .await @@ -5291,8 +5284,7 @@ mod tests { async fn claimed_publish_mutations_enforce_plan_identity_and_atomic_updates() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "publish guards"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("sign publish guards"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("sign publish guards"); let receipt = outbox .enqueue_signed_operation(signed_operation_input(draft, signed_event, 1_000)) .await @@ -5532,8 +5524,7 @@ mod tests { FIXTURE_ALICE_PUBLIC_KEY_HEX, ) .expect("ephemeral draft"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed"); let unsigned_error = outbox .enqueue_operation(operation_input(draft.clone(), 1_000)) @@ -5873,8 +5864,7 @@ mod tests { async fn no_wait_delivery_plan_persists_directly_and_completes_without_target_satisfaction() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "no wait"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -6168,8 +6158,7 @@ mod tests { async fn signed_enqueue_claims_ready_delivery_targets_and_records_attempts() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "signed"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(signed_operation_input(draft, signed_event.clone(), 1_000)) .await @@ -6271,8 +6260,7 @@ mod tests { async fn required_target_plan_evaluation_uses_persisted_fingerprints() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "required target"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let optional = nostr_target(NOSTR_PRIMARY_WSS); let required = nostr_target(NOSTR_SECONDARY_WSS); let receipt = outbox @@ -6382,8 +6370,7 @@ mod tests { FIXTURE_ALICE_PUBLIC_KEY_HEX, "required target optional failure", ); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let optional = nostr_target(NOSTR_PRIMARY_WSS); let required = nostr_target(NOSTR_SECONDARY_WSS); let receipt = outbox @@ -6515,8 +6502,7 @@ mod tests { ] { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, terminal_status.as_str()); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -6621,8 +6607,7 @@ mod tests { async fn publish_claims_one_delivery_plan_and_rejects_sibling_target_outcomes() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "duplicate endpoint plans"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let first = outbox .enqueue_signed_operation( RadrootsOutboxSignedOperationInput::new( @@ -6764,8 +6749,7 @@ mod tests { async fn active_plan_terminal_failure_leaves_sibling_claimable() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "plan scoped terminal"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let first = outbox .enqueue_signed_operation( RadrootsOutboxSignedOperationInput::new( @@ -6907,8 +6891,7 @@ mod tests { async fn cancel_claimed_event_marks_every_delivery_plan_cancelled() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "cancel all plans"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let first = outbox .enqueue_signed_operation( RadrootsOutboxSignedOperationInput::new( @@ -6991,8 +6974,7 @@ mod tests { async fn quorum_accepted_delivery_plan_round_trips_and_completes_after_required_target() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "at least"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7059,8 +7041,7 @@ mod tests { async fn publish_attempt_stays_retryable_while_delivery_targets_remain_ready() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "retryable"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(signed_operation_input(draft, signed_event, 1_000)) .await @@ -7101,8 +7082,7 @@ mod tests { async fn reticulum_reject_targets_are_deferred_until_implemented_and_not_ready() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "reticulum rejected"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7171,8 +7151,7 @@ mod tests { async fn reticulum_deferred_targets_do_not_retry_or_satisfy_delivery() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "reticulum deferred"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7239,8 +7218,7 @@ mod tests { let default_behavior_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "reticulum deferred"); let default_behavior_signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &default_behavior_draft) - .expect("signed event"); + sign_frozen_draft(&fixture_keys(), &default_behavior_draft).expect("signed event"); let default_behavior_preflight = outbox .preflight_signed_operation_idempotency(&RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7268,8 +7246,7 @@ mod tests { async fn repeated_reticulum_signed_delivery_reuses_one_logical_operation_and_plan() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "reticulum repeated"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let first = outbox .enqueue_signed_operation( RadrootsOutboxSignedOperationInput::new( @@ -7337,8 +7314,8 @@ mod tests { async fn reticulum_events_report_deferred_records() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let reject_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "reticulum record"); - let reject_signed_event = radroots_nostr_sign_frozen_draft(&fixture_keys(), &reject_draft) - .expect("reticulum signed event"); + let reject_signed_event = + sign_frozen_draft(&fixture_keys(), &reject_draft).expect("reticulum signed event"); let reject = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7359,8 +7336,7 @@ mod tests { let deferred_draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "reticulum deferred record"); let deferred_signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &deferred_draft) - .expect("deferred signed event"); + sign_frozen_draft(&fixture_keys(), &deferred_draft).expect("deferred signed event"); let deferred = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7491,8 +7467,7 @@ mod tests { .expect("claim") .expect("claimed"); assert_eq!(claimed.active_delivery_plan_id, None); - let signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); + let signed = sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); outbox .complete_signing(receipt.outbox_event_id, "claim-a", signed, 1_100) @@ -7528,8 +7503,7 @@ mod tests { async fn explicit_all_targets_completes_after_nostr_success_with_reticulum_preserved() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "explicit all targets"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7630,8 +7604,7 @@ mod tests { async fn explicit_quorum_rejects_deferred_targets_as_required_success_capacity() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "explicit quorum"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let err = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7667,8 +7640,7 @@ mod tests { async fn explicit_nostr_and_reticulum_preserves_ready_nostr_work() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "explicit reticulum"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7724,8 +7696,7 @@ mod tests { async fn accepted_delivery_target_can_advance_to_strict_success_status() { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "accepted then delivered"); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7832,8 +7803,7 @@ mod tests { ] { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, content); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -7976,8 +7946,7 @@ mod tests { ] { let outbox = RadrootsOutbox::open_memory().await.expect("open"); let draft = generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, content); - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &draft).expect("signed event"); let receipt = outbox .enqueue_signed_operation(RadrootsOutboxSignedOperationInput::new( "publish_post", @@ -8110,8 +8079,7 @@ mod tests { .await .expect("claim") .expect("claimed"); - let signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); + let signed = sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); outbox .complete_signing( receipt.outbox_event_id, @@ -8181,8 +8149,7 @@ mod tests { .await .expect("claim") .expect("claimed"); - let signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); + let signed = sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); outbox .complete_signing( receipt.outbox_event_id, @@ -8242,8 +8209,7 @@ mod tests { .await .expect("claim") .expect("claimed"); - let signed = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); + let signed = sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed"); let mut wire = signed.wire().clone(); wire.sig = "0".repeat(128); let raw_json = serde_json::to_string(&wire).expect("invalid-signature wire JSON"); diff --git a/crates/replica_sync/src/ingest.rs b/crates/replica_sync/src/ingest.rs @@ -1636,7 +1636,7 @@ mod tests { use radroots_event_codec::encode::farm as farm_list_sets; use radroots_event_codec::encode::list_set as list_set_encode; use radroots_event_codec::encode::plot as plot_encode; - use radroots_nostr::event::radroots_event_from_nostr; + use radroots_nostr::event::from_nostr; use radroots_replica_schema::farm::IFarmFields; use radroots_replica_schema::farm_gcs_location::IFarmGcsLocationFields; use radroots_replica_schema::farm_member::IFarmMemberFields; @@ -2072,7 +2072,7 @@ mod tests { .custom_created_at(Timestamp::from_secs(created_at)) .sign_with_keys(&keys) .expect("signed listing event"); - radroots_event_from_nostr(&event).expect("listing event adapter") + from_nostr(&event).expect("listing event adapter") } fn focused_listing_event(author: &str, created_at: u64, d_tag: &str) -> EventEnvelope { diff --git a/crates/transport_nostr/src/publish.rs b/crates/transport_nostr/src/publish.rs @@ -1050,7 +1050,7 @@ mod tests { use radroots_event::draft::{EventDraft, SignedEvent}; use radroots_event::envelope::kind::KIND_GEOCHAT; use radroots_event::wire::Nip01EventWire; - use radroots_nostr::draft_signing::radroots_nostr_sign_frozen_draft; + use radroots_nostr::signing::sign_frozen_draft; const FIXTURE_ALICE_SECRET_KEY_HEX: &str = "10c5304d6c9ae3a1a16f7860f1cc8f5e3a76225a2663b3a989a0d775919b7df5"; @@ -1070,7 +1070,7 @@ mod tests { FIXTURE_ALICE_PUBLIC_KEY_HEX, ) .expect("draft"); - let signed_event = radroots_nostr_sign_frozen_draft(&keys, &draft).expect("signed event"); + let signed_event = sign_frozen_draft(&keys, &draft).expect("signed event"); let raw_event = RadrootsNostrEvent::from_json(signed_event.raw_json()).expect("raw event"); (raw_event, signed_event) } diff --git a/crates/transport_nostr/tests/transport.rs b/crates/transport_nostr/tests/transport.rs @@ -9,11 +9,11 @@ use radroots_event::wire::v1::DEFAULT_RAW_JSON_MAX_BYTES; use radroots_event_store::{ RadrootsEventStore, RadrootsTransportObservationRow, RadrootsTransportObservationType, }; -use radroots_nostr::draft_signing::radroots_nostr_sign_frozen_draft; use radroots_nostr::event::Kind as RadrootsNostrKind; use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; use radroots_nostr::filter::Filter as RadrootsNostrFilter; -use radroots_nostr::filter::radroots_nostr_filter_tag; +use radroots_nostr::filter::with_tag; +use radroots_nostr::signing::sign_frozen_draft; use radroots_nostr::tag::Tag as RadrootsNostrTag; use radroots_nostr::tag::TagKind as RadrootsNostrTagKind; use radroots_outbox::{ @@ -475,8 +475,7 @@ async fn complete_claimed_signing( if let Some(signed_event) = claimed.signed_event.clone() { return signed_event; } - let signed_event = - radroots_nostr_sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed event"); + let signed_event = sign_frozen_draft(&fixture_keys(), &claimed.draft).expect("signed event"); outbox .complete_signing( claimed.outbox_event_id, @@ -598,7 +597,7 @@ fn invalid_contract_shape_raw_event() -> String { } fn post_relay_fetch_filter(limit: usize) -> RadrootsNostrFilter { - radroots_nostr_filter_tag( + with_tag( RadrootsNostrFilter::new() .kind(RadrootsNostrKind::Custom( u16::try_from(KIND_POST).expect("post kind must fit NIP-01"), @@ -2614,7 +2613,7 @@ async fn fetch_rejects_out_of_filter_events_before_store_mutation() { relay_url: RELAY_PRIMARY_WSS.to_owned(), }, ]); - let filter = radroots_nostr_filter_tag( + let filter = with_tag( RadrootsNostrFilter::new() .kind(RadrootsNostrKind::Custom( u16::try_from(KIND_POST).expect("post kind must fit NIP-01"), @@ -2769,7 +2768,7 @@ async fn fetch_relay_events_applies_shared_filter_limit_and_outcome_evidence() { let skipped = signed_event_with_kind_and_hashtag("shared fetch skipped", KIND_POST, "soil"); let wrong_tag = signed_event_with_kind_and_hashtag("shared fetch wrong tag", KIND_POST, "compost"); - let filter = radroots_nostr_filter_tag( + let filter = with_tag( RadrootsNostrFilter::new() .kind(RadrootsNostrKind::Custom( u16::try_from(KIND_POST).expect("post kind must fit NIP-01"), diff --git a/docs/api/radroots_nostr.txt b/docs/api/radroots_nostr.txt @@ -1,236 +1,178 @@ pub mod radroots_nostr pub mod radroots_nostr::blossom -#[non_exhaustive] pub enum radroots_nostr::blossom::RadrootsNostrBlossomError -pub radroots_nostr::blossom::RadrootsNostrBlossomError::BlossomClaim(radroots_blossom::error::Error) -pub radroots_nostr::blossom::RadrootsNostrBlossomError::EmptyHeaderPayload -pub radroots_nostr::blossom::RadrootsNostrBlossomError::EventSigning -pub radroots_nostr::blossom::RadrootsNostrBlossomError::HeaderPaddingForbidden -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidEventId -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidEventJson -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidEventKind -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidEventKind::actual: u64 -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidEventSignature -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidHeaderBase64 -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidHeaderScheme -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidHeaderUtf8 -pub radroots_nostr::blossom::RadrootsNostrBlossomError::InvalidHeaderWhitespace -pub radroots_nostr::blossom::RadrootsNostrBlossomError::NonCanonicalHeaderBase64 -impl radroots_nostr::blossom::RadrootsNostrBlossomError -pub fn radroots_nostr::blossom::RadrootsNostrBlossomError::blossom_claim_error(&self) -> core::option::Option<&radroots_blossom::error::Error> -pub const fn radroots_nostr::blossom::RadrootsNostrBlossomError::code(&self) -> &'static str -impl core::convert::From<radroots_blossom::error::Error> for radroots_nostr::blossom::RadrootsNostrBlossomError -pub fn radroots_nostr::blossom::RadrootsNostrBlossomError::from(radroots_blossom::error::Error) -> Self -impl core::error::Error for radroots_nostr::blossom::RadrootsNostrBlossomError -impl core::fmt::Display for radroots_nostr::blossom::RadrootsNostrBlossomError -pub fn radroots_nostr::blossom::RadrootsNostrBlossomError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub struct radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader(_) -impl radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader -pub fn radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader::as_str(&self) -> &str -pub fn radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader::into_string(self) -> alloc::string::String -impl core::convert::AsRef<str> for radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader -pub fn radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader::as_ref(&self) -> &str -impl core::fmt::Debug for radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader -pub fn radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub struct radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization -impl radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization -pub fn radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization::author(&self) -> radroots_nostr::types::RadrootsNostrPublicKey -pub fn radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization::created_at(&self) -> radroots_nostr::event::Timestamp -pub fn radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization::event_id(&self) -> radroots_nostr::event::EventId -impl core::fmt::Debug for radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization -pub fn radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub struct radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization -impl radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization -pub fn radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization::author(&self) -> radroots_nostr::types::RadrootsNostrPublicKey -pub fn radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization::claim(&self) -> &radroots_blossom::authorization::ValidatedAuthorizationClaim -pub fn radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization::created_at(&self) -> radroots_nostr::event::Timestamp -pub fn radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization::event_id(&self) -> radroots_nostr::event::EventId -impl core::fmt::Debug for radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization -pub fn radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn radroots_nostr::blossom::radroots_nostr_decode_verify_blossom_authorization_header(&str, &radroots_blossom::authorization::AuthorizationValidation) -> core::result::Result<radroots_nostr::blossom::RadrootsNostrVerifiedBlossomAuthorization, radroots_nostr::blossom::RadrootsNostrBlossomError> -pub fn radroots_nostr::blossom::radroots_nostr_encode_blossom_authorization_header(&radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization) -> radroots_nostr::blossom::RadrootsNostrBlossomAuthorizationHeader -pub fn radroots_nostr::blossom::radroots_nostr_sign_blossom_authorization(&radroots_nostr::types::RadrootsNostrKeys, &radroots_blossom::authorization::AuthoredUploadClaim) -> core::result::Result<radroots_nostr::blossom::RadrootsNostrSignedBlossomAuthorization, radroots_nostr::blossom::RadrootsNostrBlossomError> -pub mod radroots_nostr::codec_adapters -pub fn radroots_nostr::codec_adapters::to_job_feedback_index(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedEvent<radroots_event::social::job_feedback::JobFeedback>, radroots_event_codec::job::error::JobParseError> -pub fn radroots_nostr::codec_adapters::to_job_feedback_metadata(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::job_feedback::JobFeedback>, radroots_event_codec::job::error::JobParseError> -pub fn radroots_nostr::codec_adapters::to_job_request_index(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedEvent<radroots_event::social::job_request::JobRequest>, radroots_event_codec::job::error::JobParseError> -pub fn radroots_nostr::codec_adapters::to_job_request_metadata(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::job_request::JobRequest>, radroots_event_codec::job::error::JobParseError> -pub fn radroots_nostr::codec_adapters::to_job_result_index(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedEvent<radroots_event::social::job_result::JobResult>, radroots_event_codec::job::error::JobParseError> -pub fn radroots_nostr::codec_adapters::to_job_result_metadata(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::job_result::JobResult>, radroots_event_codec::job::error::JobParseError> -pub mod radroots_nostr::draft_signing -pub fn radroots_nostr::draft_signing::radroots_nostr_sign_frozen_draft(&radroots_nostr::types::RadrootsNostrKeys, &radroots_event::draft::EventDraft) -> core::result::Result<radroots_event::draft::SignedEvent, radroots_nostr::error::RadrootsNostrError> -pub mod radroots_nostr::error -pub enum radroots_nostr::error::RadrootsNostrError -pub radroots_nostr::error::RadrootsNostrError::CoordinateConversion -pub radroots_nostr::error::RadrootsNostrError::DraftError(radroots_event::draft::DraftError) -pub radroots_nostr::error::RadrootsNostrError::EventBuildError(nostr::event::builder::Error) -pub radroots_nostr::error::RadrootsNostrError::EventConversion -pub radroots_nostr::error::RadrootsNostrError::EventConversion::field: &'static str -pub radroots_nostr::error::RadrootsNostrError::EventError(nostr::event::error::Error) -pub radroots_nostr::error::RadrootsNostrError::EventWire(radroots_event::wire::v1::EventWireError) -pub radroots_nostr::error::RadrootsNostrError::ExternalSigningAuthorMismatch -pub radroots_nostr::error::RadrootsNostrError::ExternalSigningAuthorMismatch::actual: nostr::key::public_key::PublicKey -pub radroots_nostr::error::RadrootsNostrError::ExternalSigningAuthorMismatch::expected: nostr::key::public_key::PublicKey -pub radroots_nostr::error::RadrootsNostrError::ExternalSigningEventIdMismatch -pub radroots_nostr::error::RadrootsNostrError::ExternalSigningEventIdMismatch::actual: nostr::event::id::EventId -pub radroots_nostr::error::RadrootsNostrError::ExternalSigningEventIdMismatch::expected: nostr::event::id::EventId -pub radroots_nostr::error::RadrootsNostrError::ExternalSigningEventInvalid(nostr::event::error::Error) -pub radroots_nostr::error::RadrootsNostrError::FilterTagError(alloc::string::String) -pub radroots_nostr::error::RadrootsNostrError::FoodAvailabilityEncode(radroots_event_codec::food_availability::authored::RadrootsFoodAvailabilityEncodeError) -pub radroots_nostr::error::RadrootsNostrError::FrozenDraftEventIdMismatch -pub radroots_nostr::error::RadrootsNostrError::FrozenDraftEventIdMismatch::actual_event_id: alloc::string::String -pub radroots_nostr::error::RadrootsNostrError::FrozenDraftEventIdMismatch::expected_event_id: alloc::string::String -pub radroots_nostr::error::RadrootsNostrError::FrozenDraftPubkeyMismatch -pub radroots_nostr::error::RadrootsNostrError::FrozenDraftPubkeyMismatch::actual_pubkey: alloc::string::String -pub radroots_nostr::error::RadrootsNostrError::FrozenDraftPubkeyMismatch::expected_pubkey: alloc::string::String -pub radroots_nostr::error::RadrootsNostrError::InvalidEncryptedSecretKey -pub radroots_nostr::error::RadrootsNostrError::InvalidNpub -pub radroots_nostr::error::RadrootsNostrError::InvalidPublicKey -pub radroots_nostr::error::RadrootsNostrError::InvalidSecretKey -pub radroots_nostr::error::RadrootsNostrError::KeyError(nostr::key::Error) -pub radroots_nostr::error::RadrootsNostrError::KindOutOfRange -pub radroots_nostr::error::RadrootsNostrError::KindOutOfRange::kind: u32 -pub radroots_nostr::error::RadrootsNostrError::KindOutOfRange::max: u16 -pub radroots_nostr::error::RadrootsNostrError::ProfileEncode(radroots_event_codec::profile::authored::RadrootsAuthoredProfileEncodeError) -pub radroots_nostr::error::RadrootsNostrError::SecretKeyDecryption -pub radroots_nostr::error::RadrootsNostrError::SecretKeyEncryption -pub radroots_nostr::error::RadrootsNostrError::SignedEvent(radroots_event::draft::SignedEventError) -pub radroots_nostr::error::RadrootsNostrError::TagConversion -pub radroots_nostr::error::RadrootsNostrError::TypedAuthoringRequired -pub radroots_nostr::error::RadrootsNostrError::TypedAuthoringRequired::kind: u16 -impl core::convert::From<nostr::event::builder::Error> for radroots_nostr::error::RadrootsNostrError -pub fn radroots_nostr::error::RadrootsNostrError::from(nostr::event::builder::Error) -> Self -impl core::convert::From<nostr::event::error::Error> for radroots_nostr::error::RadrootsNostrError -pub fn radroots_nostr::error::RadrootsNostrError::from(nostr::event::error::Error) -> Self -impl core::convert::From<nostr::key::Error> for radroots_nostr::error::RadrootsNostrError -pub fn radroots_nostr::error::RadrootsNostrError::from(nostr::key::Error) -> Self -pub enum radroots_nostr::error::RadrootsNostrTagsResolveError -pub radroots_nostr::error::RadrootsNostrTagsResolveError::DecryptionError(alloc::string::String) -pub radroots_nostr::error::RadrootsNostrTagsResolveError::MissingPTag(alloc::boxed::Box<nostr::event::Event>) -pub radroots_nostr::error::RadrootsNostrTagsResolveError::NotRecipient -pub radroots_nostr::error::RadrootsNostrTagsResolveError::ParseError(serde_json::error::Error) +#[non_exhaustive] pub enum radroots_nostr::blossom::AuthorizationError +pub radroots_nostr::blossom::AuthorizationError::BlossomClaim(radroots_blossom::error::Error) +pub radroots_nostr::blossom::AuthorizationError::EmptyHeaderPayload +pub radroots_nostr::blossom::AuthorizationError::EventSigning +pub radroots_nostr::blossom::AuthorizationError::HeaderPaddingForbidden +pub radroots_nostr::blossom::AuthorizationError::InvalidEventId +pub radroots_nostr::blossom::AuthorizationError::InvalidEventJson +pub radroots_nostr::blossom::AuthorizationError::InvalidEventKind +pub radroots_nostr::blossom::AuthorizationError::InvalidEventKind::actual: u64 +pub radroots_nostr::blossom::AuthorizationError::InvalidEventSignature +pub radroots_nostr::blossom::AuthorizationError::InvalidHeaderBase64 +pub radroots_nostr::blossom::AuthorizationError::InvalidHeaderScheme +pub radroots_nostr::blossom::AuthorizationError::InvalidHeaderUtf8 +pub radroots_nostr::blossom::AuthorizationError::InvalidHeaderWhitespace +pub radroots_nostr::blossom::AuthorizationError::NonCanonicalHeaderBase64 +impl radroots_nostr::blossom::AuthorizationError +pub fn radroots_nostr::blossom::AuthorizationError::blossom_claim_error(&self) -> core::option::Option<&radroots_blossom::error::Error> +pub const fn radroots_nostr::blossom::AuthorizationError::code(&self) -> &'static str +impl core::convert::From<radroots_blossom::error::Error> for radroots_nostr::blossom::AuthorizationError +pub fn radroots_nostr::blossom::AuthorizationError::from(radroots_blossom::error::Error) -> Self +impl core::error::Error for radroots_nostr::blossom::AuthorizationError +impl core::fmt::Display for radroots_nostr::blossom::AuthorizationError +pub fn radroots_nostr::blossom::AuthorizationError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub struct radroots_nostr::blossom::AuthorizationHeader(_) +impl radroots_nostr::blossom::AuthorizationHeader +pub fn radroots_nostr::blossom::AuthorizationHeader::as_str(&self) -> &str +pub fn radroots_nostr::blossom::AuthorizationHeader::into_string(self) -> alloc::string::String +impl core::convert::AsRef<str> for radroots_nostr::blossom::AuthorizationHeader +pub fn radroots_nostr::blossom::AuthorizationHeader::as_ref(&self) -> &str +impl core::fmt::Debug for radroots_nostr::blossom::AuthorizationHeader +pub fn radroots_nostr::blossom::AuthorizationHeader::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub struct radroots_nostr::blossom::SignedAuthorization +impl radroots_nostr::blossom::SignedAuthorization +pub fn radroots_nostr::blossom::SignedAuthorization::author(&self) -> nostr::key::public_key::PublicKey +pub fn radroots_nostr::blossom::SignedAuthorization::created_at(&self) -> radroots_nostr::event::Timestamp +pub fn radroots_nostr::blossom::SignedAuthorization::event_id(&self) -> radroots_nostr::event::EventId +impl core::fmt::Debug for radroots_nostr::blossom::SignedAuthorization +pub fn radroots_nostr::blossom::SignedAuthorization::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub struct radroots_nostr::blossom::VerifiedAuthorization +impl radroots_nostr::blossom::VerifiedAuthorization +pub fn radroots_nostr::blossom::VerifiedAuthorization::author(&self) -> nostr::key::public_key::PublicKey +pub fn radroots_nostr::blossom::VerifiedAuthorization::claim(&self) -> &radroots_blossom::authorization::ValidatedAuthorizationClaim +pub fn radroots_nostr::blossom::VerifiedAuthorization::created_at(&self) -> radroots_nostr::event::Timestamp +pub fn radroots_nostr::blossom::VerifiedAuthorization::event_id(&self) -> radroots_nostr::event::EventId +impl core::fmt::Debug for radroots_nostr::blossom::VerifiedAuthorization +pub fn radroots_nostr::blossom::VerifiedAuthorization::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub fn radroots_nostr::blossom::decode_verify_authorization_header(&str, &radroots_blossom::authorization::AuthorizationValidation) -> core::result::Result<radroots_nostr::blossom::VerifiedAuthorization, radroots_nostr::blossom::AuthorizationError> +pub fn radroots_nostr::blossom::encode_authorization_header(&radroots_nostr::blossom::SignedAuthorization) -> radroots_nostr::blossom::AuthorizationHeader +pub fn radroots_nostr::blossom::sign_authorization(&nostr::key::Keys, &radroots_blossom::authorization::AuthoredUploadClaim) -> core::result::Result<radroots_nostr::blossom::SignedAuthorization, radroots_nostr::blossom::AuthorizationError> pub mod radroots_nostr::event -pub struct radroots_nostr::event::RadrootsNostrExternalSigningRequest -impl radroots_nostr::types::RadrootsNostrExternalSigningRequest -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::complete(self, radroots_nostr::event::Event) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::expected_event_id(&self) -> radroots_nostr::event::EventId -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::expected_public_key(&self) -> radroots_nostr::types::RadrootsNostrPublicKey -impl serde_core::ser::Serialize for radroots_nostr::types::RadrootsNostrExternalSigningRequest -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer -pub struct radroots_nostr::event::RadrootsNostrGenericEventBuilder -impl radroots_nostr::types::RadrootsNostrGenericEventBuilder -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::allow_self_tagging(self) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::dedup_tags(self) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::into_external_signing_request(self, radroots_nostr::types::RadrootsNostrPublicKey) -> core::result::Result<radroots_nostr::types::RadrootsNostrExternalSigningRequest, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::new(radroots_nostr::event::Kind, impl core::convert::Into<alloc::string::String>) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::pow(self, u8) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::tag(self, radroots_nostr::tag::Tag) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::tags<I>(self, I) -> Self where I: core::iter::traits::collect::IntoIterator<Item = radroots_nostr::tag::Tag> -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::text_note(impl core::convert::Into<alloc::string::String>) -> Self -pub fn radroots_nostr::event::coordinate_from_nostr(&radroots_nostr::event::Coordinate) -> core::result::Result<radroots_event::id::Nip01Coordinate, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::event::coordinate_to_nostr(&radroots_event::id::Nip01Coordinate) -> core::result::Result<radroots_nostr::event::Coordinate, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::event::nostr_event_from_radroots(&radroots_event::envelope::EventEnvelope) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::event::radroots_event_from_nostr(&radroots_nostr::event::Event) -> core::result::Result<radroots_event::envelope::EventEnvelope, radroots_event::envelope::EventEnvelopeError> -pub fn radroots_nostr::event::radroots_event_ptr_from_nostr(&radroots_nostr::event::Event) -> radroots_event::tag::EventPtr +pub enum radroots_nostr::event::Verification +pub radroots_nostr::event::Verification::IdMismatch +pub radroots_nostr::event::Verification::IdVerified +pub radroots_nostr::event::Verification::MalformedEnvelope +pub radroots_nostr::event::Verification::SignatureInvalid +pub radroots_nostr::event::Verification::Verified +pub struct radroots_nostr::event::ApplicationHandlerSpec +impl radroots_nostr::event::ApplicationHandlerSpec +pub fn radroots_nostr::event::ApplicationHandlerSpec::extra_tags(&self) -> &[alloc::vec::Vec<alloc::string::String>] +pub fn radroots_nostr::event::ApplicationHandlerSpec::identifier(&self) -> core::option::Option<&str> +pub fn radroots_nostr::event::ApplicationHandlerSpec::kinds(&self) -> &[u32] +pub fn radroots_nostr::event::ApplicationHandlerSpec::metadata(&self) -> core::option::Option<&radroots_nostr::event::Metadata> +pub fn radroots_nostr::event::ApplicationHandlerSpec::new(alloc::vec::Vec<u32>) -> Self +pub fn radroots_nostr::event::ApplicationHandlerSpec::nostr_connect_url(&self) -> core::option::Option<&str> +pub fn radroots_nostr::event::ApplicationHandlerSpec::relays(&self) -> &[alloc::string::String] +pub fn radroots_nostr::event::ApplicationHandlerSpec::with_extra_tags(self, alloc::vec::Vec<alloc::vec::Vec<alloc::string::String>>) -> Self +pub fn radroots_nostr::event::ApplicationHandlerSpec::with_identifier(self, impl core::convert::Into<alloc::string::String>) -> Self +pub fn radroots_nostr::event::ApplicationHandlerSpec::with_metadata(self, radroots_nostr::event::Metadata) -> Self +pub fn radroots_nostr::event::ApplicationHandlerSpec::with_nostr_connect_url(self, impl core::convert::Into<alloc::string::String>) -> Self +pub fn radroots_nostr::event::ApplicationHandlerSpec::with_relays(self, alloc::vec::Vec<alloc::string::String>) -> Self +pub struct radroots_nostr::event::EventAdapter<'a> +impl<'a> radroots_nostr::event::EventAdapter<'a> +pub fn radroots_nostr::event::EventAdapter<'a>::new(&'a radroots_nostr::event::Event) -> Self +impl radroots_event_codec::job::traits::JobEventLike for radroots_nostr::event::EventAdapter<'_> +pub fn radroots_nostr::event::EventAdapter<'_>::raw_author(&self) -> alloc::string::String +pub fn radroots_nostr::event::EventAdapter<'_>::raw_content(&self) -> alloc::string::String +pub fn radroots_nostr::event::EventAdapter<'_>::raw_id(&self) -> alloc::string::String +pub fn radroots_nostr::event::EventAdapter<'_>::raw_kind(&self) -> u32 +pub fn radroots_nostr::event::EventAdapter<'_>::raw_published_at(&self) -> u64 +pub fn radroots_nostr::event::EventAdapter<'_>::raw_sig(&self) -> alloc::string::String +pub fn radroots_nostr::event::EventAdapter<'_>::raw_tags(&self) -> alloc::vec::Vec<alloc::vec::Vec<alloc::string::String>> +impl<'a> radroots_event_codec::job::traits::JobEventBorrow<'a> for radroots_nostr::event::EventAdapter<'a> +pub fn radroots_nostr::event::EventAdapter<'a>::raw_author(&'a self) -> alloc::string::String +pub fn radroots_nostr::event::EventAdapter<'a>::raw_content(&'a self) -> &'a str +pub fn radroots_nostr::event::EventAdapter<'a>::raw_id(&'a self) -> alloc::string::String +pub fn radroots_nostr::event::EventAdapter<'a>::raw_kind(&'a self) -> u32 +pub struct radroots_nostr::event::ExternalSigningRequest +impl radroots_nostr::event::ExternalSigningRequest +pub fn radroots_nostr::event::ExternalSigningRequest::complete(self, radroots_nostr::event::Event) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub fn radroots_nostr::event::ExternalSigningRequest::expected_event_id(&self) -> radroots_nostr::event::EventId +pub fn radroots_nostr::event::ExternalSigningRequest::expected_public_key(&self) -> nostr::key::public_key::PublicKey +impl serde_core::ser::Serialize for radroots_nostr::event::ExternalSigningRequest +pub fn radroots_nostr::event::ExternalSigningRequest::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer +pub struct radroots_nostr::event::FoodAvailabilityBuilder +impl radroots_nostr::event::FoodAvailabilityBuilder +pub fn radroots_nostr::event::FoodAvailabilityBuilder::sign_with_keys(self, &nostr::key::Keys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub struct radroots_nostr::event::GenericBuilder +impl radroots_nostr::event::GenericBuilder +pub fn radroots_nostr::event::GenericBuilder::allow_self_tagging(self) -> Self +pub fn radroots_nostr::event::GenericBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self +pub fn radroots_nostr::event::GenericBuilder::dedup_tags(self) -> Self +pub fn radroots_nostr::event::GenericBuilder::into_external_signing_request(self, nostr::key::public_key::PublicKey) -> core::result::Result<radroots_nostr::event::ExternalSigningRequest, radroots_nostr::Error> +pub fn radroots_nostr::event::GenericBuilder::new(radroots_nostr::event::Kind, impl core::convert::Into<alloc::string::String>) -> Self +pub fn radroots_nostr::event::GenericBuilder::pow(self, u8) -> Self +pub fn radroots_nostr::event::GenericBuilder::sign_with_keys(self, &nostr::key::Keys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub fn radroots_nostr::event::GenericBuilder::tag(self, radroots_nostr::tag::Tag) -> Self +pub fn radroots_nostr::event::GenericBuilder::tags<I>(self, I) -> Self where I: core::iter::traits::collect::IntoIterator<Item = radroots_nostr::tag::Tag> +pub fn radroots_nostr::event::GenericBuilder::text_note(impl core::convert::Into<alloc::string::String>) -> Self +pub struct radroots_nostr::event::Nip09DeletionRequestBuilder +impl radroots_nostr::event::Nip09DeletionRequestBuilder +pub fn radroots_nostr::event::Nip09DeletionRequestBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self +pub fn radroots_nostr::event::Nip09DeletionRequestBuilder::sign_with_keys(self, &nostr::key::Keys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub struct radroots_nostr::event::Nip10ReplyBuilder +impl radroots_nostr::event::Nip10ReplyBuilder +pub fn radroots_nostr::event::Nip10ReplyBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self +pub fn radroots_nostr::event::Nip10ReplyBuilder::sign_with_keys(self, &nostr::key::Keys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub struct radroots_nostr::event::Nip22CommentBuilder +impl radroots_nostr::event::Nip22CommentBuilder +pub fn radroots_nostr::event::Nip22CommentBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self +pub fn radroots_nostr::event::Nip22CommentBuilder::sign_with_keys(self, &nostr::key::Keys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub struct radroots_nostr::event::PostBuilder +impl radroots_nostr::event::PostBuilder +pub fn radroots_nostr::event::PostBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self +pub fn radroots_nostr::event::PostBuilder::sign_with_keys(self, &nostr::key::Keys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub struct radroots_nostr::event::ProfileBuilder +impl radroots_nostr::event::ProfileBuilder +pub fn radroots_nostr::event::ProfileBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self +pub fn radroots_nostr::event::ProfileBuilder::sign_with_keys(self, &nostr::key::Keys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub struct radroots_nostr::event::SignatureVerifier +impl radroots_event::verification::SignatureVerifier for radroots_nostr::event::SignatureVerifier +pub fn radroots_nostr::event::SignatureVerifier::verify_signature(&self, &radroots_event::envelope::EventEnvelope) -> core::result::Result<(), radroots_event::verification::Error> +pub fn radroots_nostr::event::build_application_handler(&radroots_nostr::event::ApplicationHandlerSpec) -> core::result::Result<radroots_nostr::event::GenericBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_ask(&radroots_event::post::AuthoredAsk) -> core::result::Result<radroots_nostr::event::PostBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_food_availability(&radroots_event::food::availability::FoodAvailabilityDetails, radroots_nostr::event::Timestamp) -> core::result::Result<radroots_nostr::event::FoodAvailabilityBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_job_feedback(&radroots_nostr::event::Event, &str, core::option::Option<alloc::string::String>, core::option::Option<alloc::vec::Vec<radroots_nostr::tag::Tag>>) -> core::result::Result<radroots_nostr::event::GenericBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_job_result(&radroots_nostr::event::Event, impl core::convert::Into<alloc::string::String>, u64, core::option::Option<alloc::string::String>, core::option::Option<alloc::vec::Vec<radroots_nostr::tag::Tag>>) -> core::result::Result<radroots_nostr::event::GenericBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_nip09_deletion_request(&radroots_event::post::deletion::AuthoredNip09DeletionRequest) -> core::result::Result<radroots_nostr::event::Nip09DeletionRequestBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_nip10_reply(&radroots_event::post::reply::AuthoredNip10Reply) -> core::result::Result<radroots_nostr::event::Nip10ReplyBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_nip22_comment(&radroots_event::post::comment::AuthoredNip22Comment) -> core::result::Result<radroots_nostr::event::Nip22CommentBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_photo_update(&radroots_event::post::AuthoredPhotoUpdate) -> core::result::Result<radroots_nostr::event::PostBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_profile(&radroots_event::profile::AuthoredProfile) -> core::result::Result<radroots_nostr::event::ProfileBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::build_update(&radroots_event::post::AuthoredUpdate) -> core::result::Result<radroots_nostr::event::PostBuilder, radroots_nostr::Error> +pub fn radroots_nostr::event::coordinate_from_nostr(&radroots_nostr::event::Coordinate) -> core::result::Result<radroots_event::id::Nip01Coordinate, radroots_nostr::Error> +pub fn radroots_nostr::event::coordinate_to_nostr(&radroots_event::id::Nip01Coordinate) -> core::result::Result<radroots_nostr::event::Coordinate, radroots_nostr::Error> +pub fn radroots_nostr::event::created_at_u32_saturating(radroots_nostr::event::Timestamp) -> u32 +pub fn radroots_nostr::event::event_created_at_u32_saturating(&radroots_nostr::event::Event) -> u32 +pub fn radroots_nostr::event::from_nostr(&radroots_nostr::event::Event) -> core::result::Result<radroots_event::envelope::EventEnvelope, radroots_event::envelope::EventEnvelopeError> +pub fn radroots_nostr::event::metadata_has_fields(&radroots_nostr::event::Metadata) -> bool +pub fn radroots_nostr::event::pointer_from_nostr(&radroots_nostr::event::Event) -> radroots_event::tag::EventPtr +pub fn radroots_nostr::event::post_filter(core::option::Option<u16>, core::option::Option<u64>) -> radroots_nostr::filter::Filter +pub fn radroots_nostr::event::to_job_feedback_index(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedEvent<radroots_event::social::job_feedback::JobFeedback>, radroots_event_codec::job::error::JobParseError> +pub fn radroots_nostr::event::to_job_feedback_metadata(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::job_feedback::JobFeedback>, radroots_event_codec::job::error::JobParseError> +pub fn radroots_nostr::event::to_job_request_index(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedEvent<radroots_event::social::job_request::JobRequest>, radroots_event_codec::job::error::JobParseError> +pub fn radroots_nostr::event::to_job_request_metadata(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::job_request::JobRequest>, radroots_event_codec::job::error::JobParseError> +pub fn radroots_nostr::event::to_job_result_index(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedEvent<radroots_event::social::job_result::JobResult>, radroots_event_codec::job::error::JobParseError> +pub fn radroots_nostr::event::to_job_result_metadata(&radroots_nostr::event::Event) -> core::result::Result<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::job_result::JobResult>, radroots_event_codec::job::error::JobParseError> +pub fn radroots_nostr::event::to_nostr(&radroots_event::envelope::EventEnvelope) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::Error> +pub fn radroots_nostr::event::to_post_event_metadata(&radroots_nostr::event::Event) -> radroots_event_codec::parsed::RadrootsParsedData<radroots_event_codec::post::decode::LegacyPost> +pub fn radroots_nostr::event::to_profile_event_metadata(&radroots_nostr::event::Event) -> core::option::Option<radroots_event_codec::parsed::RadrootsParsedData<radroots_event_codec::profile::RadrootsProfileData>> +pub fn radroots_nostr::event::verify(&radroots_event::envelope::EventEnvelope) -> radroots_nostr::event::Verification +pub fn radroots_nostr::event::verify_id(&radroots_event::envelope::EventEnvelope) -> radroots_nostr::event::Verification pub type radroots_nostr::event::Coordinate = nostr::nips::nip01::Coordinate pub type radroots_nostr::event::Event = nostr::event::Event pub type radroots_nostr::event::EventId = nostr::event::id::EventId pub type radroots_nostr::event::Kind = nostr::event::kind::Kind pub type radroots_nostr::event::Metadata = nostr::nips::nip01::Metadata pub type radroots_nostr::event::Timestamp = nostr::types::time::Timestamp -pub mod radroots_nostr::event_adapters -pub fn radroots_nostr::event_adapters::to_post_event_metadata(&radroots_nostr::event::Event) -> radroots_event_codec::parsed::RadrootsParsedData<radroots_event_codec::post::decode::LegacyPost> -pub fn radroots_nostr::event_adapters::to_profile_event_metadata(&radroots_nostr::event::Event) -> core::option::Option<radroots_event_codec::parsed::RadrootsParsedData<radroots_event_codec::profile::RadrootsProfileData>> -pub mod radroots_nostr::event_verify -pub enum radroots_nostr::event_verify::RadrootsNostrEventVerification -pub radroots_nostr::event_verify::RadrootsNostrEventVerification::IdMismatch -pub radroots_nostr::event_verify::RadrootsNostrEventVerification::IdVerified -pub radroots_nostr::event_verify::RadrootsNostrEventVerification::MalformedEnvelope -pub radroots_nostr::event_verify::RadrootsNostrEventVerification::SignatureInvalid -pub radroots_nostr::event_verify::RadrootsNostrEventVerification::Verified -pub struct radroots_nostr::event_verify::NostrSignatureVerifier -impl radroots_event::verification::SignatureVerifier for radroots_nostr::event_verify::NostrSignatureVerifier -pub fn radroots_nostr::event_verify::NostrSignatureVerifier::verify_signature(&self, &radroots_event::envelope::EventEnvelope) -> core::result::Result<(), radroots_event::verification::Error> -pub fn radroots_nostr::event_verify::radroots_nostr_verify_event(&radroots_event::envelope::EventEnvelope) -> radroots_nostr::event_verify::RadrootsNostrEventVerification -pub fn radroots_nostr::event_verify::radroots_nostr_verify_event_id(&radroots_event::envelope::EventEnvelope) -> radroots_nostr::event_verify::RadrootsNostrEventVerification -pub mod radroots_nostr::events -pub mod radroots_nostr::events::application_handler -pub struct radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec -pub radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec::extra_tags: alloc::vec::Vec<alloc::vec::Vec<alloc::string::String>> -pub radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec::identifier: core::option::Option<alloc::string::String> -pub radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec::kinds: alloc::vec::Vec<u32> -pub radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec::metadata: core::option::Option<radroots_nostr::event::Metadata> -pub radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec::nostrconnect_url: core::option::Option<alloc::string::String> -pub radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec::relays: alloc::vec::Vec<alloc::string::String> -impl radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec -pub fn radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec::new(alloc::vec::Vec<u32>) -> Self -pub fn radroots_nostr::events::application_handler::radroots_nostr_build_application_handler_event(&radroots_nostr::events::application_handler::RadrootsNostrApplicationHandlerSpec) -> core::result::Result<radroots_nostr::types::RadrootsNostrGenericEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::application_handler::radroots_nostr_metadata_has_fields(&radroots_nostr::event::Metadata) -> bool -pub mod radroots_nostr::events::comment -pub struct radroots_nostr::events::comment::RadrootsNostrNip22CommentEventBuilder -impl radroots_nostr::events::comment::RadrootsNostrNip22CommentEventBuilder -pub fn radroots_nostr::events::comment::RadrootsNostrNip22CommentEventBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self -pub fn radroots_nostr::events::comment::RadrootsNostrNip22CommentEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::comment::radroots_nostr_build_nip22_comment_event(&radroots_event::post::comment::AuthoredNip22Comment) -> core::result::Result<radroots_nostr::events::comment::RadrootsNostrNip22CommentEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub mod radroots_nostr::events::deletion -pub struct radroots_nostr::events::deletion::RadrootsNostrNip09DeletionRequestEventBuilder -impl radroots_nostr::events::deletion::RadrootsNostrNip09DeletionRequestEventBuilder -pub fn radroots_nostr::events::deletion::RadrootsNostrNip09DeletionRequestEventBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self -pub fn radroots_nostr::events::deletion::RadrootsNostrNip09DeletionRequestEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::deletion::radroots_nostr_build_nip09_deletion_request_event(&radroots_event::post::deletion::AuthoredNip09DeletionRequest) -> core::result::Result<radroots_nostr::events::deletion::RadrootsNostrNip09DeletionRequestEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub mod radroots_nostr::events::food_availability -pub struct radroots_nostr::events::food_availability::RadrootsNostrFoodAvailabilityEventBuilder -impl radroots_nostr::events::food_availability::RadrootsNostrFoodAvailabilityEventBuilder -pub fn radroots_nostr::events::food_availability::RadrootsNostrFoodAvailabilityEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::food_availability::radroots_nostr_build_food_availability_event(&radroots_event::food::availability::FoodAvailabilityDetails, radroots_nostr::event::Timestamp) -> core::result::Result<radroots_nostr::events::food_availability::RadrootsNostrFoodAvailabilityEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub mod radroots_nostr::events::jobs -pub fn radroots_nostr::events::jobs::radroots_nostr_build_event_job_feedback(&radroots_nostr::event::Event, &str, core::option::Option<alloc::string::String>, core::option::Option<alloc::vec::Vec<radroots_nostr::tag::Tag>>) -> core::result::Result<radroots_nostr::types::RadrootsNostrGenericEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::jobs::radroots_nostr_build_event_job_result(&radroots_nostr::event::Event, impl core::convert::Into<alloc::string::String>, u64, core::option::Option<alloc::string::String>, core::option::Option<alloc::vec::Vec<radroots_nostr::tag::Tag>>) -> core::result::Result<radroots_nostr::types::RadrootsNostrGenericEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub mod radroots_nostr::events::metadata -pub struct radroots_nostr::events::metadata::RadrootsNostrProfileEventBuilder -impl radroots_nostr::events::metadata::RadrootsNostrProfileEventBuilder -pub fn radroots_nostr::events::metadata::RadrootsNostrProfileEventBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self -pub fn radroots_nostr::events::metadata::RadrootsNostrProfileEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::metadata::radroots_nostr_build_profile_event(&radroots_event::profile::AuthoredProfile) -> core::result::Result<radroots_nostr::events::metadata::RadrootsNostrProfileEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub mod radroots_nostr::events::post -pub struct radroots_nostr::events::post::RadrootsNostrPostEventBuilder -impl radroots_nostr::events::post::RadrootsNostrPostEventBuilder -pub fn radroots_nostr::events::post::RadrootsNostrPostEventBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self -pub fn radroots_nostr::events::post::RadrootsNostrPostEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::post::radroots_nostr_build_ask_event(&radroots_event::post::AuthoredAsk) -> core::result::Result<radroots_nostr::events::post::RadrootsNostrPostEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::post::radroots_nostr_build_photo_update_event(&radroots_event::post::AuthoredPhotoUpdate) -> core::result::Result<radroots_nostr::events::post::RadrootsNostrPostEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::post::radroots_nostr_build_update_event(&radroots_event::post::AuthoredUpdate) -> core::result::Result<radroots_nostr::events::post::RadrootsNostrPostEventBuilder, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::post::radroots_nostr_post_events_filter(core::option::Option<u16>, core::option::Option<u64>) -> radroots_nostr::filter::Filter -pub mod radroots_nostr::events::reply -pub struct radroots_nostr::events::reply::RadrootsNostrNip10ReplyEventBuilder -impl radroots_nostr::events::reply::RadrootsNostrNip10ReplyEventBuilder -pub fn radroots_nostr::events::reply::RadrootsNostrNip10ReplyEventBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self -pub fn radroots_nostr::events::reply::RadrootsNostrNip10ReplyEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::events::reply::radroots_nostr_build_nip10_reply_event(&radroots_event::post::reply::AuthoredNip10Reply) -> core::result::Result<radroots_nostr::events::reply::RadrootsNostrNip10ReplyEventBuilder, radroots_nostr::error::RadrootsNostrError> pub mod radroots_nostr::filter -pub fn radroots_nostr::filter::radroots_nostr_filter_kind(u16) -> radroots_nostr::filter::Filter -pub fn radroots_nostr::filter::radroots_nostr_filter_new_events(radroots_nostr::filter::Filter) -> radroots_nostr::filter::Filter -pub fn radroots_nostr::filter::radroots_nostr_filter_tag(radroots_nostr::filter::Filter, &str, alloc::vec::Vec<alloc::string::String>) -> core::result::Result<radroots_nostr::filter::Filter, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::filter::radroots_nostr_kind(u16) -> radroots_nostr::event::Kind +pub fn radroots_nostr::filter::for_kind(u16) -> radroots_nostr::filter::Filter +pub fn radroots_nostr::filter::kind(u16) -> radroots_nostr::event::Kind +pub fn radroots_nostr::filter::since_now(radroots_nostr::filter::Filter) -> radroots_nostr::filter::Filter +pub fn radroots_nostr::filter::with_tag(radroots_nostr::filter::Filter, &str, alloc::vec::Vec<alloc::string::String>) -> core::result::Result<radroots_nostr::filter::Filter, radroots_nostr::Error> pub type radroots_nostr::filter::Filter = nostr::filter::Filter -pub mod radroots_nostr::job_adapter -pub struct radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a> -impl<'a> radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a> -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a>::new(&'a radroots_nostr::event::Event) -> Self -impl radroots_event_codec::job::traits::JobEventLike for radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_> -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_>::raw_author(&self) -> alloc::string::String -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_>::raw_content(&self) -> alloc::string::String -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_>::raw_id(&self) -> alloc::string::String -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_>::raw_kind(&self) -> u32 -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_>::raw_published_at(&self) -> u64 -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_>::raw_sig(&self) -> alloc::string::String -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'_>::raw_tags(&self) -> alloc::vec::Vec<alloc::vec::Vec<alloc::string::String>> -impl<'a> radroots_event_codec::job::traits::JobEventBorrow<'a> for radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a> -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a>::raw_author(&'a self) -> alloc::string::String -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a>::raw_content(&'a self) -> &'a str -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a>::raw_id(&'a self) -> alloc::string::String -pub fn radroots_nostr::job_adapter::RadrootsNostrEventAdapter<'a>::raw_kind(&'a self) -> u32 pub mod radroots_nostr::key pub enum radroots_nostr::key::Nip49KeySecurity pub radroots_nostr::key::Nip49KeySecurity::Medium @@ -248,120 +190,98 @@ pub fn radroots_nostr::key::Nip49Options::default() -> Self pub struct radroots_nostr::key::SecretKey impl radroots_nostr::key::SecretKey pub fn radroots_nostr::key::SecretKey::generate() -> Self -pub fn radroots_nostr::key::SecretKey::parse(&str) -> core::result::Result<Self, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::SecretKey::public_key(&self) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::error::RadrootsNostrError> +pub fn radroots_nostr::key::SecretKey::parse(&str) -> core::result::Result<Self, radroots_nostr::Error> +pub fn radroots_nostr::key::SecretKey::public_key(&self) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::Error> impl core::fmt::Debug for radroots_nostr::key::SecretKey pub fn radroots_nostr::key::SecretKey::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub fn radroots_nostr::key::decrypt_secret_key_nip49(&str, &str) -> core::result::Result<radroots_nostr::key::SecretKey, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::encrypt_secret_key_nip49(&radroots_nostr::key::SecretKey, &str) -> core::result::Result<alloc::string::String, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::encrypt_secret_key_nip49_with_options(&radroots_nostr::key::SecretKey, &str, radroots_nostr::key::Nip49Options) -> core::result::Result<alloc::string::String, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::parse_public_key(&str) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::parse_secret_key(&str) -> core::result::Result<radroots_nostr::key::SecretKey, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::public_key_from_nostr(nostr::key::public_key::PublicKey) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::public_key_from_npub(&str) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::public_key_to_nostr(radroots_identity::key::PublicKey) -> core::result::Result<nostr::key::public_key::PublicKey, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::key::public_key_to_npub(radroots_identity::key::PublicKey) -> core::result::Result<alloc::string::String, radroots_nostr::error::RadrootsNostrError> +pub fn radroots_nostr::key::decrypt_secret_key_nip49(&str, &str) -> core::result::Result<radroots_nostr::key::SecretKey, radroots_nostr::Error> +pub fn radroots_nostr::key::encrypt_secret_key_nip49(&radroots_nostr::key::SecretKey, &str) -> core::result::Result<alloc::string::String, radroots_nostr::Error> +pub fn radroots_nostr::key::encrypt_secret_key_nip49_with_options(&radroots_nostr::key::SecretKey, &str, radroots_nostr::key::Nip49Options) -> core::result::Result<alloc::string::String, radroots_nostr::Error> +pub fn radroots_nostr::key::parse_public_key(&str) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::Error> +pub fn radroots_nostr::key::parse_secret_key(&str) -> core::result::Result<radroots_nostr::key::SecretKey, radroots_nostr::Error> +pub fn radroots_nostr::key::public_key_from_nostr(nostr::key::public_key::PublicKey) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::Error> +pub fn radroots_nostr::key::public_key_from_npub(&str) -> core::result::Result<radroots_identity::key::PublicKey, radroots_nostr::Error> +pub fn radroots_nostr::key::public_key_to_nostr(radroots_identity::key::PublicKey) -> core::result::Result<nostr::key::public_key::PublicKey, radroots_nostr::Error> +pub fn radroots_nostr::key::public_key_to_npub(radroots_identity::key::PublicKey) -> core::result::Result<alloc::string::String, radroots_nostr::Error> pub fn radroots_nostr::key::secret_key_to_nsec(&radroots_nostr::key::SecretKey) -> alloc::string::String pub mod radroots_nostr::nip17 -#[non_exhaustive] pub enum radroots_nostr::nip17::RadrootsNip17Error -pub radroots_nostr::nip17::RadrootsNip17Error::GiftWrap -pub radroots_nostr::nip17::RadrootsNip17Error::InvalidRecipient -pub radroots_nostr::nip17::RadrootsNip17Error::MessageDecode -pub radroots_nostr::nip17::RadrootsNip17Error::MessageEncode -pub radroots_nostr::nip17::RadrootsNip17Error::Signer -pub radroots_nostr::nip17::RadrootsNip17Error::UnsupportedRumorKind -pub radroots_nostr::nip17::RadrootsNip17Error::UnsupportedRumorKind::kind: u32 -impl radroots_nostr::nip17::RadrootsNip17Error -pub const fn radroots_nostr::nip17::RadrootsNip17Error::code(&self) -> &'static str -impl core::convert::From<nostr::event::builder::Error> for radroots_nostr::nip17::RadrootsNip17Error -pub fn radroots_nostr::nip17::RadrootsNip17Error::from(nostr::event::builder::Error) -> Self -impl core::convert::From<nostr::key::Error> for radroots_nostr::nip17::RadrootsNip17Error -pub fn radroots_nostr::nip17::RadrootsNip17Error::from(nostr::key::Error) -> Self -impl core::convert::From<nostr::nips::nip59::Error> for radroots_nostr::nip17::RadrootsNip17Error -pub fn radroots_nostr::nip17::RadrootsNip17Error::from(nostr::nips::nip59::Error) -> Self -impl core::convert::From<nostr::signer::SignerError> for radroots_nostr::nip17::RadrootsNip17Error -pub fn radroots_nostr::nip17::RadrootsNip17Error::from(nostr::signer::SignerError) -> Self -impl core::convert::From<radroots_event_codec::error::EventEncodeError> for radroots_nostr::nip17::RadrootsNip17Error -pub fn radroots_nostr::nip17::RadrootsNip17Error::from(radroots_event_codec::error::EventEncodeError) -> Self -impl core::convert::From<radroots_event_codec::error::EventParseError> for radroots_nostr::nip17::RadrootsNip17Error -pub fn radroots_nostr::nip17::RadrootsNip17Error::from(radroots_event_codec::error::EventParseError) -> Self -impl core::error::Error for radroots_nostr::nip17::RadrootsNip17Error -impl core::fmt::Display for radroots_nostr::nip17::RadrootsNip17Error -pub fn radroots_nostr::nip17::RadrootsNip17Error::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub enum radroots_nostr::nip17::RadrootsNip17Rumor -pub radroots_nostr::nip17::RadrootsNip17Rumor::Message(radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::message::Message>) -pub radroots_nostr::nip17::RadrootsNip17Rumor::MessageFile(alloc::boxed::Box<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::message_file::MessageFile>>) -impl core::fmt::Debug for radroots_nostr::nip17::RadrootsNip17Rumor -pub fn radroots_nostr::nip17::RadrootsNip17Rumor::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result -pub struct radroots_nostr::nip17::RadrootsNip17WrapOptions -pub radroots_nostr::nip17::RadrootsNip17WrapOptions::gift_wrap_tags: alloc::vec::Vec<alloc::vec::Vec<alloc::string::String>> -pub radroots_nostr::nip17::RadrootsNip17WrapOptions::include_sender: bool -pub radroots_nostr::nip17::RadrootsNip17WrapOptions::rumor_created_at: core::option::Option<u64> -impl core::default::Default for radroots_nostr::nip17::RadrootsNip17WrapOptions -pub fn radroots_nostr::nip17::RadrootsNip17WrapOptions::default() -> Self -pub async fn radroots_nostr::nip17::radroots_nostr_unwrap_gift_wrap<T>(&T, &nostr::event::Event) -> core::result::Result<radroots_nostr::nip17::RadrootsNip17Rumor, radroots_nostr::nip17::RadrootsNip17Error> where T: nostr::signer::NostrSigner -pub async fn radroots_nostr::nip17::radroots_nostr_wrap_message<T>(&T, &radroots_event::social::message::Message, radroots_nostr::nip17::RadrootsNip17WrapOptions) -> core::result::Result<alloc::vec::Vec<nostr::event::Event>, radroots_nostr::nip17::RadrootsNip17Error> where T: nostr::signer::NostrSigner -pub async fn radroots_nostr::nip17::radroots_nostr_wrap_message_file<T>(&T, &radroots_event::social::message_file::MessageFile, radroots_nostr::nip17::RadrootsNip17WrapOptions) -> core::result::Result<alloc::vec::Vec<nostr::event::Event>, radroots_nostr::nip17::RadrootsNip17Error> where T: nostr::signer::NostrSigner +#[non_exhaustive] pub enum radroots_nostr::nip17::Error +pub radroots_nostr::nip17::Error::GiftWrap +pub radroots_nostr::nip17::Error::InvalidRecipient +pub radroots_nostr::nip17::Error::MessageDecode +pub radroots_nostr::nip17::Error::MessageEncode +pub radroots_nostr::nip17::Error::Signer +pub radroots_nostr::nip17::Error::UnsupportedRumorKind +pub radroots_nostr::nip17::Error::UnsupportedRumorKind::kind: u32 +impl radroots_nostr::nip17::Error +pub const fn radroots_nostr::nip17::Error::code(&self) -> &'static str +impl core::convert::From<nostr::event::builder::Error> for radroots_nostr::nip17::Error +pub fn radroots_nostr::nip17::Error::from(nostr::event::builder::Error) -> Self +impl core::convert::From<nostr::key::Error> for radroots_nostr::nip17::Error +pub fn radroots_nostr::nip17::Error::from(nostr::key::Error) -> Self +impl core::convert::From<nostr::nips::nip59::Error> for radroots_nostr::nip17::Error +pub fn radroots_nostr::nip17::Error::from(nostr::nips::nip59::Error) -> Self +impl core::convert::From<nostr::signer::SignerError> for radroots_nostr::nip17::Error +pub fn radroots_nostr::nip17::Error::from(nostr::signer::SignerError) -> Self +impl core::convert::From<radroots_event_codec::error::EventEncodeError> for radroots_nostr::nip17::Error +pub fn radroots_nostr::nip17::Error::from(radroots_event_codec::error::EventEncodeError) -> Self +impl core::convert::From<radroots_event_codec::error::EventParseError> for radroots_nostr::nip17::Error +pub fn radroots_nostr::nip17::Error::from(radroots_event_codec::error::EventParseError) -> Self +impl core::error::Error for radroots_nostr::nip17::Error +impl core::fmt::Display for radroots_nostr::nip17::Error +pub fn radroots_nostr::nip17::Error::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub enum radroots_nostr::nip17::Rumor +pub radroots_nostr::nip17::Rumor::Message(radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::message::Message>) +pub radroots_nostr::nip17::Rumor::MessageFile(alloc::boxed::Box<radroots_event_codec::parsed::RadrootsParsedData<radroots_event::social::message_file::MessageFile>>) +impl core::fmt::Debug for radroots_nostr::nip17::Rumor +pub fn radroots_nostr::nip17::Rumor::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result +pub struct radroots_nostr::nip17::WrapOptions +impl radroots_nostr::nip17::WrapOptions +pub fn radroots_nostr::nip17::WrapOptions::gift_wrap_tags(&self) -> &[alloc::vec::Vec<alloc::string::String>] +pub fn radroots_nostr::nip17::WrapOptions::include_sender(self, bool) -> Self +pub const fn radroots_nostr::nip17::WrapOptions::includes_sender(&self) -> bool +pub const fn radroots_nostr::nip17::WrapOptions::rumor_created_at(&self) -> core::option::Option<u64> +pub fn radroots_nostr::nip17::WrapOptions::with_gift_wrap_tags(self, alloc::vec::Vec<alloc::vec::Vec<alloc::string::String>>) -> Self +pub fn radroots_nostr::nip17::WrapOptions::with_rumor_created_at(self, u64) -> Self +impl core::default::Default for radroots_nostr::nip17::WrapOptions +pub fn radroots_nostr::nip17::WrapOptions::default() -> Self +pub async fn radroots_nostr::nip17::unwrap_gift_wrap<T>(&T, &nostr::event::Event) -> core::result::Result<radroots_nostr::nip17::Rumor, radroots_nostr::nip17::Error> where T: nostr::signer::NostrSigner +pub async fn radroots_nostr::nip17::wrap_message<T>(&T, &radroots_event::social::message::Message, radroots_nostr::nip17::WrapOptions) -> core::result::Result<alloc::vec::Vec<nostr::event::Event>, radroots_nostr::nip17::Error> where T: nostr::signer::NostrSigner +pub async fn radroots_nostr::nip17::wrap_message_file<T>(&T, &radroots_event::social::message_file::MessageFile, radroots_nostr::nip17::WrapOptions) -> core::result::Result<alloc::vec::Vec<nostr::event::Event>, radroots_nostr::nip17::Error> where T: nostr::signer::NostrSigner pub mod radroots_nostr::signing pub struct radroots_nostr::signing::LocalSigner impl radroots_nostr::signing::LocalSigner -pub fn radroots_nostr::signing::LocalSigner::generate() -> core::result::Result<Self, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::signing::LocalSigner::new(radroots_nostr::key::SecretKey) -> core::result::Result<Self, radroots_nostr::error::RadrootsNostrError> +pub fn radroots_nostr::signing::LocalSigner::generate() -> core::result::Result<Self, radroots_nostr::Error> +pub fn radroots_nostr::signing::LocalSigner::new(radroots_nostr::key::SecretKey) -> core::result::Result<Self, radroots_nostr::Error> pub const fn radroots_nostr::signing::LocalSigner::public_key(&self) -> radroots_identity::key::PublicKey impl core::fmt::Debug for radroots_nostr::signing::LocalSigner pub fn radroots_nostr::signing::LocalSigner::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl radroots_signing::signer::Signer for radroots_nostr::signing::LocalSigner pub fn radroots_nostr::signing::LocalSigner::sign(&self, radroots_signing::request::SignRequest) -> radroots_signing::signer::BoxFuture<'_, core::result::Result<radroots_signing::receipt::SignReceipt, radroots_signing::error::Error>> pub fn radroots_nostr::signing::LocalSigner::status(&self) -> radroots_signing::signer::BoxFuture<'_, core::result::Result<radroots_signing::status::SignerStatus, radroots_signing::error::Error>> +pub fn radroots_nostr::signing::sign_frozen_draft(&nostr::key::Keys, &radroots_event::draft::EventDraft) -> core::result::Result<radroots_event::draft::SignedEvent, radroots_nostr::Error> pub mod radroots_nostr::tag -pub fn radroots_nostr::tag::from_parts(alloc::vec::Vec<alloc::string::String>) -> core::result::Result<radroots_nostr::tag::Tag, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::tag::radroots_nostr_tag_at_value(&radroots_nostr::tag::Tag, usize) -> core::option::Option<alloc::string::String> -pub fn radroots_nostr::tag::radroots_nostr_tag_first_value(&radroots_nostr::tag::Tag, &str) -> core::option::Option<alloc::string::String> -pub fn radroots_nostr::tag::radroots_nostr_tag_match_geohash(&radroots_nostr::tag::Tag) -> core::option::Option<alloc::string::String> -pub fn radroots_nostr::tag::radroots_nostr_tag_match_l(&radroots_nostr::tag::Tag) -> core::option::Option<(&str, f64)> -pub fn radroots_nostr::tag::radroots_nostr_tag_match_location(&radroots_nostr::tag::Tag) -> core::option::Option<(&str, &str, &str)> -pub fn radroots_nostr::tag::radroots_nostr_tag_match_summary(&radroots_nostr::tag::Tag) -> core::option::Option<alloc::string::String> -pub fn radroots_nostr::tag::radroots_nostr_tag_match_title(&radroots_nostr::tag::Tag) -> core::option::Option<alloc::string::String> -pub fn radroots_nostr::tag::radroots_nostr_tag_relays_parse(&radroots_nostr::tag::Tag) -> core::option::Option<&alloc::vec::Vec<radroots_nostr::types::RadrootsNostrRelayUrl>> -pub fn radroots_nostr::tag::radroots_nostr_tag_slice(&radroots_nostr::tag::Tag, usize) -> core::option::Option<alloc::vec::Vec<alloc::string::String>> -pub fn radroots_nostr::tag::radroots_nostr_tags_match(&radroots_nostr::tag::Tag) -> core::option::Option<(&str, &[alloc::string::String])> -pub fn radroots_nostr::tag::radroots_nostr_tags_resolve(&radroots_nostr::event::Event, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<alloc::vec::Vec<radroots_nostr::tag::Tag>, radroots_nostr::error::RadrootsNostrTagsResolveError> +pub enum radroots_nostr::tag::ResolveError +pub radroots_nostr::tag::ResolveError::DecryptionError(alloc::string::String) +pub radroots_nostr::tag::ResolveError::MissingPTag(alloc::boxed::Box<nostr::event::Event>) +pub radroots_nostr::tag::ResolveError::NotRecipient +pub radroots_nostr::tag::ResolveError::ParseError(serde_json::error::Error) +pub fn radroots_nostr::tag::first_value(&radroots_nostr::tag::Tag, &str) -> core::option::Option<alloc::string::String> +pub fn radroots_nostr::tag::from_parts(alloc::vec::Vec<alloc::string::String>) -> core::result::Result<radroots_nostr::tag::Tag, radroots_nostr::Error> +pub fn radroots_nostr::tag::match_geohash(&radroots_nostr::tag::Tag) -> core::option::Option<alloc::string::String> +pub fn radroots_nostr::tag::match_location(&radroots_nostr::tag::Tag) -> core::option::Option<(&str, &str, &str)> +pub fn radroots_nostr::tag::match_location_coordinate(&radroots_nostr::tag::Tag) -> core::option::Option<(&str, f64)> +pub fn radroots_nostr::tag::match_parts(&radroots_nostr::tag::Tag) -> core::option::Option<(&str, &[alloc::string::String])> +pub fn radroots_nostr::tag::match_summary(&radroots_nostr::tag::Tag) -> core::option::Option<alloc::string::String> +pub fn radroots_nostr::tag::match_title(&radroots_nostr::tag::Tag) -> core::option::Option<alloc::string::String> +pub fn radroots_nostr::tag::relay_urls(&radroots_nostr::tag::Tag) -> core::option::Option<&alloc::vec::Vec<nostr::types::url::RelayUrl>> +pub fn radroots_nostr::tag::resolve(&radroots_nostr::event::Event, &nostr::key::Keys) -> core::result::Result<alloc::vec::Vec<radroots_nostr::tag::Tag>, radroots_nostr::tag::ResolveError> pub fn radroots_nostr::tag::to_parts(&radroots_nostr::tag::Tag) -> alloc::vec::Vec<alloc::string::String> +pub fn radroots_nostr::tag::value_at(&radroots_nostr::tag::Tag, usize) -> core::option::Option<alloc::string::String> +pub fn radroots_nostr::tag::values_from(&radroots_nostr::tag::Tag, usize) -> core::option::Option<alloc::vec::Vec<alloc::string::String>> pub type radroots_nostr::tag::Tag = nostr::event::tag::Tag pub type radroots_nostr::tag::TagKind<'a> = nostr::event::tag::kind::TagKind<'a> pub type radroots_nostr::tag::TagStandard = nostr::event::tag::standard::TagStandard -pub mod radroots_nostr::types -pub use radroots_nostr::types::RadrootsNostrFromBech32 -pub use radroots_nostr::types::RadrootsNostrSecp256k1SecretKey -pub use radroots_nostr::types::RadrootsNostrToBech32 -pub struct radroots_nostr::types::RadrootsNostrExternalSigningRequest -impl radroots_nostr::types::RadrootsNostrExternalSigningRequest -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::complete(self, radroots_nostr::event::Event) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::expected_event_id(&self) -> radroots_nostr::event::EventId -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::expected_public_key(&self) -> radroots_nostr::types::RadrootsNostrPublicKey -impl serde_core::ser::Serialize for radroots_nostr::types::RadrootsNostrExternalSigningRequest -pub fn radroots_nostr::types::RadrootsNostrExternalSigningRequest::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer -pub struct radroots_nostr::types::RadrootsNostrGenericEventBuilder -impl radroots_nostr::types::RadrootsNostrGenericEventBuilder -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::allow_self_tagging(self) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::custom_created_at(self, radroots_nostr::event::Timestamp) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::dedup_tags(self) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::into_external_signing_request(self, radroots_nostr::types::RadrootsNostrPublicKey) -> core::result::Result<radroots_nostr::types::RadrootsNostrExternalSigningRequest, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::new(radroots_nostr::event::Kind, impl core::convert::Into<alloc::string::String>) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::pow(self, u8) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::sign_with_keys(self, &radroots_nostr::types::RadrootsNostrKeys) -> core::result::Result<radroots_nostr::event::Event, radroots_nostr::error::RadrootsNostrError> -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::tag(self, radroots_nostr::tag::Tag) -> Self -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::tags<I>(self, I) -> Self where I: core::iter::traits::collect::IntoIterator<Item = radroots_nostr::tag::Tag> -pub fn radroots_nostr::types::RadrootsNostrGenericEventBuilder::text_note(impl core::convert::Into<alloc::string::String>) -> Self -pub type radroots_nostr::types::RadrootsNostrKeys = nostr::key::Keys -pub type radroots_nostr::types::RadrootsNostrPublicKey = nostr::key::public_key::PublicKey -pub type radroots_nostr::types::RadrootsNostrRelayUrl = nostr::types::url::RelayUrl -pub type radroots_nostr::types::RadrootsNostrSecretKey = nostr::key::secret_key::SecretKey -pub type radroots_nostr::types::RadrootsNostrSubscriptionId = nostr::message::SubscriptionId -pub type radroots_nostr::types::RadrootsNostrUrl = url::Url -pub mod radroots_nostr::util -pub fn radroots_nostr::util::created_at_u32_saturating(radroots_nostr::event::Timestamp) -> u32 -pub fn radroots_nostr::util::event_created_at_u32_saturating(&radroots_nostr::event::Event) -> u32 pub enum radroots_nostr::Error pub radroots_nostr::Error::CoordinateConversion pub radroots_nostr::Error::DraftError(radroots_event::draft::DraftError) @@ -400,9 +320,9 @@ pub radroots_nostr::Error::SignedEvent(radroots_event::draft::SignedEventError) pub radroots_nostr::Error::TagConversion pub radroots_nostr::Error::TypedAuthoringRequired pub radroots_nostr::Error::TypedAuthoringRequired::kind: u16 -impl core::convert::From<nostr::event::builder::Error> for radroots_nostr::error::RadrootsNostrError -pub fn radroots_nostr::error::RadrootsNostrError::from(nostr::event::builder::Error) -> Self -impl core::convert::From<nostr::event::error::Error> for radroots_nostr::error::RadrootsNostrError -pub fn radroots_nostr::error::RadrootsNostrError::from(nostr::event::error::Error) -> Self -impl core::convert::From<nostr::key::Error> for radroots_nostr::error::RadrootsNostrError -pub fn radroots_nostr::error::RadrootsNostrError::from(nostr::key::Error) -> Self +impl core::convert::From<nostr::event::builder::Error> for radroots_nostr::Error +pub fn radroots_nostr::Error::from(nostr::event::builder::Error) -> Self +impl core::convert::From<nostr::event::error::Error> for radroots_nostr::Error +pub fn radroots_nostr::Error::from(nostr::event::error::Error) -> Self +impl core::convert::From<nostr::key::Error> for radroots_nostr::Error +pub fn radroots_nostr::Error::from(nostr::key::Error) -> Self diff --git a/tools/xtask/src/contract.rs b/tools/xtask/src/contract.rs @@ -1903,8 +1903,8 @@ const REPLY_WITNESSES: [EventBoundarySourceWitness; 5] = [ EventBoundarySourceWitness { relative_path: "crates/nostr/src/events/reply.rs", required_fragments: &[ - "pub struct RadrootsNostrNip10ReplyEventBuilder", - "pub fn radroots_nostr_build_nip10_reply_event", + "pub struct Nip10ReplyBuilder", + "pub fn build_nip10_reply_event", ], }, ]; @@ -1943,8 +1943,8 @@ const COMMENT_WITNESSES: [EventBoundarySourceWitness; 7] = [ EventBoundarySourceWitness { relative_path: "crates/nostr/src/events/comment.rs", required_fragments: &[ - "pub struct RadrootsNostrNip22CommentEventBuilder", - "pub fn radroots_nostr_build_nip22_comment_event", + "pub struct Nip22CommentBuilder", + "pub fn build_nip22_comment_event", ], }, EventBoundarySourceWitness { @@ -1990,8 +1990,8 @@ const DELETION_WITNESSES: [EventBoundarySourceWitness; 7] = [ EventBoundarySourceWitness { relative_path: "crates/nostr/src/events/deletion.rs", required_fragments: &[ - "pub struct RadrootsNostrNip09DeletionRequestEventBuilder", - "pub fn radroots_nostr_build_nip09_deletion_request_event", + "pub struct Nip09DeletionRequestBuilder", + "pub fn build_nip09_deletion_request_event", ], }, EventBoundarySourceWitness { @@ -2055,10 +2055,7 @@ const MESSAGE_WITNESSES: [EventBoundarySourceWitness; 4] = [ }, EventBoundarySourceWitness { relative_path: "crates/nostr/src/nip17.rs", - required_fragments: &[ - "pub async fn radroots_nostr_wrap_message<T>(", - "KIND_MESSAGE =>", - ], + required_fragments: &["pub async fn wrap_message<T>(", "KIND_MESSAGE =>"], }, EventBoundarySourceWitness { relative_path: "crates/nostr/src/lib.rs", @@ -2077,10 +2074,7 @@ const MESSAGE_FILE_WITNESSES: [EventBoundarySourceWitness; 4] = [ }, EventBoundarySourceWitness { relative_path: "crates/nostr/src/nip17.rs", - required_fragments: &[ - "pub async fn radroots_nostr_wrap_message_file<T>(", - "KIND_MESSAGE_FILE =>", - ], + required_fragments: &["pub async fn wrap_message_file<T>(", "KIND_MESSAGE_FILE =>"], }, EventBoundarySourceWitness { relative_path: "crates/nostr/src/lib.rs", @@ -2099,7 +2093,7 @@ const GIFT_WRAP_WITNESSES: [EventBoundarySourceWitness; 4] = [ }, EventBoundarySourceWitness { relative_path: "crates/nostr/src/nip17.rs", - required_fragments: &["pub async fn radroots_nostr_unwrap_gift_wrap<T>("], + required_fragments: &["pub async fn unwrap_gift_wrap<T>("], }, EventBoundarySourceWitness { relative_path: "crates/nostr/src/lib.rs", @@ -2227,7 +2221,7 @@ const APP_HANDLER_WITNESSES: [EventBoundarySourceWitness; 2] = [ }, EventBoundarySourceWitness { relative_path: "crates/nostr/src/events/application_handler.rs", - required_fragments: &["pub fn radroots_nostr_build_application_handler_event("], + required_fragments: &["pub fn build_application_handler_event("], }, ]; @@ -2647,7 +2641,7 @@ const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 44] = [ EventBoundaryExpectation { domain: "reply", kind: "1", - radroots_type: "AuthoredNip10Reply / RadrootsInboundNip10ReplyProjection / RadrootsAdmittedNip10ReplyEvent / RadrootsNostrNip10ReplyEventBuilder", + radroots_type: "AuthoredNip10Reply / RadrootsInboundNip10ReplyProjection / RadrootsAdmittedNip10ReplyEvent / Nip10ReplyBuilder", rpc_methods: &[ "social.reply.build_authored_draft", "social.reply.project_verified_event", @@ -2658,7 +2652,7 @@ const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 44] = [ EventBoundaryExpectation { domain: "comment", kind: "1111", - radroots_type: "AuthoredNip22Comment / RadrootsInboundNip22CommentProjection / RadrootsAdmittedNip22CommentEvent / RadrootsNostrNip22CommentEventBuilder", + radroots_type: "AuthoredNip22Comment / RadrootsInboundNip22CommentProjection / RadrootsAdmittedNip22CommentEvent / Nip22CommentBuilder", rpc_methods: &[ "social.comment.build_authored_draft", "social.comment.project_verified_event", @@ -2669,7 +2663,7 @@ const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 44] = [ EventBoundaryExpectation { domain: "deletion_request", kind: "5", - radroots_type: "AuthoredNip09DeletionRequest / RadrootsInboundNip09DeletionProjection / RadrootsAdmittedNip09DeletionRequestEvent / RadrootsNip09SuppressionDecision / RadrootsNostrNip09DeletionRequestEventBuilder", + radroots_type: "AuthoredNip09DeletionRequest / RadrootsInboundNip09DeletionProjection / RadrootsAdmittedNip09DeletionRequestEvent / RadrootsNip09SuppressionDecision / Nip09DeletionRequestBuilder", rpc_methods: &[ "social.deletion_request.build_authored_draft", "social.deletion_request.project_verified_event", @@ -2947,7 +2941,7 @@ const CANONICAL_EVENT_BOUNDARY_EXPECTATIONS: [EventBoundaryExpectation; 44] = [ EventBoundaryExpectation { domain: "food_availability", kind: "30402", - radroots_type: "FoodAvailabilityDetails / RadrootsInboundFoodAvailabilityProjection / RadrootsAdmittedFoodAvailabilityEvent / RadrootsNostrFoodAvailabilityEventBuilder", + radroots_type: "FoodAvailabilityDetails / RadrootsInboundFoodAvailabilityProjection / RadrootsAdmittedFoodAvailabilityEvent / FoodAvailabilityBuilder", rpc_methods: &[ "food_availability.build_authored_draft", "food_availability.project_verified_event",