tangle_indexer


git clone https://radroots.dev/git/tangle_indexer.git
Log | Files | Refs | Submodules | LICENSE

commit 4e943e9b75ec9de169918ca408124dc2dd287131
parent 4fd126a77ecf41b070031eaf41e61022428978b9
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Wed, 20 Aug 2025 15:16:40 -0700

Edit `indexer` migrating crates to `events` and `events-indexed` and updating events indexes for `manifest/shard-metadata` types. Edit `app` migrating to crate-scoped bindings, adding theme.css and refactoring build loaders to use common `_env` indexer base url.

Diffstat:
MCargo.lock | 46++++++++++++++++++++++++++++++++++++++++++----
Mapp/package.json | 5++++-
Mapp/src/app.css | 9++++++++-
Mapp/src/routes/(market)/(listing)/[0=country]/+page.ts | 18+++++++++++-------
Mapp/src/routes/(market)/(profile)/[0=nip05]/+page.ts | 5+++--
Mapp/src/routes/(market)/(profile)/profile/+error.svelte | 8++++----
Mapp/src/routes/(market)/(profile)/profile/[0=npub]/+page.ts | 2+-
Mapp/src/routes/(market)/(profile)/profile/[0=public_key]/+page.ts | 2+-
Mapp/src/routes/+layout.svelte | 18++++++++++++++++--
Mapp/src/routes/+page.ts | 8+++++---
Aapp/theme.css | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/indexer/Cargo.toml | 3++-
Mcrates/indexer/config.toml | 2+-
Mcrates/indexer/src/audit.rs | 4++--
Mcrates/indexer/src/config.rs | 4++--
Mcrates/indexer/src/domain/events/listing.rs | 202+++++++------------------------------------------------------------------------
Mcrates/indexer/src/domain/events/profile.rs | 10++++------
Mcrates/indexer/src/domain/indexer/models/listing.rs | 33+++++++++++++++------------------
Mcrates/indexer/src/domain/indexer/models/profile.rs | 2+-
Mcrates/indexer/src/lib.rs | 5+----
Mpackage.json | 3++-
Aturbo.json | 45+++++++++++++++++++++++++++++++++++++++++++++
22 files changed, 342 insertions(+), 247 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1299,12 +1299,28 @@ dependencies = [ ] [[package]] -name = "radroots-common" +name = "radroots-core" +version = "0.1.0" +dependencies = [ + "rust_decimal", + "rust_decimal_macros", + "serde", +] + +[[package]] +name = "radroots-events" +version = "0.1.0" +dependencies = [ + "radroots-core", + "serde", + "typeshare", +] + +[[package]] +name = "radroots-events-indexed" version = "0.1.0" dependencies = [ "serde", - "serde_json", - "thiserror 1.0.69", "typeshare", ] @@ -1317,7 +1333,8 @@ dependencies = [ "config", "indexer-utils", "once_cell", - "radroots-common", + "radroots-events", + "radroots-events-indexed", "regex", "serde", "serde_json", @@ -1457,6 +1474,27 @@ dependencies = [ ] [[package]] +name = "rust_decimal" +version = "1.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d" +dependencies = [ + "arrayvec", + "num-traits", + "serde", +] + +[[package]] +name = "rust_decimal_macros" +version = "1.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6268b74858287e1a062271b988a0c534bf85bbeb567fe09331bf40ed78113d5" +dependencies = [ + "quote", + "syn", +] + +[[package]] name = "rustc-demangle" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/app/package.json b/app/package.json @@ -32,7 +32,10 @@ "@radroots/apps-lib": "*", "@radroots/apps-lib-market": "*", "@radroots/utils-nostr": "*", - "@radroots/radroots-common-bindings": "*", + "@radroots/core-bindings": "*", + "@radroots/events-bindings": "*", + "@radroots/events-indexed-bindings": "*", + "@radroots/trade-bindings": "*", "@nostr-dev-kit/ndk": "2.14.33" } } \ No newline at end of file diff --git a/app/src/app.css b/app/src/app.css @@ -1,3 +1,10 @@ @import "tailwindcss"; -@plugin "daisyui" {} +@import "../theme.css"; + +@plugin "daisyui" { + themes: os_light, os_dark; +} + +@source "../../../../../global/packages/apps-lib/src/**/*.{svelte,ts}"; +@source "../../../../../global/packages/apps-lib-market/src/**/*.{svelte,ts}"; diff --git a/app/src/routes/(market)/(listing)/[0=country]/+page.ts b/app/src/routes/(market)/(listing)/[0=country]/+page.ts @@ -1,22 +1,26 @@ -import { VITE_PUBLIC_RADROOTS_MARKET_RELAY_INDEXES_URL } from "$env/static/public"; -import type { RadrootsIndexManifest, RadrootsListingEventMetadata } from "@radroots/radroots-common-bindings"; +import { _env } from "$lib/utils/_env"; +import type { RadrootsListingEventMetadata } from "@radroots/events-bindings"; +import type { RadrootsEventsIndexedManifest } from "@radroots/events-indexed-bindings"; + import { error } from "@sveltejs/kit"; import type { EntryGenerator, PageLoad } from "./$types"; +const { RADROOTS_MARKET_RELAY_INDEXES_URL: indexes_url } = _env; + export const entries: EntryGenerator = async () => { const [ events_0_country_indexes, ]: [ string[] ] = await Promise.all([ - fetch(`${VITE_PUBLIC_RADROOTS_MARKET_RELAY_INDEXES_URL}/events/30402/country/indexes.json`).then(r => r.json()) + fetch(`${indexes_url}/events/30402/country/indexes.json`).then(r => r.json()) ]); return events_0_country_indexes.map(i => ({ 0: i })) }; type PageLoadData = { country: string; - manifest: RadrootsIndexManifest; + manifest: RadrootsEventsIndexedManifest; events: RadrootsListingEventMetadata[]; }; @@ -26,17 +30,17 @@ export const load: PageLoad<PageLoadData> = async ({ fetch, params }) => { const [ res_country_manifest, ] = await Promise.all([ - fetch(`${VITE_PUBLIC_RADROOTS_MARKET_RELAY_INDEXES_URL}/events/30402/country/${country}/manifest.json`) + fetch(`${indexes_url}/events/30402/country/${country}/manifest.json`) ]); if (!res_country_manifest.ok) error(404, { message: `country:${country}` }); - const manifest: RadrootsIndexManifest = await res_country_manifest.json(); + const manifest: RadrootsEventsIndexedManifest = await res_country_manifest.json(); let events: RadrootsListingEventMetadata[] = []; if (manifest.shards.length > 0) { const shard = manifest.shards[0]; - const res_country_shard = await fetch(`${VITE_PUBLIC_RADROOTS_MARKET_RELAY_INDEXES_URL}/events/30402/country/${country}/${shard.file}?v=${shard.sha256}`); + const res_country_shard = await fetch(`${indexes_url}/events/30402/country/${country}/${shard.file}?v=${shard.sha256}`); if (!res_country_shard.ok) error(500, { message: `load:${country}:${shard.file}` }); events = await res_country_shard.json(); } diff --git a/app/src/routes/(market)/(profile)/[0=nip05]/+page.ts b/app/src/routes/(market)/(profile)/[0=nip05]/+page.ts @@ -1,6 +1,7 @@ import { _env } from "$lib/utils/_env"; import type { PageLoadProfileData } from "@radroots/apps-lib-market"; -import type { RadrootsIndexManifest, RadrootsListingEventMetadata, RadrootsProfileEventMetadata } from "@radroots/radroots-common-bindings"; +import type { RadrootsListingEventMetadata, RadrootsProfileEventMetadata } from "@radroots/events-bindings"; +import type { RadrootsEventsIndexedManifest } from "@radroots/events-indexed-bindings"; import { lib_nostr_npub_encode } from "@radroots/utils-nostr"; import { error } from "@sveltejs/kit"; import type { EntryGenerator, PageLoad } from "./$types"; @@ -35,7 +36,7 @@ export const load: PageLoad<PageLoadData> = async ({ fetch, params }) => { if (!res_nip05_listings_manifest.ok) error(404, { message: `nip05:listing:manifest:${nip05}`, }); const profile_event: RadrootsProfileEventMetadata = await res_nip05_metadata.json(); - const listings_manifest: RadrootsIndexManifest = await res_nip05_listings_manifest.json(); + const listings_manifest: RadrootsEventsIndexedManifest = await res_nip05_listings_manifest.json(); let listings_events: RadrootsListingEventMetadata[] = []; if (listings_manifest.shards.length > 0) { diff --git a/app/src/routes/(market)/(profile)/profile/+error.svelte b/app/src/routes/(market)/(profile)/profile/+error.svelte @@ -2,9 +2,9 @@ import { page } from "$app/state"; import { Profile, - type IProfileViewUnknownNip05, - type IProfileViewUnknownNpub, - type IProfileViewUnknownPublicKey, + type IProfileViewNetworkNip05, + type IProfileViewNetworkNpub, + type IProfileViewNetworkPublicKey, } from "@radroots/apps-lib-market"; $effect(() => { @@ -14,7 +14,7 @@ {#if page.error?.message} {@const [profile_type, profile_payload] = page.error.message.split(`:`)} - {@const unknown: IProfileViewUnknownPublicKey | IProfileViewUnknownNpub | IProfileViewUnknownNip05 | undefined = + {@const unknown: IProfileViewNetworkPublicKey | IProfileViewNetworkNpub | IProfileViewNetworkNip05 | undefined = profile_type === `public_key` ? { public_key: profile_payload, diff --git a/app/src/routes/(market)/(profile)/profile/[0=npub]/+page.ts b/app/src/routes/(market)/(profile)/profile/[0=npub]/+page.ts @@ -1,6 +1,6 @@ import { _env } from "$lib/utils/_env"; import type { PageLoadProfileData } from "@radroots/apps-lib-market"; -import type { RadrootsProfileEventMetadata } from "@radroots/radroots-common-bindings"; +import type { RadrootsProfileEventMetadata } from "@radroots/events-bindings"; import { error } from "@sveltejs/kit"; import type { EntryGenerator, PageLoad } from "./$types"; diff --git a/app/src/routes/(market)/(profile)/profile/[0=public_key]/+page.ts b/app/src/routes/(market)/(profile)/profile/[0=public_key]/+page.ts @@ -1,6 +1,6 @@ import { _env } from "$lib/utils/_env"; import type { PageLoadProfileData } from "@radroots/apps-lib-market"; -import type { RadrootsProfileEventMetadata } from "@radroots/radroots-common-bindings"; +import type { RadrootsProfileEventMetadata } from "@radroots/events-bindings"; import { lib_nostr_npub_encode } from "@radroots/utils-nostr"; import { error } from "@sveltejs/kit"; import type { EntryGenerator, PageLoad } from "./$types"; diff --git a/app/src/routes/+layout.svelte b/app/src/routes/+layout.svelte @@ -1,14 +1,19 @@ <script lang="ts"> - import { ndk, ndk_global } from "@radroots/apps-lib"; + import { ndk, ndk_global, ndk_user, nostr_login } from "@radroots/apps-lib"; import { idb, init_theme } from "@radroots/apps-lib-market"; + import { lib_nostr_key_generate } from "@radroots/utils-nostr"; import { onMount, type Snippet } from "svelte"; import "../app.css"; let { children }: { children: Snippet } = $props(); + let loaded = $state(false); + onMount(async () => { await init_theme(); + loaded = true; + await $ndk.connect(); console.log(`[ndk] connected`); @@ -21,7 +26,16 @@ await $ndk_global.connect(); console.log(`[ndk_global] connected`); + + await nostr_login({ + nostr_key: lib_nostr_key_generate(), + }); + + console.log(`$ndk `, $ndk); + console.log(`$ndk_user `, $ndk_user); }); </script> -{@render children()} +{#if loaded} + {@render children()} +{/if} diff --git a/app/src/routes/+page.ts b/app/src/routes/+page.ts @@ -1,7 +1,9 @@ -import { VITE_PUBLIC_RADROOTS_MARKET_RELAY_INDEXES_URL } from "$env/static/public"; +import { _env } from "$lib/utils/_env"; import { error } from "@sveltejs/kit"; import type { PageLoad } from "./$types"; +const { RADROOTS_MARKET_RELAY_INDEXES_URL: indexes_url } = _env; + type PageLoadData = { profiles: string[]; countries: string[]; @@ -13,8 +15,8 @@ export const load: PageLoad<PageLoadData> = async ({ fetch, params }) => { res_nip05_indexes, res_country_indexes, ] = await Promise.all([ - fetch(`${VITE_PUBLIC_RADROOTS_MARKET_RELAY_INDEXES_URL}/events/30402/nip05/indexes.json`), - fetch(`${VITE_PUBLIC_RADROOTS_MARKET_RELAY_INDEXES_URL}/events/30402/country/indexes.json`), + fetch(`${indexes_url}/events/30402/nip05/indexes.json`), + fetch(`${indexes_url}/events/30402/country/indexes.json`), ]); if (!res_nip05_indexes.ok) error(404, { message: `nip05:indexes` }); diff --git a/app/theme.css b/app/theme.css @@ -0,0 +1,155 @@ +@theme { + --color-ly0: rgb(var(--ly0) / <alpha-value>); + --color-ly0-a: rgb(var(--ly0-a) / <alpha-value>); + --color-ly0-edge: rgb(var(--ly0-edge) / <alpha-value>); + --color-ly0-gl: rgb(var(--ly0-gl) / <alpha-value>); + --color-ly0-gl-a: rgb(var(--ly0-gl-a) / <alpha-value>); + --color-ly0-gl-d: rgb(var(--ly0-gl-d) / <alpha-value>); + --color-ly0-gl-pl: rgb(var(--ly0-gl-pl) / <alpha-value>); + --color-ly0-gl-hl: rgb(var(--ly0-gl-hl) / <alpha-value>); + --color-ly0-gl-hl-a: rgb(var(--ly0-gl-hl-a) / <alpha-value>); + --color-ly0-gl-label: rgb(var(--ly0-gl-label) / <alpha-value>); + --color-ly1: rgb(var(--ly1) / <alpha-value>); + --color-ly1-a: rgb(var(--ly1-a) / <alpha-value>); + --color-ly1-edge: rgb(var(--ly1-edge) / <alpha-value>); + --color-ly1-icon: rgb(var(--ly1-icon) / <alpha-value>); + --color-ly1-overlay: rgb(var(--ly1-overlay) / <alpha-value>); + --color-ly1-gl: rgb(var(--ly1-gl) / <alpha-value>); + --color-ly1-gl-a: rgb(var(--ly1-gl-a) / <alpha-value>); + --color-ly1-gl-d: rgb(var(--ly1-gl-d) / <alpha-value>); + --color-ly1-gl-pl: rgb(var(--ly1-gl-pl) / <alpha-value>); + --color-ly1-gl-hl: rgb(var(--ly1-gl-hl) / <alpha-value>); + --color-ly1-gl-hl-a: rgb(var(--ly1-gl-hl-a) / <alpha-value>); + --color-ly1-gl-label: rgb(var(--ly1-gl-label) / <alpha-value>); + --color-ly1-gl-edge: rgb(var(--ly1-gl-edge) / <alpha-value>); + --color-ly2: rgb(var(--ly2) / <alpha-value>); + --color-ly2-a: rgb(var(--ly2-a) / <alpha-value>); + --color-ly2-edge: rgb(var(--ly2-edge) / <alpha-value>); + --color-ly2-icon: rgb(var(--ly2-icon) / <alpha-value>); + --color-ly2-gl: rgb(var(--ly2-gl) / <alpha-value>); + --color-ly2-gl-a: rgb(var(--ly2-gl-a) / <alpha-value>); + --color-ly2-gl-d: rgb(var(--ly2-gl-d) / <alpha-value>); + --color-ly2-gl-pl: rgb(var(--ly2-gl-pl) / <alpha-value>); + --color-ly2-gl-hl: rgb(var(--ly2-gl-hl) / <alpha-value>); + --color-ly2-gl-hl-a: rgb(var(--ly2-gl-hl-a) / <alpha-value>); + --color-ly2-gl-label: rgb(var(--ly2-gl-label) / <alpha-value>); + --color-ly0: rgb(var(--ly0) / <alpha-value>); + --color-ly0-a: rgb(var(--ly0-a) / <alpha-value>); + --color-ly0-edge: rgb(var(--ly0-edge) / <alpha-value>); + --color-ly0-gl: rgb(var(--ly0-gl) / <alpha-value>); + --color-ly0-gl-a: rgb(var(--ly0-gl-a) / <alpha-value>); + --color-ly0-gl-d: rgb(var(--ly0-gl-d) / <alpha-value>); + --color-ly0-gl-pl: rgb(var(--ly0-gl-pl) / <alpha-value>); + --color-ly0-gl-hl: rgb(var(--ly0-gl-hl) / <alpha-value>); + --color-ly0-gl-hl-a: rgb(var(--ly0-gl-hl-a) / <alpha-value>); + --color-ly0-gl-label: rgb(var(--ly0-gl-label) / <alpha-value>); + --color-ly1: rgb(var(--ly1) / <alpha-value>); + --color-ly1-a: rgb(var(--ly1-a) / <alpha-value>); + --color-ly1-edge: rgb(var(--ly1-edge) / <alpha-value>); + --color-ly1-icon: rgb(var(--ly1-icon) / <alpha-value>); + --color-ly1-overlay: rgb(var(--ly1-overlay) / <alpha-value>); + --color-ly1-gl: rgb(var(--ly1-gl) / <alpha-value>); + --color-ly1-gl-a: rgb(var(--ly1-gl-a) / <alpha-value>); + --color-ly1-gl-d: rgb(var(--ly1-gl-d) / <alpha-value>); + --color-ly1-gl-pl: rgb(var(--ly1-gl-pl) / <alpha-value>); + --color-ly1-gl-hl: rgb(var(--ly1-gl-hl) / <alpha-value>); + --color-ly1-gl-hl-a: rgb(var(--ly1-gl-hl-a) / <alpha-value>); + --color-ly1-gl-label: rgb(var(--ly1-gl-label) / <alpha-value>); + --color-ly1-gl-edge: rgb(var(--ly1-gl-edge) / <alpha-value>); + --color-ly2: rgb(var(--ly2) / <alpha-value>); + --color-ly2-a: rgb(var(--ly2-a) / <alpha-value>); + --color-ly2-edge: rgb(var(--ly2-edge) / <alpha-value>); + --color-ly2-icon: rgb(var(--ly2-icon) / <alpha-value>); + --color-ly2-gl: rgb(var(--ly2-gl) / <alpha-value>); + --color-ly2-gl-a: rgb(var(--ly2-gl-a) / <alpha-value>); + --color-ly2-gl-d: rgb(var(--ly2-gl-d) / <alpha-value>); + --color-ly2-gl-pl: rgb(var(--ly2-gl-pl) / <alpha-value>); + --color-ly2-gl-hl: rgb(var(--ly2-gl-hl) / <alpha-value>); + --color-ly2-gl-hl-a: rgb(var(--ly2-gl-hl-a) / <alpha-value>); + --color-ly2-gl-label: rgb(var(--ly2-gl-label) / <alpha-value>); +} + +@plugin "daisyui/theme" { + name: "os_light"; + default: false; + prefersdark: false; + color-scheme: light; + + --color-ly0: rgb(242, 242, 247); + --color-ly0-a: rgb(242, 242, 247); + --color-ly0-edge: rgb(159, 159, 165); + --color-ly0-gl: rgb(0, 0, 0); + --color-ly0-gl-a: rgb(0, 0, 0); + --color-ly0-gl-d: rgb(145, 145, 149); + --color-ly0-gl-pl: rgb(145, 145, 149); + --color-ly0-gl-hl: rgb(52, 120, 246); + --color-ly0-gl-hl-a: rgb(108, 165, 249); + --color-ly0-gl-label: rgb(177, 177, 182); + --color-ly1: rgb(255, 255, 255); + --color-ly1-a: rgb(209, 209, 214); + --color-ly1-edge: rgb(197, 197, 199); + --color-ly1-icon: rgb(127, 127, 132); + --color-ly1-overlay: rgb(142, 142, 147); + --color-ly1-gl: rgb(14, 14, 14); + --color-ly1-gl-a: rgb(29, 29, 29); + --color-ly1-gl-d: rgb(29, 29, 29); + --color-ly1-gl-pl: rgb(29, 29, 29); + --color-ly1-gl-hl: rgb(52, 120, 246); + --color-ly1-gl-hl-a: rgb(199, 217, 246); + --color-ly1-gl-label: rgb(164, 164, 164); + --color-ly1-gl-edge: rgb(191, 191, 191); + --color-ly2: rgb(242, 242, 247); + --color-ly2-a: rgb(58, 58, 60); + --color-ly2-edge: rgb(112, 112, 115); + --color-ly2-icon: rgb(159, 159, 164); + --color-ly2-gl: rgb(14, 14, 14); + --color-ly2-gl-a: rgb(29, 29, 29); + --color-ly2-gl-d: rgb(29, 29, 29); + --color-ly2-gl-pl: rgb(29, 29, 29); + --color-ly2-gl-hl: rgb(52, 120, 246); + --color-ly2-gl-hl-a: rgb(199, 217, 246); + --color-ly2-gl-label: rgb(137, 137, 142); +} + +@plugin "daisyui/theme" { + name: "os_dark"; + default: false; + prefersdark: false; + color-scheme: dark; + + --color-ly0: rgb(0, 0, 0); + --color-ly0-a: rgb(31, 31, 31); + --color-ly0-edge: rgb(125, 125, 129); + --color-ly0-gl: rgb(255, 255, 255); + --color-ly0-gl-a: rgb(255, 255, 255); + --color-ly0-gl-d: rgb(125, 125, 129); + --color-ly0-gl-pl: rgb(125, 125, 129); + --color-ly0-gl-hl: rgb(54, 117, 220); + --color-ly0-gl-hl-a: rgb(85, 151, 242); + --color-ly0-gl-label: rgb(125, 125, 129); + --color-ly1: rgb(28, 28, 31); + --color-ly1-a: rgb(58, 58, 60); + --color-ly1-edge: rgb(38, 38, 40); + --color-ly1-icon: rgb(152, 152, 158); + --color-ly1-overlay: rgb(142, 142, 147); + --color-ly1-gl: rgb(240, 240, 240); + --color-ly1-gl-a: rgb(240, 240, 240); + --color-ly1-gl-d: rgb(88, 88, 93); + --color-ly1-gl-pl: rgb(128, 128, 133); + --color-ly1-gl-hl: rgb(59, 130, 247); + --color-ly1-gl-hl-a: rgb(21, 52, 98); + --color-ly1-gl-label: rgb(125, 125, 125); + --color-ly1-gl-edge: rgb(85, 85, 85); + --color-ly2: rgb(44, 44, 46); + --color-ly2-a: rgb(58, 58, 60); + --color-ly2-edge: rgb(112, 112, 115); + --color-ly2-icon: rgb(159, 159, 164); + --color-ly2-gl: rgb(241, 241, 241); + --color-ly2-gl-a: rgb(241, 241, 241); + --color-ly2-gl-d: rgb(130, 130, 134); + --color-ly2-gl-pl: rgb(128, 128, 133); + --color-ly2-gl-hl: rgb(59, 130, 247); + --color-ly2-gl-hl-a: rgb(21, 52, 98); + --color-ly2-gl-label: rgb(130, 130, 134); +} + diff --git a/crates/indexer/Cargo.toml b/crates/indexer/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" [dependencies] indexer-utils = { path = "../indexer-utils" } -radroots-common = { path = "../../../../../crates/radroots-common/" } +radroots-events = { path = "../../../../../crates/radroots-common/crates/events" } +radroots-events-indexed = { path = "../../../../../crates/radroots-common/crates/events-indexed" } anyhow = "1.0" clap = { version = "4", features = ["derive"] } diff --git a/crates/indexer/config.toml b/crates/indexer/config.toml @@ -5,7 +5,7 @@ flush_interval = 20 [relay] url = "ws://127.0.0.1:8080" -db_path = "data/nostr-rs-relay/nostr.db" +database_path = "data/nostr-rs-relay/nostr.db" [listings] country_shard_size = 1000 diff --git a/crates/indexer/src/audit.rs b/crates/indexer/src/audit.rs @@ -10,8 +10,8 @@ use tracing::info; use crate::domain::resolvers::profile::ProfileResolver; use crate::relay::event::RelayIndexerEvent; -use radroots_common::events::listing::models::RadrootsListingEventIndex; -use radroots_common::events::profile::models::RadrootsProfileEventIndex; +use radroots_events::listing::models::RadrootsListingEventIndex; +use radroots_events::profile::models::RadrootsProfileEventIndex; #[derive(Clone, Debug)] pub struct AuditFilter { diff --git a/crates/indexer/src/config.rs b/crates/indexer/src/config.rs @@ -50,12 +50,12 @@ impl Settings { Ok(cfg) => match cfg.try_deserialize::<Settings>() { Ok(settings) => Ok(settings), Err(err) => { - error!("❌ Failed to deserialize configuration: {err}"); + error!("Failed to deserialize configuration: {err}"); Err(SettingsError::Load(err)) } }, Err(err) => { - error!("❌ Failed to load configuration from '{}': {err}", path); + error!("Failed to load configuration from '{}': {err}", path); Err(SettingsError::Load(err)) } } diff --git a/crates/indexer/src/domain/events/listing.rs b/crates/indexer/src/domain/events/listing.rs @@ -1,195 +1,26 @@ -use crate::relay::event::RelayIndexerEvent; -use anyhow::Result; -use indexer_utils::nostr::NostrUtilsError; -use radroots_common::events::listing::models::{ - RadrootsListing, RadrootsListingDiscount, RadrootsListingEventIndex, - RadrootsListingEventMetadata, RadrootsListingImage, RadrootsListingLocation, - RadrootsListingPrice, RadrootsListingProduct, RadrootsListingQuantity, -}; -use radroots_common::events::RadrootsNostrEvent; -use std::collections::HashMap; use thiserror::Error; -#[derive(Debug, Error)] -pub enum RadrootsListingEventIndexError { - #[error("Missing or invalid tag structure")] - TagParseError, +use radroots_events::{ + listing::models::{RadrootsListing, RadrootsListingEventIndex, RadrootsListingEventMetadata}, + RadrootsNostrEvent, +}; - #[error("Missing required field: {0}")] - MissingField(String), +use crate::relay::event::RelayIndexerEvent; - #[error("Nostr Error: {0}")] - NostrUtilsError(#[from] NostrUtilsError), +#[derive(Debug, Error)] +pub enum RadrootsListingEventIndexError { + #[error("Failed to parse listing JSON: {0}")] + ParseError(#[from] serde_json::Error), } -pub fn create_radroots_listing_event_metadata( +fn create_radroots_listing_event_metadata( id: String, author: String, published_at: u32, - tags: Vec<Vec<String>>, + content: String, + _tags: Vec<Vec<String>>, ) -> Result<RadrootsListingEventMetadata, RadrootsListingEventIndexError> { - let mut tags_map: HashMap<String, Vec<String>> = HashMap::new(); - let mut location_lat: Option<String> = None; - let mut location_lng: Option<String> = None; - - for tag in &tags { - if let Some(key) = tag.get(0).map(String::as_str) { - match key { - "l" => { - if let Some(value) = tag.get(1) { - if let Some(hint) = tag.get(2) { - match hint.as_str() { - "dd.lat" if location_lat.is_none() => { - location_lat = Some(value.clone()); - } - "dd.lon" if location_lng.is_none() => { - location_lng = Some(value.clone()); - } - _ => {} - } - } else if value.contains(',') { - let parts: Vec<&str> = value.split(',').map(str::trim).collect(); - if parts.len() == 2 { - location_lat = Some(parts[0].to_string()); - location_lng = Some(parts[1].to_string()); - } - } - } - } - _ => { - tags_map - .entry(key.to_string()) - .or_default() - .extend_from_slice(&tag[1..]); - } - } - } - } - - let get = |key: &str, idx: usize| -> Option<String> { - tags_map.get(key).and_then(|v| v.get(idx)).cloned() - }; - - let d_tag = - get("d", 0).ok_or_else(|| RadrootsListingEventIndexError::MissingField("d".into()))?; - let title = get("title", 0) - .ok_or_else(|| RadrootsListingEventIndexError::MissingField("title".into()))?; - - let location_address = get("location", 0) - .ok_or_else(|| RadrootsListingEventIndexError::MissingField("location".into()))?; - let location_city = get("location", 1) - .ok_or_else(|| RadrootsListingEventIndexError::MissingField("location_city".into()))?; - let location_region = get("location", 2) - .ok_or_else(|| RadrootsListingEventIndexError::MissingField("location_region".into()))?; - let location_country = get("location", 3) - .ok_or_else(|| RadrootsListingEventIndexError::MissingField("location_country".into()))?; - - let location_geohash = tags - .iter() - .filter_map(|tag| { - if tag.get(0).map(String::as_str) == Some("g") { - tag.get(1).cloned() - } else { - None - } - }) - .max_by_key(|g| g.len()) - .ok_or_else(|| RadrootsListingEventIndexError::MissingField("location_geohash".into()))?; - - let quantities = tags - .iter() - .filter_map(|tag| { - if tag.get(0).map(String::as_str) == Some("quantity") { - Some(RadrootsListingQuantity { - amt: tag.get(1)?.clone(), - unit: tag.get(2)?.clone(), - label: tag.get(3).cloned(), - }) - } else { - None - } - }) - .collect::<Vec<RadrootsListingQuantity>>(); - - let prices = tags - .iter() - .filter_map(|tag| { - if tag.get(0).map(String::as_str) == Some("price") { - Some(RadrootsListingPrice { - amt: tag.get(1)?.clone(), - currency: tag.get(2)?.clone(), - qty_amt: tag.get(3)?.clone(), - qty_unit: tag.get(4)?.clone(), - qty_key: tag.get(5)?.clone(), - }) - } else { - None - } - }) - .collect::<Vec<RadrootsListingPrice>>(); - - let discounts = tags - .iter() - .filter_map(|tag| { - if tag.get(0).map(String::as_str) == Some("discount") { - Some(RadrootsListingDiscount::Quantity { - ref_quantity: "sample_ref".into(), - threshold: "100".into(), - value: "5".into(), - currency: "USD".into(), - }) - } else { - None - } - }) - .collect::<Vec<RadrootsListingDiscount>>(); - - let location = Some(RadrootsListingLocation { - primary: location_address, - city: Some(location_city), - region: Some(location_region), - country: Some(location_country), - lat: location_lat.map(|lat| lat.parse().unwrap_or_default()), - lng: location_lng.map(|lng| lng.parse().unwrap_or_default()), - geohash: Some(location_geohash), - }); - - let images = tags - .iter() - .filter_map(|tag| { - if tag.get(0).map(String::as_str) == Some("image") { - tag.get(1).map(|url| RadrootsListingImage { - url: url.clone(), - size: None, - }) - } else { - None - } - }) - .collect::<Vec<RadrootsListingImage>>(); - - let product = RadrootsListingProduct { - key: get("key", 0).unwrap_or_default(), - title, - category: get("category", 0).unwrap_or_default(), - summary: get("summary", 0), - process: get("process", 0), - lot: get("lot", 0), - location: get("location", 0), - profile: get("profile", 0), - year: get("year", 0), - }; - - let listing = RadrootsListing { - d_tag, - product, - quantities, - prices, - discounts: Some(discounts), - location, - images: Some(images), - }; - + let listing: RadrootsListing = serde_json::from_str(&content)?; Ok(RadrootsListingEventMetadata { id, author, @@ -211,7 +42,8 @@ impl ToRadrootsListingEventIndex for RelayIndexerEvent { let metadata = create_radroots_listing_event_metadata( self.id.clone(), self.author.clone(), - self.created_at.clone(), + self.created_at, + self.content.clone(), self.tags.clone(), )?; @@ -220,9 +52,9 @@ impl ToRadrootsListingEventIndex for RelayIndexerEvent { id: self.id, author: self.author, created_at: self.created_at, - kind: self.kind.as_u64().try_into().unwrap(), - content: self.content, + kind: self.kind.as_u64() as u32, tags: self.tags, + content: self.content, sig: self.sig, }, metadata, diff --git a/crates/indexer/src/domain/events/profile.rs b/crates/indexer/src/domain/events/profile.rs @@ -1,8 +1,8 @@ use anyhow::Result; -use radroots_common::events::profile::models::{ - RadrootsProfile, RadrootsProfileEventIndex, RadrootsProfileEventMetadata, +use radroots_events::{ + profile::models::{RadrootsProfile, RadrootsProfileEventIndex, RadrootsProfileEventMetadata}, + RadrootsNostrEvent, }; -use radroots_common::events::RadrootsNostrEvent; use std::collections::HashMap; use thiserror::Error; @@ -12,10 +12,8 @@ use crate::relay::event::RelayIndexerEvent; pub enum RadrootsProfileEventIndexError { #[error("Failed to parse metadata content JSON: {0}")] ParseError(#[from] serde_json::Error), - #[error("Missing or empty 'name' field in profile data")] MissingNameField, - #[error("Missing or invalid 'published_at' tag")] MissingPublishedAt, } @@ -60,7 +58,7 @@ impl ToRadrootsProfileEventIndex for RelayIndexerEvent { let metadata = create_radroots_profile_event_metadata( self.id.clone(), self.author.clone(), - self.created_at.clone(), + self.created_at, self.content.clone(), self.tags.clone(), )?; diff --git a/crates/indexer/src/domain/indexer/models/listing.rs b/crates/indexer/src/domain/indexer/models/listing.rs @@ -4,10 +4,8 @@ use indexer_utils::{ nostr::public_key_to_npub, write::{compute_hash, write_hash, write_json}, }; -use radroots_common::{ - events::listing::models::{RadrootsListingEventIndex, RadrootsListingEventMetadata}, - models::indexer::{RadrootsIndexManifest, RadrootsIndexShardMetadata}, -}; +use radroots_events::listing::models::{RadrootsListingEventIndex, RadrootsListingEventMetadata}; +use radroots_events_indexed::{RadrootsEventsIndexedManifest, RadrootsEventsIndexedShardMetadata}; use std::{collections::BTreeMap, fs, path::PathBuf}; use tracing::{instrument, warn}; @@ -19,7 +17,6 @@ use crate::{ key::LISTING_INDEX_DIRECTORY, kind::IndexerEventKind, models::{EventIndexes, NostrEventsStaticError, WriteEventIndexes}, - IndexerKey, }, resolvers::profile::ProfileResolver, }, @@ -175,7 +172,7 @@ impl EventListingIndexes { impl EventIndexes for EventListingIndexes { type Event = RelayIndexerEvent; - fn subdirs() -> &'static [IndexerKey] { + fn subdirs() -> &'static [crate::domain::indexer::IndexerKey] { &LISTING_INDEX_DIRECTORY } @@ -232,7 +229,7 @@ impl WriteEventIndexes for EventListingIndexes { } { - let sub_country = base.join(IndexerKey::Country.as_str()); + let sub_country = base.join(crate::domain::indexer::IndexerKey::Country.as_str()); fs_mkdir(&[&sub_country])?; let country_codes: Vec<String> = self.country_ids.keys().cloned().collect(); write_if_stale!(sub_country.join("indexes.json"), country_codes, updated); @@ -262,7 +259,7 @@ impl WriteEventIndexes for EventListingIndexes { (0, 0) }; - let mut manifest = RadrootsIndexManifest { + let mut manifest = RadrootsEventsIndexedManifest { country: cc.clone(), total: u32::try_from(data_items.len()).expect("too many data items for u32"), shard_size: u32::try_from(shard_size).expect("shard_size too large for u32"), @@ -297,7 +294,7 @@ impl WriteEventIndexes for EventListingIndexes { (fp.0, fp.1, lp.0, lp.1) }; - manifest.shards.push(RadrootsIndexShardMetadata { + manifest.shards.push(RadrootsEventsIndexedShardMetadata { file: file_rel, count: u32::try_from(chunk.len()).expect("chunk length too large for u32"), first_id, @@ -313,7 +310,7 @@ impl WriteEventIndexes for EventListingIndexes { } { - let sub_author = base.join(IndexerKey::Author.as_str()); + let sub_author = base.join(crate::domain::indexer::IndexerKey::Author.as_str()); fs_mkdir(&[&sub_author])?; let authors: Vec<String> = self.author_ids.keys().cloned().collect(); write_if_stale!(sub_author.join("indexes.json"), authors, updated); @@ -341,7 +338,7 @@ impl WriteEventIndexes for EventListingIndexes { (0, 0) }; - let mut manifest = RadrootsIndexManifest { + let mut manifest = RadrootsEventsIndexedManifest { country: author.clone(), total: u32::try_from(data_items.len()).expect("too many data items for u32"), shard_size: u32::try_from(shard_size).expect("shard_size too large for u32"), @@ -381,7 +378,7 @@ impl WriteEventIndexes for EventListingIndexes { (fp.0, fp.1, lp.0, lp.1) }; - manifest.shards.push(RadrootsIndexShardMetadata { + manifest.shards.push(RadrootsEventsIndexedShardMetadata { file: file_rel, count: u32::try_from(std::cmp::min( shard_size, @@ -401,7 +398,7 @@ impl WriteEventIndexes for EventListingIndexes { } { - let sub_npub = base.join(IndexerKey::Npub.as_str()); + let sub_npub = base.join(crate::domain::indexer::IndexerKey::Npub.as_str()); fs_mkdir(&[&sub_npub])?; let npubs: Vec<String> = self.npub_ids.keys().cloned().collect(); write_if_stale!(sub_npub.join("indexes.json"), npubs, updated); @@ -429,7 +426,7 @@ impl WriteEventIndexes for EventListingIndexes { (0, 0) }; - let mut manifest = RadrootsIndexManifest { + let mut manifest = RadrootsEventsIndexedManifest { country: npub.clone(), total: u32::try_from(data_items.len()).expect("too many data items for u32"), shard_size: u32::try_from(shard_size).expect("shard_size too large for u32"), @@ -469,7 +466,7 @@ impl WriteEventIndexes for EventListingIndexes { (fp.0, fp.1, lp.0, lp.1) }; - manifest.shards.push(RadrootsIndexShardMetadata { + manifest.shards.push(RadrootsEventsIndexedShardMetadata { file: file_rel, count: u32::try_from(std::cmp::min( shard_size, @@ -488,7 +485,7 @@ impl WriteEventIndexes for EventListingIndexes { } { - let sub_nip05 = base.join(IndexerKey::Nip05.as_str()); + let sub_nip05 = base.join(crate::domain::indexer::IndexerKey::Nip05.as_str()); fs_mkdir(&[&sub_nip05])?; let names: Vec<String> = self.nip05_ids.keys().cloned().collect(); write_if_stale!(sub_nip05.join("indexes.json"), names, updated); @@ -515,7 +512,7 @@ impl WriteEventIndexes for EventListingIndexes { (0, 0) }; - let mut manifest = RadrootsIndexManifest { + let mut manifest = RadrootsEventsIndexedManifest { country: name.clone(), total: u32::try_from(data_items.len()).expect("u32 overflow"), shard_size: u32::try_from(shard_size).expect("u32 overflow"), @@ -550,7 +547,7 @@ impl WriteEventIndexes for EventListingIndexes { (fp.0, fp.1, lp.0, lp.1) }; - manifest.shards.push(RadrootsIndexShardMetadata { + manifest.shards.push(RadrootsEventsIndexedShardMetadata { file: file_rel, count: u32::try_from(std::cmp::min( shard_size, diff --git a/crates/indexer/src/domain/indexer/models/profile.rs b/crates/indexer/src/domain/indexer/models/profile.rs @@ -4,7 +4,7 @@ use indexer_utils::{ nostr::public_key_to_npub, write::{compute_hash, write_hash, write_json}, }; -use radroots_common::events::profile::models::RadrootsProfileEventIndex; +use radroots_events::profile::models::RadrootsProfileEventIndex; use std::{collections::BTreeMap, fs, path::PathBuf}; use tracing::{instrument, warn}; diff --git a/crates/indexer/src/lib.rs b/crates/indexer/src/lib.rs @@ -27,7 +27,7 @@ pub mod audit; #[cfg(not(feature = "audit"))] pub mod audit { - use radroots_common::events::{ + use radroots_events::{ listing::models::RadrootsListingEventIndex, profile::models::RadrootsProfileEventIndex, }; @@ -109,7 +109,6 @@ pub async fn run(settings: Settings) -> Result<()> { last_created_at = last_created_at.max(ev.created_at); let id = &ev.id; let hash = &ev.hash; - let skip = if let Some(old) = db_idx.get_raw(tree_raw, id)? { old.as_ref() == hash.as_bytes() } else { @@ -211,6 +210,4 @@ pub async fn run(settings: Settings) -> Result<()> { ); tokio::time::sleep(delay).await; } - #[allow(unreachable_code)] - Ok(()) } diff --git a/package.json b/package.json @@ -19,7 +19,8 @@ "app", "packages/*", "../../../global/packages/*", - "../../../crates/radroots-common/bindings/ts*" + "../../../crates/radroots-common/bindings/ts*", + "../../../crates/radroots-common/packages/bindings/*" ], "nohoist": [] }, diff --git a/turbo.json b/turbo.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://turborepo.com/schema.json", + "ui": "tui", + "tasks": { + "build": { + "dependsOn": [ + "^build" + ], + "inputs": [ + "$TURBO_DEFAULT$", + ".env*" + ], + "outputs": [ + "dist/**", + ".svelte-kit/**" + ] + }, + "lint": { + "dependsOn": [ + "^lint" + ] + }, + "check-types": { + "dependsOn": [ + "^check-types" + ] + }, + "dev": { + "cache": false, + "persistent": true + }, + "app#build": { + "dependsOn": [ + "@radroots/apps-lib#build", + "@radroots/apps-lib-market#build", + "@radroots/utils-nostr#build", + "@radroots/core-bindings#build", + "@radroots/events-bindings#build", + "@radroots/events-indexed-bindings#build", + "@radroots/trade-bindings#build" + ] + } + } +} +\ No newline at end of file