From b6a28957f1a802d16228d22dae2dd773e4af2237 Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Thu, 11 Jun 2026 07:37:14 +0100 Subject: [PATCH 01/11] feat: integrate treasury management features and refactor hackathon orchestration and API client architecture. --- .env.example | 10 +- .../[slug]/components/SponsorsSection.tsx | 30 +- .../components/sidebar/MySubmissionPanel.tsx | 2 +- .../components/sidebar/PoolAndAction.tsx | 84 +- .../[slug]/components/tabs/contents/index.tsx | 0 .../contents/submissions/SubmissionCard.tsx | 2 +- .../hackathons/[slug]/submit/page.tsx | 2 +- app/(landing)/hackathons/layout.tsx | 13 +- .../[id]/hackathons/[hackathonId]/page.tsx | 62 +- .../hackathons/[hackathonId]/rewards/page.tsx | 219 +- .../[id]/hackathons/drafts/[draftId]/page.tsx | 6 +- .../[id]/hackathons/new/page.tsx | 6 +- .../organizations/[id]/hackathons/page.tsx | 62 +- .../organizations/[id]/treasury/page.tsx | 67 + app/providers.tsx | 39 +- components/auth/LoginWrapper.tsx | 30 - components/auth/OtpForm.tsx | 33 +- components/hackathons/HackathonsPage.tsx | 6 +- .../overview/RegisterHackathonModal.tsx | 92 - .../submissions/SubmissionAnchorProgress.tsx | 258 + .../hackathons/submissions/SubmissionForm.tsx | 97 +- .../organization/OrganizationSidebar.tsx | 7 + .../HackathonPublishStatusBanner.tsx | 146 + .../hackathons/details/HackathonSidebar.tsx | 7 +- .../new/FundingConfirmationModal.tsx | 524 + .../hackathons/new/FundingProgressModal.tsx | 248 + .../hackathons/new/NewHackathonTab.tsx | 357 +- .../new/PrePublishAnnounceDialog.tsx | 2 +- .../hackathons/new/tabs/ReviewTab.tsx | 4 + .../tabs/components/review/PublishSection.tsx | 5 +- .../rewards/CreateMilestonesDialog.tsx | 122 - .../hackathons/rewards/EscrowStatusCard.tsx | 28 - .../rewards/PublishWinnersWizard.tsx | 176 +- .../RewardDistributionStatusBanner.tsx | 254 - .../rewards/RewardPayoutProgressModal.tsx | 240 + .../hackathons/rewards/RewardsPageContent.tsx | 269 +- .../hackathons/rewards/WinnerFormItem.tsx | 75 - .../settings/AdvancedSettingsTab.tsx | 56 +- components/organization/treasury/AuditLog.tsx | 150 + .../organization/treasury/PolicyEditor.tsx | 160 + .../organization/treasury/SpendInbox.tsx | 313 + .../organization/treasury/WalletsSection.tsx | 286 + components/providers/auth-provider.tsx | 94 - features/hackathons/api/draft-client.ts | 51 + features/hackathons/api/escrow-client.ts | 194 + features/hackathons/api/keys.ts | 14 + features/hackathons/api/use-draft.ts | 117 + features/hackathons/api/use-escrow.ts | 343 + .../hackathons/api/use-submission-anchor.ts | 98 + .../hackathons/api}/use-submission.ts | 94 +- features/hackathons/index.ts | 103 + features/hackathons/types.ts | 77 + features/treasury/api.ts | 217 + features/treasury/index.ts | 20 + features/treasury/keys.ts | 13 + features/treasury/types.ts | 111 + features/treasury/use-treasury-audit.ts | 14 + features/treasury/use-treasury-policy.ts | 29 + features/treasury/use-treasury-spend.ts | 85 + features/treasury/use-treasury-wallets.ts | 85 + hooks/hackathon/use-cancel-hackathon.ts | 78 + hooks/hackathon/use-delete-hackathon.ts | 2 +- hooks/hackathon/use-hackathons-list.ts | 339 +- hooks/hackathon/use-register-hackathon.ts | 130 - hooks/hackathon/use-team-posts.ts | 4 +- hooks/use-auth.ts | 9 +- hooks/use-follow.ts | 50 +- hooks/use-hackathon-draft.ts | 202 +- hooks/use-hackathon-publish.ts | 344 +- hooks/use-hackathon-rewards.ts | 75 +- hooks/use-hackathon-steps.ts | 64 +- hooks/use-hackathons.ts | 89 +- hooks/use-publish-winners.ts | 145 +- hooks/use-reward-distribution-status.ts | 79 - hooks/use-wizard-steps.ts | 6 +- instrumentation-client.ts | 25 - instrumentation.ts | 13 - lib/api/auth.ts | 25 +- lib/api/client.ts | 166 + lib/api/generated/schema.d.ts | 36197 ++++++++++++++++ lib/api/hackathons.ts | 228 +- lib/api/hackathons/draft.ts | 171 - lib/api/hackathons/index.ts | 4 +- lib/api/hackathons/partners.ts | 12 +- lib/api/hackathons/rewards.ts | 84 +- lib/api/hackathons/tracks.ts | 65 +- lib/api/index.ts | 22 + lib/api/openapi.ts | 28 + lib/api/organization.ts | 14 +- lib/api/types.ts | 52 +- lib/api/user/earnings.ts | 25 +- lib/api/wallet.ts | 22 +- lib/auth/logger.ts | 4 +- lib/config/tokens.ts | 89 + lib/config/wallet-kit.ts | 22 +- lib/error-reporting.ts | 87 +- lib/providers/OrganizationProvider.tsx | 617 +- lib/providers/hackathonProvider.tsx | 2 +- lib/stores/auth-store.ts | 422 - lib/utils/hackathon-escrow.ts | 194 +- lib/utils/hackathon-form-transforms.ts | 237 +- lib/utils/hackathon-step-validation.ts | 58 +- lib/utils/hackathon-winner-distribution.ts | 163 - lib/utils/prize-tier-matcher.ts | 146 - lib/utils/publish-op-storage.ts | 39 + lib/wallet/wallet-kit.ts | 114 + next.config.ts | 9 +- openapi.snapshot.json | 32611 ++++++++++++++ package-lock.json | 12486 ++++-- package.json | 6 +- sentry.edge.config.ts | 12 - sentry.server.config.ts | 12 - types/earnings.ts | 20 +- types/hackathon/core.ts | 2 + types/hackathon/draft.ts | 5 +- types/hackathon/rewards.ts | 54 - 116 files changed, 84941 insertions(+), 7547 deletions(-) delete mode 100644 app/(landing)/hackathons/[slug]/components/tabs/contents/index.tsx create mode 100644 app/(landing)/organizations/[id]/treasury/page.tsx delete mode 100644 components/hackathons/overview/RegisterHackathonModal.tsx create mode 100644 components/hackathons/submissions/SubmissionAnchorProgress.tsx create mode 100644 components/organization/hackathons/HackathonPublishStatusBanner.tsx create mode 100644 components/organization/hackathons/new/FundingConfirmationModal.tsx create mode 100644 components/organization/hackathons/new/FundingProgressModal.tsx delete mode 100644 components/organization/hackathons/rewards/CreateMilestonesDialog.tsx delete mode 100644 components/organization/hackathons/rewards/EscrowStatusCard.tsx delete mode 100644 components/organization/hackathons/rewards/RewardDistributionStatusBanner.tsx create mode 100644 components/organization/hackathons/rewards/RewardPayoutProgressModal.tsx delete mode 100644 components/organization/hackathons/rewards/WinnerFormItem.tsx create mode 100644 components/organization/treasury/AuditLog.tsx create mode 100644 components/organization/treasury/PolicyEditor.tsx create mode 100644 components/organization/treasury/SpendInbox.tsx create mode 100644 components/organization/treasury/WalletsSection.tsx delete mode 100644 components/providers/auth-provider.tsx create mode 100644 features/hackathons/api/draft-client.ts create mode 100644 features/hackathons/api/escrow-client.ts create mode 100644 features/hackathons/api/keys.ts create mode 100644 features/hackathons/api/use-draft.ts create mode 100644 features/hackathons/api/use-escrow.ts create mode 100644 features/hackathons/api/use-submission-anchor.ts rename {hooks/hackathon => features/hackathons/api}/use-submission.ts (78%) create mode 100644 features/hackathons/index.ts create mode 100644 features/hackathons/types.ts create mode 100644 features/treasury/api.ts create mode 100644 features/treasury/index.ts create mode 100644 features/treasury/keys.ts create mode 100644 features/treasury/types.ts create mode 100644 features/treasury/use-treasury-audit.ts create mode 100644 features/treasury/use-treasury-policy.ts create mode 100644 features/treasury/use-treasury-spend.ts create mode 100644 features/treasury/use-treasury-wallets.ts create mode 100644 hooks/hackathon/use-cancel-hackathon.ts delete mode 100644 hooks/hackathon/use-register-hackathon.ts delete mode 100644 hooks/use-reward-distribution-status.ts delete mode 100644 instrumentation-client.ts delete mode 100644 instrumentation.ts create mode 100644 lib/api/client.ts create mode 100644 lib/api/generated/schema.d.ts delete mode 100644 lib/api/hackathons/draft.ts create mode 100644 lib/api/index.ts create mode 100644 lib/api/openapi.ts create mode 100644 lib/config/tokens.ts delete mode 100644 lib/stores/auth-store.ts delete mode 100644 lib/utils/hackathon-winner-distribution.ts delete mode 100644 lib/utils/prize-tier-matcher.ts create mode 100644 lib/utils/publish-op-storage.ts create mode 100644 lib/wallet/wallet-kit.ts create mode 100644 openapi.snapshot.json delete mode 100644 sentry.edge.config.ts delete mode 100644 sentry.server.config.ts diff --git a/.env.example b/.env.example index 50e04a865..34910cd13 100644 --- a/.env.example +++ b/.env.example @@ -22,12 +22,10 @@ NEXT_PUBLIC_GOOGLE_CLIENT_ID="" NEXT_PUBLIC_HORIZON_PUBLIC_URL="https://horizon.stellar.org" NEXT_PUBLIC_HORIZON_TESTNET_URL="https://horizon-testnet.stellar.org" NEXT_PUBLIC_STELLAR_NETWORK="testnet" +# Whitelisted USDC SAC (Soroban contract C-address) used as the escrow tokenAddress. +# Must match the boundless-events contract's whitelisted token (see backend admin runbook). +NEXT_PUBLIC_USDC_TOKEN_CONTRACT_TESTNET="CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" +NEXT_PUBLIC_USDC_TOKEN_CONTRACT_PUBLIC="" NEXT_PUBLIC_TRUSTLESS_WORK_API_KEY="" NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID="your_wallet_connect_project_id" -# Error reporting (optional). When set, errors are sent to Sentry. -NEXT_PUBLIC_SENTRY_DSN="" -SENTRY_DSN="" -SENTRY_ORG="" -SENTRY_PROJECT="boundless-next" -SENTRY_AUTH_TOKEN="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" NODE_ENV="dev" \ No newline at end of file diff --git a/app/(landing)/hackathons/[slug]/components/SponsorsSection.tsx b/app/(landing)/hackathons/[slug]/components/SponsorsSection.tsx index 14dade6df..843c97a2d 100644 --- a/app/(landing)/hackathons/[slug]/components/SponsorsSection.tsx +++ b/app/(landing)/hackathons/[slug]/components/SponsorsSection.tsx @@ -1,7 +1,7 @@ 'use client'; -import { useEffect, useState } from 'react'; import { Loader2 } from 'lucide-react'; +import { useQuery } from '@tanstack/react-query'; import { getPublicContributors, type PublicContributorsResponse, @@ -56,25 +56,23 @@ export default function SponsorsSection({ slug, marketingPartners, }: SponsorsSectionProps) { - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - let cancelled = false; - (async () => { + // Shared, cached query. Replaces a manual effect that re-fetched the + // contributors endpoint on every mount / StrictMode pass and 404'd loudly for + // hackathons without sponsors. Any failure (incl. 404) maps to "no + // contributors" and is cached, so React Query doesn't re-request. + const { data, isLoading: loading } = useQuery({ + queryKey: ['hackathon', slug, 'contributors'], + queryFn: async (): Promise => { try { const res = await getPublicContributors(slug); - if (!cancelled) setData(res.data ?? null); + return res.data ?? null; } catch { - // Silent fail — sponsors section is non-critical. - } finally { - if (!cancelled) setLoading(false); + return null; } - })(); - return () => { - cancelled = true; - }; - }, [slug]); + }, + enabled: !!slug, + staleTime: 60_000, + }); const contributors = data?.contributors ?? []; const validMarketing = (marketingPartners ?? []).filter( diff --git a/app/(landing)/hackathons/[slug]/components/sidebar/MySubmissionPanel.tsx b/app/(landing)/hackathons/[slug]/components/sidebar/MySubmissionPanel.tsx index d16107015..24f0730c5 100644 --- a/app/(landing)/hackathons/[slug]/components/sidebar/MySubmissionPanel.tsx +++ b/app/(landing)/hackathons/[slug]/components/sidebar/MySubmissionPanel.tsx @@ -3,7 +3,7 @@ import { useParams, useRouter } from 'next/navigation'; import { CheckCircle2, FileText, ShieldX, Trophy } from 'lucide-react'; import { useAuthStatus } from '@/hooks/use-auth'; -import { useSubmission } from '@/hooks/hackathon/use-submission'; +import { useSubmission } from '@/features/hackathons'; import { useHackathonData } from '@/lib/providers/hackathonProvider'; import { Skeleton } from '@/components/ui/skeleton'; import { BoundlessButton } from '@/components/buttons'; diff --git a/app/(landing)/hackathons/[slug]/components/sidebar/PoolAndAction.tsx b/app/(landing)/hackathons/[slug]/components/sidebar/PoolAndAction.tsx index f18c134e5..700352de1 100644 --- a/app/(landing)/hackathons/[slug]/components/sidebar/PoolAndAction.tsx +++ b/app/(landing)/hackathons/[slug]/components/sidebar/PoolAndAction.tsx @@ -1,7 +1,7 @@ 'use client'; import { useEffect, useState } from 'react'; -import { useParams, useRouter } from 'next/navigation'; +import { useParams } from 'next/navigation'; import Link from 'next/link'; import { Clock, @@ -9,17 +9,22 @@ import { ChevronRight, Flower, AlertCircle, + UserPlus, } from 'lucide-react'; import { useHackathonData } from '@/lib/providers/hackathonProvider'; -import { useHackathonTracks } from '@/hooks/hackathon/use-hackathon-queries'; +import { + useHackathonTracks, + useJoinHackathon, +} from '@/hooks/hackathon/use-hackathon-queries'; import { useOptionalAuth } from '@/hooks/use-auth'; import { useRequireAuthForAction } from '@/hooks/use-require-auth-for-action'; -import { useSubmission } from '@/hooks/hackathon/use-submission'; +import { useSubmission } from '@/features/hackathons'; import { Badge } from '@/components/ui/badge'; import { Skeleton } from '@/components/ui/skeleton'; import Image from 'next/image'; import { BoundlessButton } from '@/components/buttons'; import { cn } from '@/lib/utils'; +import { toast } from 'sonner'; import { ExtendedBadge } from '@/components/hackathons/ExtendedBadge'; import { Participant } from '@/lib/api/hackathons'; @@ -59,7 +64,6 @@ function useCountdown(deadline?: string) { export default function PoolAndAction() { const params = useParams(); - const router = useRouter(); const { user, isAuthenticated } = useOptionalAuth(); const slug = params.slug as string; @@ -77,6 +81,7 @@ export default function PoolAndAction() { submissions, error, loading, + refreshCurrentHackathon, } = useHackathonData(); const hackathonError = error; const isDataLoading = loading || !hackathon; @@ -134,22 +139,25 @@ export default function PoolAndAction() { // // `redirectTo` is still set so Google sign-in (a full provider redirect // that bypasses onAuthSuccess) lands somewhere sensible. - const submitUrl = `/hackathons/${slug}/submit`; - const handleSubmit = withAuth( - () => { - if (isButtonDisabled) return; - router.push(submitUrl); - }, - { - redirectTo: submitUrl, - onAuthSuccess: () => { - const popup = window.open(submitUrl, '_blank', 'noopener,noreferrer'); - if (!popup) { - router.push(submitUrl); - } - }, + // A non-participant who wants to submit is routed through JOIN first (the + // header JOIN does the same). A hackathon has no on-chain "join" — it's a DB + // registration — so this is a plain mutation; on success the participation + // refresh flips the CTA to "Submit Now". withAuth opens the auth modal when + // the viewer is signed out. + const joinMutation = useJoinHackathon(slug); + const handleJoinToSubmit = withAuth(async () => { + try { + await joinMutation.mutateAsync(); + await refreshCurrentHackathon(); + toast.success( + 'You joined the hackathon — you can now submit your project.' + ); + } catch (err) { + toast.error( + err instanceof Error ? err.message : 'Failed to join hackathon' + ); } - ); + }); if (isDataLoading) { return ( @@ -191,14 +199,16 @@ export default function PoolAndAction() { if (hackathon?.status === 'CANCELLED') return 'Hackathon Cancelled'; if (isEnded) return 'Submissions Closed'; if (isNotStarted) return 'Hackathon Not Started'; - if (!isParticipant) return 'Register to Submit'; + if (!isParticipant) return 'Join to Submit'; return 'Submit Now'; }; - const isButtonDisabled = + // "Closed" = the hackathon itself can't take submissions (ended / not yet + // started / archived / cancelled). NOT being a participant is NOT closed — + // that's an actionable "join first" state, handled separately below. + const isClosed = isEnded || isNotStarted || - !isParticipant || ['ARCHIVED', 'CANCELLED'].includes(hackathon?.status || ''); return ( @@ -362,27 +372,29 @@ export default function PoolAndAction() { users still get the button so the auth modal can intercept in place. */} {!hasSubmitted && - (isButtonDisabled || !isAuthenticated ? ( + (isClosed ? ( + // Non-actionable status (ended / not started / archived / cancelled). + + {getButtonText()} + + ) : !isParticipant ? ( + // Open, but the viewer hasn't joined — JOIN first (auth-gated). - ) - } + icon={} > {getButtonText()} ) : ( + // Participant + open — go to the submit form. - - {children} - - + + {children} + ); } diff --git a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/page.tsx b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/page.tsx index da4ea8e5d..2bacb2194 100644 --- a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/page.tsx +++ b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/page.tsx @@ -9,7 +9,7 @@ import { Check, } from 'lucide-react'; import { useHackathons } from '@/hooks/use-hackathons'; -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { useHackathonAnalytics } from '@/hooks/use-hackathon-analytics'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { HackathonStatistics } from '@/components/organization/hackathons/details/HackathonStatistics'; @@ -17,22 +17,14 @@ import { HackathonCharts } from '@/components/organization/hackathons/details/Ha import { HackathonTimeline } from '@/components/organization/hackathons/details/HackathonTimeline'; import { AuthGuard } from '@/components/auth'; import Loading from '@/components/Loading'; -import HackathonPublishedModal from '@/components/organization/hackathons/new/tabs/components/review/HackathonPublishedModal'; import { ExportButton } from '@/components/organization/hackathons/details/ExportButton'; -import type { PublishResponseData } from '@/hooks/use-hackathon-publish'; - -const STORAGE_KEY = 'boundless_hackathon_published'; +import HackathonPublishStatusBanner from '@/components/organization/hackathons/HackathonPublishStatusBanner'; export default function HackathonPage() { const params = useParams(); const organizationId = params.id as string; const hackathonId = params.hackathonId as string; - const [publishedModalData, setPublishedModalData] = useState<{ - publishResponse: PublishResponseData; - organizationId: string; - } | null>(null); - const { currentHackathon, currentLoading, currentError, fetchHackathon } = useHackathons({ organizationId, @@ -51,37 +43,6 @@ export default function HackathonPage() { } }, [organizationId, hackathonId, fetchHackathon]); - useEffect(() => { - try { - const raw = sessionStorage.getItem(STORAGE_KEY); - if (!raw) return; - const payload = JSON.parse(raw) as { - organizationId: string; - id: string; - slug: string; - publishedAt: string; - message: string; - escrowAddress: string; - transactionHash: string | null; - }; - if (payload.id !== hackathonId) return; - sessionStorage.removeItem(STORAGE_KEY); - setPublishedModalData({ - publishResponse: { - id: payload.id, - slug: payload.slug, - publishedAt: payload.publishedAt, - message: payload.message, - escrowAddress: payload.escrowAddress, - transactionHash: payload.transactionHash, - }, - organizationId: payload.organizationId, - }); - } catch { - // ignore - } - }, [hackathonId]); - if (currentLoading) { return (
@@ -136,15 +97,6 @@ export default function HackathonPage() { return ( }>
- { - if (!open) setPublishedModalData(null); - }} - publishResponse={publishedModalData?.publishResponse ?? null} - organizationId={publishedModalData?.organizationId} - /> - {/* Hero Section with Hackathon Name */}
@@ -161,6 +113,16 @@ export default function HackathonPage() { {/* Main Content */}
+ {/* Resumes an in-flight publish (DRAFT_AWAITING_FUNDING) on load. */} + { + void fetchHackathon(hackathonId); + }} + /> + {/* Statistics Section */}
diff --git a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/rewards/page.tsx b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/rewards/page.tsx index ae88666f2..c105daed5 100644 --- a/app/(landing)/organizations/[id]/hackathons/[hackathonId]/rewards/page.tsx +++ b/app/(landing)/organizations/[id]/hackathons/[hackathonId]/rewards/page.tsx @@ -1,15 +1,30 @@ 'use client'; -import React, { useState, useMemo } from 'react'; +import React, { useState, useMemo, useEffect } from 'react'; import { useParams } from 'next/navigation'; import { Loader2, AlertCircle } from 'lucide-react'; +import { toast } from 'sonner'; import PublishWinnersWizard from '@/components/organization/hackathons/rewards/PublishWinnersWizard'; import { RewardsPageHeader } from '@/components/organization/hackathons/rewards/RewardsPageHeader'; import { RewardsPageContent } from '@/components/organization/hackathons/rewards/RewardsPageContent'; import { useHackathonRewards } from '@/hooks/use-hackathon-rewards'; -import { useRewardDistributionStatus } from '@/hooks/use-reward-distribution-status'; import { useRankAssignment } from '@/hooks/use-rank-assignment'; +import { + publishJudgingResults, + getJudgingCompleteness, + type JudgingCompletenessPreview, +} from '@/lib/api/hackathons/judging'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog'; import { AuthGuard } from '@/components/auth'; import Loading from '@/components/Loading'; @@ -21,13 +36,10 @@ export default function RewardsPage() { const { submissions, setSubmissions, - escrow, prizeTiers, isLoading, - isLoadingEscrow, isLoadingSubmissions, error, - refreshEscrow, refetchHackathon, resultsPublished, hackathon, @@ -37,12 +49,67 @@ export default function RewardsPage() { const { handleRankChange } = useRankAssignment(); const [isPublishWizardOpen, setIsPublishWizardOpen] = useState(false); - const { - distributionStatus, - isLoading: isLoadingDistributionStatus, - error: distributionError, - refetch: refetchDistributionStatus, - } = useRewardDistributionStatus(organizationId, hackathonId); + // ── Step 1: Publish Results ──────────────────────────────────────── + // Reuses the judging page's confirm + acceptPartial UX so publishing + // from the rewards page handles incomplete judging the same way. + const [isPublishResultsDialogOpen, setIsPublishResultsDialogOpen] = + useState(false); + const [isPublishingResults, setIsPublishingResults] = useState(false); + const [completeness, setCompleteness] = + useState(null); + const [completenessLoading, setCompletenessLoading] = useState(false); + const [acceptPartial, setAcceptPartial] = useState(false); + + // Pull the completeness snapshot every time the dialog opens so the + // organizer sees fresh numbers before publishing. + useEffect(() => { + if (!isPublishResultsDialogOpen) { + setAcceptPartial(false); + return; + } + let cancelled = false; + setCompletenessLoading(true); + getJudgingCompleteness(organizationId, hackathonId) + .then(res => { + if (cancelled) return; + if (res.success && res.data) setCompleteness(res.data); + }) + .catch(() => { + // Non-fatal: the dialog still works, organizer just won't see + // the incompleteness summary. + }) + .finally(() => { + if (!cancelled) setCompletenessLoading(false); + }); + return () => { + cancelled = true; + }; + }, [isPublishResultsDialogOpen, organizationId, hackathonId]); + + const handlePublishResults = async () => { + setIsPublishingResults(true); + try { + const res = await publishJudgingResults(organizationId, hackathonId, { + acceptPartial, + }); + if (res.success) { + toast.success('Results published successfully!'); + setIsPublishResultsDialogOpen(false); + setAcceptPartial(false); + await refetchHackathon(); + } else { + toast.error( + (res as { message?: string }).message || 'Failed to publish results' + ); + } + } catch (err) { + toast.error( + err instanceof Error ? err.message : 'Failed to publish results' + ); + } finally { + setIsPublishingResults(false); + } + }; // `maxRank` is the number of OVERALL prize tier slots; track tiers // are not rank-numbered so they don't contribute to this cap. The @@ -59,6 +126,16 @@ export default function RewardsPage() { ); const hasWinners = winners.length > 0; + // Step 2 gate: the hackathon must be funded on-chain (events contract + // published) before winners can be paid. The Hackathon type has no + // dedicated escrow-event flag, so gate on the lifecycle status — a + // hackathon that left DRAFT/DRAFT_AWAITING_FUNDING is funded on-chain. + const canReward = useMemo(() => { + const status = hackathon?.status; + if (!status) return false; + return status !== 'DRAFT' && status !== 'DRAFT_AWAITING_FUNDING'; + }, [hackathon?.status]); + const handleRankChangeWrapper = async ( submissionId: string, newRank: number | null @@ -74,12 +151,6 @@ export default function RewardsPage() { ); }; - const handlePublishSuccess = () => { - refreshEscrow(); - refetchDistributionStatus(); - refetchHackathon(); - }; - return ( }>
@@ -107,29 +178,18 @@ export default function RewardsPage() { )} - {!isLoading && distributionError && ( - - - Distribution Status Error - {distributionError} - - )} - {!isLoading && !error && ( setIsPublishWizardOpen(true)} onRankChange={handleRankChangeWrapper} - distributionStatus={distributionStatus} - isLoadingDistributionStatus={isLoadingDistributionStatus} - onRefreshDistributionStatus={refetchDistributionStatus} + onPublishResults={() => setIsPublishResultsDialogOpen(true)} + isPublishingResults={isPublishingResults} resultsPublished={resultsPublished} - escrowAddress={hackathon?.escrowAddress || hackathon?.contractId} + canReward={canReward} trackWinners={trackWinners} /> )} @@ -139,11 +199,104 @@ export default function RewardsPage() { onOpenChange={setIsPublishWizardOpen} submissions={submissions} prizeTiers={prizeTiers} - escrow={escrow} organizationId={organizationId} hackathonId={hackathonId} - onSuccess={handlePublishSuccess} + onSuccess={() => refetchHackathon()} /> + + {/* Step 1 confirmation: mirrors the judging page's publish dialog. */} + + + + Publish Judging Results? + + This will finalize the rankings and announce the winners. This + action is irreversible. + + + + {completenessLoading && ( +

+ Checking judging progress… +

+ )} + + {completeness && completeness.complete && ( +

+ All {completeness.expectedJudgeCount} active judges have scored + every shortlisted submission. +

+ )} + + {completeness && !completeness.complete && ( +
+
+

Judging is incomplete.

+

+ {completeness.incompleteSubmissionCount} of{' '} + {completeness.totalShortlisted} shortlisted submissions are + missing scores from one or more active judges. +

+
+ {completeness.incompleteJudges.length > 0 && ( +
+

+ Judges with outstanding work +

+
    + {completeness.incompleteJudges.map(j => ( +
  • + {j.name} + + {j.missingCount} left + +
  • + ))} +
+
+ )} + +
+ )} + + + + Cancel + + + {isPublishingResults + ? 'Publishing…' + : completeness && !completeness.complete && acceptPartial + ? 'Publish anyway' + : 'Publish results'} + + +
+
); diff --git a/app/(landing)/organizations/[id]/hackathons/drafts/[draftId]/page.tsx b/app/(landing)/organizations/[id]/hackathons/drafts/[draftId]/page.tsx index e12dbe4a2..cdfc67f2b 100644 --- a/app/(landing)/organizations/[id]/hackathons/drafts/[draftId]/page.tsx +++ b/app/(landing)/organizations/[id]/hackathons/drafts/[draftId]/page.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Suspense } from 'react'; import NewHackathonTab from '@/components/organization/hackathons/new/NewHackathonTab'; import { AuthGuard } from '@/components/auth'; import Loading from '@/components/Loading'; @@ -16,7 +16,9 @@ const DraftPage = async ({ params }: DraftPageProps) => { return ( }>
- + }> + +
); diff --git a/app/(landing)/organizations/[id]/hackathons/new/page.tsx b/app/(landing)/organizations/[id]/hackathons/new/page.tsx index fc2883f31..06cfb02d7 100644 --- a/app/(landing)/organizations/[id]/hackathons/new/page.tsx +++ b/app/(landing)/organizations/[id]/hackathons/new/page.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Suspense } from 'react'; import NewHackathonTab from '@/components/organization/hackathons/new/NewHackathonTab'; import Loading from '@/components/Loading'; import { AuthGuard } from '@/components/auth'; @@ -6,7 +6,9 @@ const page = () => { return ( }>
- + }> + +
); diff --git a/app/(landing)/organizations/[id]/hackathons/page.tsx b/app/(landing)/organizations/[id]/hackathons/page.tsx index 10529736e..382df04a9 100644 --- a/app/(landing)/organizations/[id]/hackathons/page.tsx +++ b/app/(landing)/organizations/[id]/hackathons/page.tsx @@ -576,29 +576,43 @@ export default function HackathonsPage() { (sum: number, tier: any) => sum + (tier.amount || 0), 0 ) || 0; + // A hackathon mid-publish stays in the drafts list but is + // no longer editable — route it to the management page where + // the publish-status banner resumes/finishes it. + const isPublishing = + draft.status === 'DRAFT_AWAITING_FUNDING'; + const targetHref = isPublishing + ? `/organizations/${organizationId}/hackathons/${draft.id}` + : `/organizations/${organizationId}/hackathons/drafts/${draft.id}`; return (
- router.push( - `/organizations/${organizationId}/hackathons/drafts/${draft.id}` - ) - } + onClick={() => router.push(targetHref)} tabIndex={0} role='button' - aria-label={`Edit draft ${title}`} + aria-label={ + isPublishing + ? `View publishing hackathon ${title}` + : `Edit draft ${title}` + } >
- Draft + {isPublishing ? 'Publishing' : 'Draft'} - {completion}% complete + {isPublishing + ? 'Finalizing on-chain…' + : `${completion}% complete`} {endDate && ( @@ -643,29 +657,29 @@ export default function HackathonsPage() { > - + {!isPublishing && ( + + )} { e.stopPropagation(); - router.push( - `/organizations/${organizationId}/hackathons/drafts/${draft.id}` - ); + router.push(targetHref); }} > - Continue + {isPublishing ? 'View' : 'Continue'}
diff --git a/app/(landing)/organizations/[id]/treasury/page.tsx b/app/(landing)/organizations/[id]/treasury/page.tsx new file mode 100644 index 000000000..36be0ab62 --- /dev/null +++ b/app/(landing)/organizations/[id]/treasury/page.tsx @@ -0,0 +1,67 @@ +'use client'; + +import { useState } from 'react'; +import { useParams } from 'next/navigation'; +import { Landmark } from 'lucide-react'; +import { AuthGuard } from '@/components/auth'; +import Loading from '@/components/Loading'; +import WalletsSection from '@/components/organization/treasury/WalletsSection'; +import SpendInbox from '@/components/organization/treasury/SpendInbox'; +import PolicyEditor from '@/components/organization/treasury/PolicyEditor'; +import AuditLog from '@/components/organization/treasury/AuditLog'; + +type TabKey = 'wallets' | 'spend' | 'policy' | 'activity'; + +const TABS: { key: TabKey; label: string }[] = [ + { key: 'wallets', label: 'Wallets' }, + { key: 'spend', label: 'Spend' }, + { key: 'policy', label: 'Policy' }, + { key: 'activity', label: 'Activity' }, +]; + +export default function TreasuryPage() { + const params = useParams(); + const organizationId = params.id as string; + const [tab, setTab] = useState('wallets'); + + return ( + }> +
+
+
+ +

+ Treasury +

+
+
+ +
+
+ {TABS.map(t => ( + + ))} +
+ + {tab === 'wallets' && ( + + )} + {tab === 'spend' && } + {tab === 'policy' && } + {tab === 'activity' && } +
+
+
+ ); +} diff --git a/app/providers.tsx b/app/providers.tsx index df9029f6d..bbfee5261 100644 --- a/app/providers.tsx +++ b/app/providers.tsx @@ -2,7 +2,7 @@ import { ReactNode, useState } from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { AuthProvider } from '@/components/providers/auth-provider'; +import { ApiError } from '@/lib/api'; import { SocketProvider } from '@/components/providers/socket-provider'; import { WalletProvider } from '@/components/providers/wallet-provider'; import { MessagesProvider } from '@/components/messages/MessagesProvider'; @@ -22,28 +22,37 @@ export function Providers({ children }: ProvidersProps) { queries: { staleTime: 60 * 1000, // 1 minute gcTime: 5 * 60 * 1000, // 5 minutes - retry: 1, refetchOnWindowFocus: false, + // Client errors (4xx) are deterministic; retrying wastes a round trip. + retry: (failureCount, error) => { + if ( + error instanceof ApiError && + error.status >= 400 && + error.status < 500 + ) { + return false; + } + return failureCount < 2; + }, }, + mutations: { retry: false }, }, }) ); return ( - - - - - - - {children} - - - - - - + + + + + + {children} + + + + + ); } diff --git a/components/auth/LoginWrapper.tsx b/components/auth/LoginWrapper.tsx index cccef17d0..e530ff0e8 100644 --- a/components/auth/LoginWrapper.tsx +++ b/components/auth/LoginWrapper.tsx @@ -9,7 +9,6 @@ import z from 'zod'; import LoginForm from './LoginForm'; import TwoFactorVerify from './TwoFactorVerify'; import { authClient } from '@/lib/auth-client'; -import { useAuthStore } from '@/lib/stores/auth-store'; const formSchema = z.object({ email: z.string().email({ @@ -207,34 +206,6 @@ const LoginWrapper = ({ setIsLoading(true); setLoadingState(true); - const syncSession = async () => { - const session = await authClient.getSession(); - if (session && typeof session === 'object' && 'user' in session) { - const sessionUser = session.user as - | { - id: string; - email: string; - name?: string | null; - image?: string | null; - } - | null - | undefined; - - if (sessionUser && sessionUser.id && sessionUser.email) { - const authStore = useAuthStore.getState(); - await authStore.syncWithSession({ - id: sessionUser.id, - email: sessionUser.email, - name: sessionUser.name || undefined, - image: sessionUser.image || undefined, - role: 'USER', - username: undefined, - accessToken: undefined, - }); - } - } - }; - try { const { data, error } = await authClient.signIn.email( { @@ -264,7 +235,6 @@ const LoginWrapper = ({ } await new Promise(resolve => setTimeout(resolve, 200)); - await syncSession(); if (onAuthSuccess) { await onAuthSuccess(); } else { diff --git a/components/auth/OtpForm.tsx b/components/auth/OtpForm.tsx index 85d2f5ded..ac859a17b 100644 --- a/components/auth/OtpForm.tsx +++ b/components/auth/OtpForm.tsx @@ -15,7 +15,6 @@ import { } from '../ui/form'; import { InputOTP, InputOTPSlot } from '../ui/input-otp'; import { authClient } from '@/lib/auth-client'; -import { useAuthStore } from '@/lib/stores/auth-store'; const formSchema = z.object({ otp: z.string().length(6, { @@ -78,36 +77,8 @@ const OtpForm = ({ // Loading state handled by form }, onSuccess: async () => { - // Get session after successful verification - const session = await authClient.getSession(); - - // Type guard for Better Auth session - if (session && typeof session === 'object' && 'user' in session) { - const sessionUser = session.user as - | { - id: string; - email: string; - name?: string | null; - image?: string | null; - } - | null - | undefined; - - if (sessionUser && sessionUser.id && sessionUser.email) { - // Sync with Zustand store - const authStore = useAuthStore.getState(); - await authStore.syncWithSession({ - id: sessionUser.id, - email: sessionUser.email, - name: sessionUser.name || undefined, - image: sessionUser.image || undefined, - role: 'USER', // Default role - username: undefined, - accessToken: undefined, // Better Auth handles tokens via cookies - }); - } - } - + // Better Auth has established the cookie session; the app reads the + // user via useAuth/useAuthStatus, so no extra store sync is needed. toast.success('Email verified successfully!'); onOtpSuccess(); }, diff --git a/components/hackathons/HackathonsPage.tsx b/components/hackathons/HackathonsPage.tsx index 9a5c345a6..453a9ee04 100644 --- a/components/hackathons/HackathonsPage.tsx +++ b/components/hackathons/HackathonsPage.tsx @@ -41,11 +41,7 @@ const HackathonsPage: React.FC = ({ className } = {}) => { const hackathonCards = React.useMemo(() => { return hackathons.map(hackathon => { return ( - + ); }); }, [hackathons]); diff --git a/components/hackathons/overview/RegisterHackathonModal.tsx b/components/hackathons/overview/RegisterHackathonModal.tsx deleted file mode 100644 index d4a5272b1..000000000 --- a/components/hackathons/overview/RegisterHackathonModal.tsx +++ /dev/null @@ -1,92 +0,0 @@ -'use client'; - -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, -} from '@/components/ui/dialog'; -import { Button } from '@/components/ui/button'; -import { Loader2 } from 'lucide-react'; -import { useRegisterHackathon } from '@/hooks/hackathon/use-register-hackathon'; -import { toast } from 'sonner'; -import type { Hackathon } from '@/lib/api/hackathons'; - -interface RegisterHackathonModalProps { - open: boolean; - onOpenChange: (open: boolean) => void; - hackathon: Hackathon | null; - organizationId?: string; - onSuccess?: (participantData?: any) => void; -} - -export function RegisterHackathonModal({ - open, - onOpenChange, - hackathon, - organizationId, - onSuccess, -}: RegisterHackathonModalProps) { - const { register: registerForHackathon, isRegistering } = - useRegisterHackathon({ - hackathon, - organizationId, - autoCheck: false, - }); - - const handleRegister = async () => { - try { - const participantData = await registerForHackathon(); - - toast.success('Successfully registered for hackathon!'); - onOpenChange(false); - - // Pass the participant data to onSuccess - onSuccess?.(participantData); - } catch { - // Error handled in hook - } - }; - - return ( - - - - - Register for Hackathon - - - Register to participate in this hackathon - - - -
- - -
-
-
- ); -} diff --git a/components/hackathons/submissions/SubmissionAnchorProgress.tsx b/components/hackathons/submissions/SubmissionAnchorProgress.tsx new file mode 100644 index 000000000..5c2e876bd --- /dev/null +++ b/components/hackathons/submissions/SubmissionAnchorProgress.tsx @@ -0,0 +1,258 @@ +'use client'; + +import { + Loader2, + Check, + AlertTriangle, + ExternalLink, + Trophy, +} from 'lucide-react'; + +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from '@/components/ui/dialog'; +import { BoundlessButton } from '@/components/buttons'; +import { getTransactionExplorerUrl } from '@/lib/wallet-utils'; +import type { EscrowRunPhase } from '@/features/hackathons'; + +interface SubmissionAnchorProgressProps { + open: boolean; + phase: EscrowRunPhase; + txHash: string | null; + error: string | null; + isCompleted: boolean; + isFailed: boolean; + /** + * True while the participant's Boundless-managed wallet is still loading or + * provisioning. Shown as an explicit step so the on-chain anchor is never + * silently skipped for a not-yet-ready wallet. + */ + walletPreparing?: boolean; + onClose: () => void; + onRetry?: () => void; + onViewSubmission?: () => void; +} + +interface Step { + phase: EscrowRunPhase; + label: string; +} + +// Participants always anchor via their managed wallet (MANAGED) — the backend +// signs + sponsor-fee-bumps, so there is no in-browser signature step. +const ANCHOR_STEPS: Step[] = [ + { phase: 'starting', label: 'Preparing your submission' }, + { phase: 'polling', label: 'Anchoring on-chain' }, +]; + +/** + * Step-by-step on-chain anchoring progress for a hackathon submission, driven by + * the participant {@link useSubmissionAnchor} runner phase. Mirrors the org-side + * FundingProgressModal but is MANAGED-only and uses anchor-appropriate copy. A + * submission is only prize-eligible once anchoring reaches COMPLETED, so the + * modal stays put (non-dismissable) until the op settles. + */ +export default function SubmissionAnchorProgress({ + open, + phase, + txHash, + error, + isCompleted, + isFailed, + walletPreparing = false, + onClose, + onRetry, + onViewSubmission, +}: SubmissionAnchorProgressProps) { + const dismissable = isCompleted || isFailed; + + const phaseIndex = ANCHOR_STEPS.findIndex(s => s.phase === phase); + const activeIndex = isCompleted + ? ANCHOR_STEPS.length + : phaseIndex >= 0 + ? phaseIndex + : 0; + + return ( + { + // Dismissable only once anchoring settles; while in-flight it stays put + // so the participant can't lose track of an on-chain op. + if (!next && dismissable) onClose(); + }} + > + { + if (!dismissable) e.preventDefault(); + }} + onEscapeKeyDown={e => { + if (!dismissable) e.preventDefault(); + }} + > + + + {isCompleted + ? 'Submission anchored' + : isFailed + ? 'Anchoring failed' + : 'Anchoring your submission'} + + + {isCompleted + ? 'Your submission is recorded on-chain and is now eligible for prizes.' + : isFailed + ? 'Your submission is saved — you can retry anchoring anytime. It must be anchored on-chain to be eligible for prizes.' + : 'Keep this open while we record your submission on-chain.'} + + + + {isCompleted ? ( +
+
+ +
+ {txHash && } +
+ ) : isFailed ? ( +
+ +

+ {error || 'The anchoring transaction could not be completed.'} +

+
+ ) : walletPreparing ? ( +
    +
  1. + + + Preparing your Boundless wallet + +
  2. + {ANCHOR_STEPS.map(step => ( +
  3. + + {step.label} +
  4. + ))} +
+ ) : ( +
    + {ANCHOR_STEPS.map((step, i) => { + const state = + i < activeIndex + ? 'done' + : i === activeIndex + ? 'active' + : 'pending'; + return ( +
  1. + + + {step.label} + +
  2. + ); + })} + {txHash && ( +
  3. + +
  4. + )} +
+ )} + + + {isCompleted && ( + <> + + Close + + {onViewSubmission && ( + + View submission + + )} + + )} + {isFailed && ( + <> + + Close + + {onRetry && ( + Retry + )} + + )} + +
+
+ ); +} + +function StepIcon({ state }: { state: 'done' | 'active' | 'pending' }) { + if (state === 'done') { + return ( + + + + ); + } + if (state === 'active') { + return ( + + + + ); + } + return ( + + + + ); +} + +function ExplorerLink({ txHash }: { txHash: string }) { + let href = ''; + try { + href = getTransactionExplorerUrl(txHash); + } catch { + href = ''; + } + if (!href) return null; + return ( + + View transaction + + + ); +} diff --git a/components/hackathons/submissions/SubmissionForm.tsx b/components/hackathons/submissions/SubmissionForm.tsx index acb808b88..7c2dfaf53 100644 --- a/components/hackathons/submissions/SubmissionForm.tsx +++ b/components/hackathons/submissions/SubmissionForm.tsx @@ -39,8 +39,11 @@ import Stepper from '@/components/stepper/Stepper'; import { uploadService } from '@/lib/api/upload'; import { useSubmission, + useSubmissionAnchor, type SubmissionFormData, -} from '@/hooks/hackathon/use-submission'; +} from '@/features/hackathons'; +import { useWalletContext } from '@/components/providers/wallet-provider'; +import SubmissionAnchorProgress from './SubmissionAnchorProgress'; import { useHackathonData } from '@/lib/providers/hackathonProvider'; import { listTracks, type HackathonTrack } from '@/lib/api/hackathons/tracks'; import { toast } from 'sonner'; @@ -355,6 +358,65 @@ const SubmissionFormContent: React.FC = ({ autoFetch: false, }); + // ── On-chain anchoring (MANAGED) ────────────────────────────────────── + // A NEW submission must be anchored on the events contract via the + // participant's Boundless-managed wallet to be prize-eligible. We run it + // with visible progress (never a silent skip) after the row is created. + // Editing an existing submission never re-anchors — the anchor is + // deterministic and already landed at create. + const { walletAddress, refreshWallet } = useWalletContext(); + const anchor = useSubmissionAnchor(hackathonSlugOrId); + const [pendingAnchorId, setPendingAnchorId] = useState(null); + const [anchorModalOpen, setAnchorModalOpen] = useState(false); + const anchorStartedRef = useRef(false); + const walletRefreshedRef = useRef(false); + + const finishSubmit = useCallback(() => { + if (onSuccess) onSuccess(); + else if (onClose) onClose(); + else collapse(); + }, [onSuccess, onClose, collapse]); + + // Drive the anchor once the managed wallet address is available. If it isn't + // loaded yet (rare race — it's provisioned at onboarding), kick a one-shot + // refresh; the modal shows a "preparing your wallet" step meanwhile. + useEffect(() => { + if (!pendingAnchorId) return; + if (!walletAddress) { + if (!walletRefreshedRef.current) { + walletRefreshedRef.current = true; + void refreshWallet(); + } + return; + } + if (anchorStartedRef.current) return; + anchorStartedRef.current = true; + void anchor.anchor({ + submissionId: pendingAnchorId, + applicantAddress: walletAddress, + }); + // anchor + refreshWallet are stable enough; re-run only when the pending id + // or the resolved wallet address changes. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [pendingAnchorId, walletAddress]); + + const handleAnchorClose = useCallback(() => { + // The submission row exists regardless of the anchor outcome, so closing + // always proceeds (a failed anchor can be retried later). + setAnchorModalOpen(false); + finishSubmit(); + }, [finishSubmit]); + + const handleAnchorRetry = useCallback(() => { + if (!pendingAnchorId || !walletAddress) return; + anchor.reset(); + anchorStartedRef.current = true; + void anchor.anchor({ + submissionId: pendingAnchorId, + applicantAddress: walletAddress, + }); + }, [anchor, pendingAnchorId, walletAddress]); + const { myTeam, fetchMyTeam, @@ -1120,16 +1182,21 @@ const SubmissionFormContent: React.FC = ({ }; if (submissionId) { + // Editing existing submission metadata only — never re-anchors. await update(submissionId, submissionData); - } else { - await create(submissionData); + finishSubmit(); + return; } - if (onSuccess) { - onSuccess(); - } else if (onClose) { - onClose(); + + // New submission: persist the row, then anchor it on-chain (MANAGED) + // with visible progress. The anchor effect fires once the managed + // wallet address is ready. + const created = await create(submissionData); + if (created?.id) { + setPendingAnchorId(created.id); + setAnchorModalOpen(true); } else { - collapse(); + finishSubmit(); } } catch { // Error handled in hook @@ -2578,6 +2645,20 @@ const SubmissionFormContent: React.FC = ({ teamMax={currentHackathon?.teamMax} organizationId={organizationId} /> +
); }; diff --git a/components/organization/OrganizationSidebar.tsx b/components/organization/OrganizationSidebar.tsx index 2f3d45494..a8d346f62 100644 --- a/components/organization/OrganizationSidebar.tsx +++ b/components/organization/OrganizationSidebar.tsx @@ -1,6 +1,7 @@ import { Trophy, HandCoins, + Landmark, Settings, Plus, Sparkles, @@ -216,6 +217,12 @@ export default function OrganizationSidebar({ description: 'Fund amazing projects', disabled: true, }, + { + icon: Landmark, + label: 'Treasury', + href: derivedOrgId ? `/organizations/${derivedOrgId}/treasury` : '#', + description: 'Wallets and funding', + }, { icon: Settings, label: 'Settings', diff --git a/components/organization/hackathons/HackathonPublishStatusBanner.tsx b/components/organization/hackathons/HackathonPublishStatusBanner.tsx new file mode 100644 index 000000000..853a509d7 --- /dev/null +++ b/components/organization/hackathons/HackathonPublishStatusBanner.tsx @@ -0,0 +1,146 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { useQuery } from '@tanstack/react-query'; +import { toast } from 'sonner'; +import { Loader2, AlertTriangle } from 'lucide-react'; +import { getDraft } from '@/lib/api/hackathons'; +import { resetHackathonEscrowToDraft } from '@/features/hackathons'; +import { useEscrowOp } from '@/features/hackathons'; +import { + clearPublishOpId, + readPublishOpId, +} from '@/lib/utils/publish-op-storage'; + +interface HackathonPublishStatusBannerProps { + organizationId: string; + hackathonId: string; + /** Current hackathon status from the page's data. */ + status?: string; + /** + * Called when the hackathon leaves DRAFT_AWAITING_FUNDING (settled to + * UPCOMING, or reset to DRAFT on failure) so the page can refetch its copy. + */ + onResolved?: () => void; +} + +/** + * Resumes an in-flight publish without the organizer re-clicking publish. + * + * When a hackathon is stuck in DRAFT_AWAITING_FUNDING (publish requested, escrow + * op still settling), this banner: + * - polls the hackathon status as the source of truth until it leaves + * DRAFT_AWAITING_FUNDING, then tells the page to refetch; + * - best-effort polls the persisted escrow op for a richer failed/in-progress + * signal. + * Renders nothing for any other status. + */ +export default function HackathonPublishStatusBanner({ + organizationId, + hackathonId, + status, + onResolved, +}: HackathonPublishStatusBannerProps) { + const router = useRouter(); + const [isResetting, setIsResetting] = useState(false); + const isAwaiting = status === 'DRAFT_AWAITING_FUNDING'; + const opRowId = isAwaiting ? readPublishOpId(hackathonId) : null; + + // Richer phase/error when we still hold the op id from this session. + const op = useEscrowOp( + { kind: 'organizer', organizationId, hackathonId }, + opRowId, + { enabled: isAwaiting && !!opRowId } + ); + + // Source of truth: poll the hackathon until the reconciliation worker flips + // it to UPCOMING (success) or back to DRAFT (failure). Uses the org-scoped + // draft GET — the public hackathon GET 404s while it's not live. + const statusPoll = useQuery({ + queryKey: ['hackathon-publish-status', hackathonId], + queryFn: () => getDraft(organizationId, hackathonId), + enabled: isAwaiting, + refetchInterval: query => { + const s = query.state.data?.data?.status; + return s && s !== 'DRAFT_AWAITING_FUNDING' ? false : 3000; + }, + }); + + const polledStatus = statusPoll.data?.data?.status; + + useEffect(() => { + if ( + isAwaiting && + polledStatus && + polledStatus !== 'DRAFT_AWAITING_FUNDING' + ) { + onResolved?.(); + } + }, [isAwaiting, polledStatus, onResolved]); + + if (!isAwaiting) return null; + + const opFailed = op.data?.status === 'FAILED'; + const errorCode = op.data?.errorCode; + + const handleResetToDraft = async () => { + setIsResetting(true); + try { + await resetHackathonEscrowToDraft(organizationId, hackathonId); + clearPublishOpId(hackathonId); + toast.success('Moved back to draft. You can edit and republish.'); + onResolved?.(); + router.push( + `/organizations/${organizationId}/hackathons/drafts/${hackathonId}` + ); + } catch (err) { + toast.error( + err instanceof Error ? err.message : 'Failed to switch back to draft.' + ); + } finally { + setIsResetting(false); + } + }; + + return ( +
+ {opFailed ? ( + + ) : ( + + )} +
+

+ {opFailed ? 'Escrow funding failed' : 'Finalizing publication'} +

+

+ {opFailed + ? `Funding failed${ + errorCode ? ` (${errorCode})` : '' + }. The hackathon will return to draft so you can fix the issue and republish.` + : 'Publishing your hackathon — funding the escrow on-chain. This ' + + 'usually takes a few moments and resumes automatically.'} +

+ +
+
+ ); +} diff --git a/components/organization/hackathons/details/HackathonSidebar.tsx b/components/organization/hackathons/details/HackathonSidebar.tsx index ec66f48a7..3087dd2e6 100644 --- a/components/organization/hackathons/details/HackathonSidebar.tsx +++ b/components/organization/hackathons/details/HackathonSidebar.tsx @@ -257,12 +257,17 @@ export default function HackathonSidebar({ ? title.trim() || 'Untitled Hackathon' : 'Untitled Hackathon'; + // A hackathon mid-publish stays in the drafts list but can't be edited; + // route it to the management page where the publish banner resumes it. + const isPublishing = draft.status === 'DRAFT_AWAITING_FUNDING'; items.push({ id: `draft-${draft.id}`, name: title, status: 'draft', href: derivedOrgId - ? `/organizations/${derivedOrgId}/hackathons/drafts/${draft.id}` + ? isPublishing + ? `/organizations/${derivedOrgId}/hackathons/${draft.id}` + : `/organizations/${derivedOrgId}/hackathons/drafts/${draft.id}` : '#', }); }); diff --git a/components/organization/hackathons/new/FundingConfirmationModal.tsx b/components/organization/hackathons/new/FundingConfirmationModal.tsx new file mode 100644 index 000000000..52a3ccdac --- /dev/null +++ b/components/organization/hackathons/new/FundingConfirmationModal.tsx @@ -0,0 +1,524 @@ +'use client'; + +import React, { useEffect, useState } from 'react'; +import { + Lock, + Wallet, + AlertTriangle, + Landmark, + Mail, + Copy, + Check, +} from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from '@/components/ui/dialog'; +import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; +import { Label } from '@/components/ui/label'; +import { + InputOTP, + InputOTPGroup, + InputOTPSlot, +} from '@/components/ui/input-otp'; +import { BoundlessButton } from '@/components/buttons'; +import { formatCurrency } from '@/lib/utils/format-utils'; +import { formatAddress } from '@/lib/wallet-utils'; +import { copyToClipboard } from '@/lib/utils'; +import { PLATFORM_FEE } from '@/lib/utils/hackathon-escrow'; + +export interface FundingOtpRequestOutcome { + required: boolean; + alreadyVerified: boolean; + sent: boolean; +} + +export type FundingSourceKind = 'MANAGED_TREASURY' | 'EXTERNAL'; + +export interface FundingSourceItem { + id: string; + kind: FundingSourceKind; + label: string; + description: string; + /** Source G-address. Null for EXTERNAL until the user connects a wallet. */ + address: string | null; +} + +interface FundingConfirmationModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; + totalPrizePool: number; + platformFee: number; + totalFunding: number; + /** Selectable funding sources: org treasury wallets or a connected wallet. */ + sources: FundingSourceItem[]; + selectedSourceId: string; + onSelectSource: (id: string) => void; + /** USDC balance of the selected source when known (managed treasury). Undefined + * for external/unknown sources, which are validated on-chain at publish. */ + sourceUsdc?: number; + /** True while the selected treasury's balance is still loading. */ + balanceLoading?: boolean; + /** True while the Wallet Kit connect modal is resolving. */ + connecting?: boolean; + /** Open the Wallet Kit picker to connect an external wallet. */ + onConnectExternal?: () => void; + onConfirm: () => void; + isSubmitting?: boolean; + /** Optional email-OTP step-up. When provided, the confirm click first runs + * requestOtp; if a code is required, the modal collects and verifies it + * before calling onConfirm. Omit to fund without step-up. */ + requestOtp?: () => Promise; + verifyOtp?: (code: string) => Promise; +} + +function sourceIcon(kind: FundingSourceKind) { + if (kind === 'MANAGED_TREASURY') return ; + return ; +} + +/** + * The funding confirmation gate shown before any funds move. Shows what will be + * locked (prize pool + platform fee), the source wallet, and a source selector + * (an org treasury wallet or a connected wallet), with an optional email-OTP + * step-up. + */ +export default function FundingConfirmationModal({ + open, + onOpenChange, + totalPrizePool, + platformFee, + totalFunding, + sources, + selectedSourceId, + onSelectSource, + sourceUsdc, + balanceLoading = false, + connecting = false, + onConnectExternal, + onConfirm, + isSubmitting = false, + requestOtp, + verifyOtp, +}: FundingConfirmationModalProps) { + const selected = + sources.find(s => s.id === selectedSourceId) ?? sources[0] ?? null; + const isExternal = selected?.kind === 'EXTERNAL'; + const externalConnected = isExternal && !!selected?.address; + + // Up-front balance gate for sources whose USDC we can read (managed treasury). + // External sources have no readable balance here and stay gated on-chain. + const balanceKnown = + typeof sourceUsdc === 'number' && Number.isFinite(sourceUsdc); + const insufficient = balanceKnown && (sourceUsdc as number) < totalFunding; + const sourceMissing = isExternal ? !externalConnected : !selected?.address; + + const [view, setView] = useState<'review' | 'otp'>('review'); + const [code, setCode] = useState(''); + const [otpBusy, setOtpBusy] = useState(false); + const [otpError, setOtpError] = useState(null); + const [otpSent, setOtpSent] = useState(false); + const [copiedAddr, setCopiedAddr] = useState(false); + + const handleCopyAddress = (addr: string) => { + copyToClipboard(addr); + setCopiedAddr(true); + setTimeout(() => setCopiedAddr(false), 1500); + }; + + // Reset the step-up flow whenever the modal closes. + useEffect(() => { + if (!open) { + setView('review'); + setCode(''); + setOtpBusy(false); + setOtpError(null); + setOtpSent(false); + } + }, [open]); + + const reviewBlocked = + sourceMissing || insufficient || balanceLoading || isSubmitting || otpBusy; + + const proceedOrStepUp = async () => { + if (!requestOtp) { + onConfirm(); + return; + } + setOtpBusy(true); + setOtpError(null); + try { + const outcome = await requestOtp(); + if (!outcome.required || outcome.alreadyVerified) { + onConfirm(); + return; + } + setOtpSent(outcome.sent); + setCode(''); + setView('otp'); + } catch (err) { + setOtpError( + err instanceof Error + ? err.message + : 'Could not start verification. Try again.' + ); + } finally { + setOtpBusy(false); + } + }; + + const verifyAndConfirm = async () => { + if (!verifyOtp || code.length !== 6) return; + setOtpBusy(true); + setOtpError(null); + try { + await verifyOtp(code); + onConfirm(); + } catch (err) { + setOtpError( + err instanceof Error + ? err.message + : 'That code is not right. Try again.' + ); + } finally { + setOtpBusy(false); + } + }; + + const resendCode = async () => { + if (!requestOtp) return; + setOtpBusy(true); + setOtpError(null); + try { + const outcome = await requestOtp(); + setOtpSent(outcome.sent); + } catch (err) { + setOtpError( + err instanceof Error ? err.message : 'Could not resend the code.' + ); + } finally { + setOtpBusy(false); + } + }; + + return ( + + + {view === 'otp' ? ( + <> + + + + Verify it's you + + + {otpSent + ? 'Enter the 6-digit code we emailed you to authorize funding.' + : 'Enter your funding code to continue.'} + + + +
+ + + + + + + + + + + + {otpError && ( +

+ + {otpError} +

+ )} + + +
+ + + setView('review')} + disabled={otpBusy} + className='border-gray-700' + > + Back + + + {otpBusy ? 'Verifying…' : 'Verify & fund'} + + + + ) : ( + <> + + + + Fund & publish hackathon + + + Publishing locks the prize pool in escrow on-chain. Review the + amount and source before confirming. + + + +
+ {/* Amount breakdown */} +
+
+ + +
+ + Total to lock + + + {formatCurrency(totalFunding)} + +
+
+
+ + {/* Selected source detail */} +
+
+ + {selected ? sourceIcon(selected.kind) : null} + {selected?.label ?? 'No source'} + + {selected?.address ? ( + + ) : ( + + Not connected + + )} +
+ + {balanceKnown ? ( + <> +
+ + USDC balance + + + {formatCurrency(sourceUsdc as number)} + +
+ {insufficient && ( +
+ + + Insufficient USDC. You need{' '} + {formatCurrency(totalFunding)} but this wallet holds{' '} + {formatCurrency(sourceUsdc as number)}. Top it up or + pick another source. + +
+ )} + + ) : ( +
+

+ {balanceLoading + ? 'Checking balance…' + : isExternal && !externalConnected + ? 'Connect a wallet that holds the prize pool in USDC.' + : 'USDC is checked on-chain when you publish.'} +

+ {isExternal && externalConnected && onConnectExternal && ( + + )} +
+ )} +
+ + {/* Funding source selector */} +
+ + + {sources.map(s => ( + + ))} + +

+ + + The selected wallet must already hold the full amount in + USDC. Fund your Boundless managed wallet, or connect a + funded external wallet, before publishing. + +

+
+ + {otpError && ( +

+ + {otpError} +

+ )} +
+ + + onOpenChange(false)} + disabled={isSubmitting || otpBusy || connecting} + className='border-gray-700' + > + Cancel + + {isExternal && !externalConnected ? ( + + {connecting ? 'Connecting…' : 'Connect wallet'} + + ) : ( + + {balanceLoading + ? 'Checking balance…' + : insufficient + ? 'Insufficient USDC' + : isSubmitting || otpBusy + ? 'Starting…' + : `Fund ${formatCurrency(totalFunding)} & publish`} + + )} + + + )} +
+
+ ); +} + +function Row({ + label, + value, + muted, +}: { + label: string; + value: string; + muted?: boolean; +}) { + return ( +
+ {label} + + {value} + +
+ ); +} + +function SourceOption({ + value, + selected, + title, + description, + icon, +}: { + value: string; + selected: boolean; + title: string; + description: string; + icon: React.ReactNode; +}) { + return ( + + ); +} diff --git a/components/organization/hackathons/new/FundingProgressModal.tsx b/components/organization/hackathons/new/FundingProgressModal.tsx new file mode 100644 index 000000000..e4f707e57 --- /dev/null +++ b/components/organization/hackathons/new/FundingProgressModal.tsx @@ -0,0 +1,248 @@ +'use client'; + +import React from 'react'; +import { + Loader2, + Check, + AlertTriangle, + ExternalLink, + PartyPopper, +} from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from '@/components/ui/dialog'; +import { BoundlessButton } from '@/components/buttons'; +import { getTransactionExplorerUrl } from '@/lib/wallet-utils'; +import type { EscrowRunPhase } from '@/features/hackathons'; +import type { FundingMode } from '@/features/hackathons'; + +interface FundingProgressModalProps { + open: boolean; + phase: EscrowRunPhase; + txHash: string | null; + error: string | null; + isCompleted: boolean; + isFailed: boolean; + fundingMode: FundingMode; + onClose: () => void; + onRetry?: () => void; + onSwitchToDraft?: () => void; + onViewHackathon?: () => void; +} + +interface Step { + phase: EscrowRunPhase; + label: string; +} + +const MANAGED_STEPS: Step[] = [ + { phase: 'starting', label: 'Preparing transaction' }, + { phase: 'polling', label: 'Funding escrow on-chain' }, +]; + +const EXTERNAL_STEPS: Step[] = [ + { phase: 'starting', label: 'Preparing transaction' }, + { phase: 'signing', label: 'Awaiting your signature' }, + { phase: 'submitting', label: 'Submitting transaction' }, + { phase: 'polling', label: 'Funding escrow on-chain' }, +]; + +/** + * Step-by-step funding progress, driven by the EscrowOpRunner phase. Replaces + * the button-label-only loading so the organizer can see exactly where their + * funding is (preparing -> signing -> submitting -> confirming -> done) and + * recover cleanly on failure. + */ +export default function FundingProgressModal({ + open, + phase, + txHash, + error, + isCompleted, + isFailed, + fundingMode, + onClose, + onRetry, + onSwitchToDraft, + onViewHackathon, +}: FundingProgressModalProps) { + const steps = fundingMode === 'EXTERNAL' ? EXTERNAL_STEPS : MANAGED_STEPS; + const dismissable = isCompleted || isFailed; + + const phaseIndex = steps.findIndex(s => s.phase === phase); + const activeIndex = isCompleted + ? steps.length + : phaseIndex >= 0 + ? phaseIndex + : 0; + + return ( + { + // Only dismissable once funding has settled; while in-flight the modal + // stays put so the organizer can't lose track of an on-chain op. + if (!next && dismissable) onClose(); + }} + > + { + if (!dismissable) e.preventDefault(); + }} + onEscapeKeyDown={e => { + if (!dismissable) e.preventDefault(); + }} + > + + + {isCompleted + ? 'Hackathon published' + : isFailed + ? 'Funding failed' + : 'Funding your hackathon'} + + + {isCompleted + ? 'Your prize pool is locked in escrow and the hackathon is live.' + : isFailed + ? 'No funds moved. You can retry or move it back to draft.' + : 'Keep this open while the escrow is funded on-chain.'} + + + + {isCompleted ? ( +
+
+ +
+ {txHash && } +
+ ) : isFailed ? ( +
+ +

+ {error || 'The funding transaction could not be completed.'} +

+
+ ) : ( +
    + {steps.map((step, i) => { + const state = + i < activeIndex + ? 'done' + : i === activeIndex + ? 'active' + : 'pending'; + return ( +
  1. + + + {step.label} + +
  2. + ); + })} + {txHash && ( +
  3. + +
  4. + )} +
+ )} + + + {isCompleted && ( + <> + + Close + + {onViewHackathon && ( + + View hackathon + + )} + + )} + {isFailed && ( + <> + {onSwitchToDraft && ( + + Back to draft + + )} + {onRetry && ( + Retry + )} + + )} + +
+
+ ); +} + +function StepIcon({ state }: { state: 'done' | 'active' | 'pending' }) { + if (state === 'done') { + return ( + + + + ); + } + if (state === 'active') { + return ( + + + + ); + } + return ( + + + + ); +} + +function ExplorerLink({ txHash }: { txHash: string }) { + let href = ''; + try { + href = getTransactionExplorerUrl(txHash); + } catch { + href = ''; + } + if (!href) return null; + return ( + + View transaction + + + ); +} diff --git a/components/organization/hackathons/new/NewHackathonTab.tsx b/components/organization/hackathons/new/NewHackathonTab.tsx index aa205c38d..edf585614 100644 --- a/components/organization/hackathons/new/NewHackathonTab.tsx +++ b/components/organization/hackathons/new/NewHackathonTab.tsx @@ -1,8 +1,8 @@ 'use client'; import { useMemo, useCallback, useRef, useEffect, useState } from 'react'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { Tabs, TabsContent } from '@/components/ui/tabs'; -import { useHackathons } from '@/hooks/use-hackathons'; import { useHackathonSteps } from '@/hooks/use-hackathon-steps'; import { useHackathonDraft } from '@/hooks/use-hackathon-draft'; import { useHackathonPublish } from '@/hooks/use-hackathon-publish'; @@ -16,9 +16,33 @@ import ResourcesTab from './tabs/ResourcesTab'; import JudgingTab from './tabs/JudgingTab'; import CollaborationTab from './tabs/CollaborationTab'; import ReviewTab from './tabs/ReviewTab'; -import PrePublishAnnounceDialog from './PrePublishAnnounceDialog'; +import FundingConfirmationModal from './FundingConfirmationModal'; +import type { FundingSourceItem } from './FundingConfirmationModal'; +import FundingProgressModal from './FundingProgressModal'; import type { StepKey } from './constants'; import { isStepDataValid } from '@/lib/utils/hackathon-step-validation'; +import { usePrizePoolCalculations } from '@/hooks/use-prize-pool-calculations'; +import { + requestHackathonFundingOtp, + verifyHackathonFundingOtp, + type FundingMode, +} from '@/features/hackathons'; +import { connectWallet } from '@/lib/wallet/wallet-kit'; +import { useTreasuryWallets } from '@/features/treasury'; +import { useQuery } from '@tanstack/react-query'; +import { getWalletBalanceByAddress } from '@/lib/api/wallet'; +import { formatAddress } from '@/lib/wallet-utils'; +import { toast } from 'sonner'; + +/** Surface the backend's specific funding-OTP message (expired / wrong / rate + * limited) instead of a generic axios error string. */ +function fundingOtpErrorMessage(err: unknown, fallback: string): string { + const message = (err as { response?: { data?: { message?: unknown } } }) + ?.response?.data?.message; + if (typeof message === 'string') return message; + if (Array.isArray(message) && message.length > 0) return String(message[0]); + return err instanceof Error ? err.message : fallback; +} interface NewHackathonTabProps { organizationId?: string; @@ -41,10 +65,15 @@ export default function NewHackathonTab({ return undefined; }, [organizationId]); - const { publishDraftAction } = useHackathons({ - organizationId: derivedOrgId, - autoFetch: false, - }); + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + + // draftId can arrive via the route path (/drafts/[draftId]) or, on the /new + // flow, via a ?draftId= query we add after the first save. Either resumes the + // same draft on refresh. + const resolvedInitialDraftId = + initialDraftId ?? searchParams.get('draftId') ?? undefined; const { activeTab, @@ -63,6 +92,7 @@ export default function NewHackathonTab({ const { draftId, + draftStatus, stepData, setStepData, isLoadingDraft, @@ -72,7 +102,7 @@ export default function NewHackathonTab({ saveStep, } = useHackathonDraft({ organizationId: derivedOrgId, - initialDraftId, + initialDraftId: resolvedInitialDraftId, onDraftLoaded: (formData, firstIncompleteStep) => { // Use the ref to call the callback if (onDraftLoadedRef.current) { @@ -81,6 +111,17 @@ export default function NewHackathonTab({ }, }); + // Persist a freshly-created draft id into the URL so a refresh resumes the + // same draft. The /drafts/[draftId] route already carries it in the path; + // this covers the /new flow by adding ?draftId= after the first save. + useEffect(() => { + if (!draftId || initialDraftId) return; + if (searchParams.get('draftId') === draftId) return; + const params = new URLSearchParams(searchParams.toString()); + params.set('draftId', draftId); + router.replace(`${pathname}?${params.toString()}`, { scroll: false }); + }, [draftId, initialDraftId, searchParams, pathname, router]); + // Define the callback after hooks are initialized const onDraftLoaded = useCallback( (formData: any, firstIncompleteStep: StepKey) => { @@ -127,12 +168,142 @@ export default function NewHackathonTab({ onDraftLoadedRef.current = onDraftLoaded; }, [onDraftLoaded]); - const { isPublishing, publish, publishResponse } = useHackathonPublish({ - organizationId: derivedOrgId || '', - stepData, - draftId: draftId || '', - publishDraftAction, + // Funding source selection: an org treasury wallet or a connected (external) + // wallet. Defaults to the org's canonical treasury (see below); the + // confirmation modal lets the organizer switch before funds move. + const [selectedSourceId, setSelectedSourceId] = useState('external'); + const [confirmOpen, setConfirmOpen] = useState(false); + const [progressOpen, setProgressOpen] = useState(false); + // EXTERNAL funding: the connected wallet (Stellar Wallets Kit) that funds + signs. + const [externalAddress, setExternalAddress] = useState(null); + const [connecting, setConnecting] = useState(false); + + const { totalPrizePool, platformFee, totalFunding } = + usePrizePoolCalculations(stepData.rewards); + + // Build the selectable funding sources: org treasury (managed) wallets and a + // connected (external) wallet. Personal/burner wallets are intentionally not + // offered — org escrow funds from the treasury or a connected wallet. + const treasuryQuery = useTreasuryWallets(derivedOrgId); + const fundingSources = useMemo(() => { + const items: FundingSourceItem[] = []; + for (const w of treasuryQuery.data ?? []) { + if (w.kind === 'MANAGED' && w.status === 'ACTIVE') { + items.push({ + id: w.id, + kind: 'MANAGED_TREASURY', + label: `${w.label} (treasury)`, + description: `Org treasury wallet · ${formatAddress(w.publicKey, 4)}`, + address: w.publicKey, + }); + } + } + items.push({ + id: 'external', + kind: 'EXTERNAL', + label: 'Connected wallet', + description: 'You sign the transaction in your own wallet.', + address: externalAddress, + }); + return items; + }, [treasuryQuery.data, externalAddress]); + + // Default the funding source to the org's canonical treasury wallet when one + // exists (the contract-auth identity), unless the organizer explicitly picks + // another. This keeps org events fundable + operable by any privileged member + // instead of being bound to a member's personal/burner wallet. + const sourcePickedRef = useRef(false); + const defaultTreasuryId = useMemo(() => { + const list = treasuryQuery.data ?? []; + const def = + list.find( + w => w.kind === 'MANAGED' && w.status === 'ACTIVE' && w.isDefault + ) ?? list.find(w => w.kind === 'MANAGED' && w.status === 'ACTIVE'); + return def?.id ?? null; + }, [treasuryQuery.data]); + useEffect(() => { + if (!sourcePickedRef.current && defaultTreasuryId) { + setSelectedSourceId(defaultTreasuryId); + } + }, [defaultTreasuryId]); + + const handleSelectSource = useCallback((id: string) => { + sourcePickedRef.current = true; + setSelectedSourceId(id); + }, []); + + // Funding mode + owner are derived from the EXPLICIT selection id: the + // connected-wallet option always has id 'external'; anything else is a treasury + // walletId. We deliberately do NOT key off a resolved source with a list + // fallback — if the wallets query is momentarily empty, that fallback could + // flip a treasury selection to the connected wallet and silently fund from it. + // Keying off the id guarantees a treasury selection always funds from a + // treasury (and only an explicit 'external' selection funds externally). + const isExternalSource = selectedSourceId === 'external'; + const selectedTreasury = isExternalSource + ? undefined + : fundingSources.find( + s => s.id === selectedSourceId && s.kind === 'MANAGED_TREASURY' + ); + const fundingMode: FundingMode = isExternalSource ? 'EXTERNAL' : 'MANAGED'; + const treasurySource = selectedTreasury?.address + ? { walletId: selectedTreasury.id, address: selectedTreasury.address } + : null; + // The connected external wallet is the owner ONLY when external is selected. + const externalOwnerAddress = isExternalSource ? externalAddress : null; + // The actual on-chain funder, for the pre-flight balance check. + const funderAddress = isExternalSource + ? externalAddress + : (selectedTreasury?.address ?? null); + + // Pre-flight USDC check: read the funder's on-chain USDC balance by address and + // block publish up front when it can't cover the prize pool + fee, instead of + // letting the escrow transfer revert on-chain. Covers managed/connected + // treasuries and connected external wallets alike (incl. a wallet not + // registered to this org). + const sourceAddress = funderAddress ?? undefined; + const sourceBalanceQuery = useQuery({ + queryKey: ['wallet-balance', sourceAddress], + queryFn: () => getWalletBalanceByAddress(sourceAddress as string), + enabled: !!sourceAddress, + staleTime: 15_000, }); + const selectedSourceUsdc = sourceAddress + ? Number.parseFloat(sourceBalanceQuery.data?.usdc ?? '') + : undefined; + const balanceLoading = !!sourceAddress && sourceBalanceQuery.isLoading; + + const { isPublishing, publish, escrowPhase, escrowError, escrowTxHash } = + useHackathonPublish({ + organizationId: derivedOrgId || '', + stepData, + draftId: draftId || '', + fundingMode, + externalOwnerAddress, + treasurySource, + }); + + const isFundingComplete = escrowPhase === 'completed'; + const isFundingFailed = escrowPhase === 'failed'; + + // Mirror the live phase into a ref so a confirm handler can tell, right after + // publish() resolves, whether the runner actually started (vs a pre-flight + // bail that only toasted). + const escrowPhaseRef = useRef(escrowPhase); + useEffect(() => { + escrowPhaseRef.current = escrowPhase; + }, [escrowPhase]); + + // Publishing now spans an on-chain settle; surface the current step. + const publishStatusLabel = !isPublishing + ? undefined + : escrowPhase === 'signing' + ? 'Awaiting signature…' + : escrowPhase === 'submitting' + ? 'Submitting transaction…' + : escrowPhase === 'polling' + ? 'Funding escrow on-chain…' + : 'Publishing…'; const { loadingStates, @@ -170,25 +341,119 @@ export default function NewHackathonTab({ } }; - const [announceDialogOpen, setAnnounceDialogOpen] = useState(false); + // After publish, organizers belong on the hackathon's overview page (which + // also resumes any in-flight escrow settle), NOT the review/publish step where + // they could fire a second publish. replace() so Back doesn't return here. + const goToHackathonOverview = useCallback(() => { + if (derivedOrgId && draftId) { + router.replace(`/organizations/${derivedOrgId}/hackathons/${draftId}`); + } + }, [derivedOrgId, draftId, router]); + + // A draft that has left DRAFT (publish requested -> escrow settling) or that we + // just funded this session is already (being) published and must not be + // re-published. + const isAwaitingFunding = draftStatus === 'DRAFT_AWAITING_FUNDING'; + const alreadyPublishRequested = isAwaitingFunding || isFundingComplete; + + // Landing on / refreshing the review step for an already-publishing draft + // bounces to the overview with a clear message. Fires once; suppressed during + // an in-session publish (the cached status is still DRAFT then, and the + // progress modal owns that redirect). + const publishedRedirectRef = useRef(false); + useEffect(() => { + if ( + isAwaitingFunding && + !publishedRedirectRef.current && + !progressOpen && + escrowPhase === 'idle' + ) { + publishedRedirectRef.current = true; + toast.info('This hackathon has already been published.'); + goToHackathonOverview(); + } + }, [isAwaitingFunding, progressOpen, escrowPhase, goToHackathonOverview]); const handlePublish = async () => { - setAnnounceDialogOpen(true); + if (alreadyPublishRequested) { + toast.info('This hackathon has already been published.'); + goToHackathonOverview(); + return; + } + setConfirmOpen(true); }; - const handleConfirmPublish = async (options: { - skipAnnouncement: boolean; - announcementSubject?: string; - }) => { + const runFunding = useCallback(async () => { try { - await publish(options); + await publish(); updateStepCompletion('review', true); - setAnnounceDialogOpen(false); - } catch (error) { - throw error; + } catch { + // Failure is reflected via escrowPhase; the progress modal offers retry. } + }, [publish, updateStepCompletion]); + + const handleConfirmFunding = async () => { + setConfirmOpen(false); + setProgressOpen(true); + await runFunding(); + // Pre-flight bailed before the runner started -> nothing to show here; the + // bail already toasted the reason. + if (escrowPhaseRef.current === 'idle') { + setProgressOpen(false); + } + }; + + const handleRetryFunding = () => { + void runFunding(); + }; + + const handleViewHackathon = () => { + setProgressOpen(false); + goToHackathonOverview(); }; + // Funding step-up (email OTP). The backend decides whether it's required; when + // disabled, requestOtp reports required:false and the modal funds directly. + const requestOtp = useCallback(async () => { + if (!derivedOrgId || !draftId) { + return { required: false, alreadyVerified: false, sent: false }; + } + const res = await requestHackathonFundingOtp(derivedOrgId, draftId); + return { + required: res.required, + alreadyVerified: res.alreadyVerified, + sent: res.sent, + }; + }, [derivedOrgId, draftId]); + + const verifyOtp = useCallback( + async (otpCode: string) => { + if (!derivedOrgId || !draftId) return; + try { + await verifyHackathonFundingOtp(derivedOrgId, draftId, otpCode); + } catch (err) { + throw new Error( + fundingOtpErrorMessage(err, 'That code is not right. Try again.') + ); + } + }, + [derivedOrgId, draftId] + ); + + const handleConnectExternal = useCallback(async () => { + setConnecting(true); + try { + const { address } = await connectWallet(); + setExternalAddress(address); + } catch (err) { + toast.error( + err instanceof Error ? err.message : 'Could not connect a wallet.' + ); + } finally { + setConnecting(false); + } + }, []); + if (isLoadingDraft) { return (
@@ -300,6 +565,7 @@ export default function NewHackathonTab({ onPublish={handlePublish} onSaveDraft={saveDraft} isLoading={isPublishing} + publishStatusLabel={publishStatusLabel} isSavingDraft={isSavingDraft} organizationId={derivedOrgId} draftId={draftId} @@ -309,15 +575,44 @@ export default function NewHackathonTab({ {draftId && derivedOrgId && ( - + <> + + { + setProgressOpen(false); + // Closing the success modal lands organizers on the overview (not + // back on the review step). On failure, stay to retry / save draft. + if (isFundingComplete) goToHackathonOverview(); + }} + onRetry={handleRetryFunding} + onSwitchToDraft={() => setProgressOpen(false)} + onViewHackathon={handleViewHackathon} + /> + )}
); diff --git a/components/organization/hackathons/new/PrePublishAnnounceDialog.tsx b/components/organization/hackathons/new/PrePublishAnnounceDialog.tsx index c453c0b81..cdbb15339 100644 --- a/components/organization/hackathons/new/PrePublishAnnounceDialog.tsx +++ b/components/organization/hackathons/new/PrePublishAnnounceDialog.tsx @@ -14,7 +14,7 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; -import { previewAnnouncementAudience } from '@/lib/api/hackathons/draft'; +import { previewAnnouncementAudience } from '@/features/hackathons'; import { reportError } from '@/lib/error-reporting'; interface PrePublishAnnounceDialogProps { diff --git a/components/organization/hackathons/new/tabs/ReviewTab.tsx b/components/organization/hackathons/new/tabs/ReviewTab.tsx index bb1bfef08..c2f90d951 100644 --- a/components/organization/hackathons/new/tabs/ReviewTab.tsx +++ b/components/organization/hackathons/new/tabs/ReviewTab.tsx @@ -35,6 +35,8 @@ interface ReviewTabProps { onPublish?: () => Promise; onSaveDraft?: () => Promise; isLoading?: boolean; + /** Phase-aware label shown on the publish button while loading. */ + publishStatusLabel?: string; isSavingDraft?: boolean; organizationId?: string; draftId?: string | null; @@ -46,6 +48,7 @@ export default function ReviewTab({ onPublish, onSaveDraft, isLoading = false, + publishStatusLabel, isSavingDraft = false, organizationId, draftId, @@ -131,6 +134,7 @@ export default function ReviewTab({ void; onSaveDraft?: () => void; @@ -18,6 +20,7 @@ interface PublishSectionProps { export const PublishSection: React.FC = ({ walletAddress, isLoading, + statusLabel, isSavingDraft, onPublish, onSaveDraft, @@ -77,7 +80,7 @@ export const PublishSection: React.FC = ({ disabled={isLoading || isSavingDraft || !walletAddress} className='flex-1 sm:flex-none' > - {isLoading ? 'Publishing...' : 'Publish Hackathon'} + {isLoading ? (statusLabel ?? 'Publishing...') : 'Publish Hackathon'}
diff --git a/components/organization/hackathons/rewards/CreateMilestonesDialog.tsx b/components/organization/hackathons/rewards/CreateMilestonesDialog.tsx deleted file mode 100644 index f6895676c..000000000 --- a/components/organization/hackathons/rewards/CreateMilestonesDialog.tsx +++ /dev/null @@ -1,122 +0,0 @@ -'use client'; - -import React from 'react'; -import { Loader2, Trophy, AlertCircle, Info } from 'lucide-react'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; -import { BoundlessButton } from '@/components/buttons'; -import { WinnerFormItem } from './WinnerFormItem'; -import type { Submission } from './types'; -import type { PrizeTier } from '@/components/organization/hackathons/new/tabs/schemas/rewardsSchema'; -import type { HackathonEscrowData } from '@/lib/api/hackathons'; - -interface CreateMilestonesDialogProps { - open: boolean; - onOpenChange: (open: boolean) => void; - winners: Submission[]; - prizeTiers: PrizeTier[]; - escrow: HackathonEscrowData | null; - walletAddresses: Record; - errors: Record; - isLoading: boolean; - onWalletAddressChange: (submissionId: string, address: string) => void; - onCreateMilestones: () => Promise; -} - -export const CreateMilestonesDialog: React.FC = ({ - open, - onOpenChange, - winners, - prizeTiers, - escrow, - walletAddresses, - errors, - isLoading, - onWalletAddressChange, - onCreateMilestones, -}) => { - return ( - - - - - Create Winner Milestones - - - Enter wallet addresses for each winner to create milestones in the - escrow - - - -
- {!escrow?.isFunded && ( - - - Cannot Create Milestones - - Escrow is not funded. Please fund the escrow first. - - - )} - - {winners.map(winner => ( - - ))} - - - - Important - - After creating milestones, you'll need to approve each winner - milestone and then release funds to distribute prizes. - - -
- -
- onOpenChange(false)} - disabled={isLoading} - > - Cancel - - 0 - } - > - {isLoading ? ( - <> - - Creating... - - ) : ( - <> - - Create Milestones - - )} - -
-
-
- ); -}; diff --git a/components/organization/hackathons/rewards/EscrowStatusCard.tsx b/components/organization/hackathons/rewards/EscrowStatusCard.tsx deleted file mode 100644 index e9bc7007a..000000000 --- a/components/organization/hackathons/rewards/EscrowStatusCard.tsx +++ /dev/null @@ -1,28 +0,0 @@ -'use client'; - -import React from 'react'; -import { Card, CardContent } from '@/components/ui/card'; -import { HackathonEscrowData } from '@/types/hackathon'; - -interface EscrowStatusCardProps { - escrow: HackathonEscrowData | null; - isLoading?: boolean; -} - -export default function EscrowStatusCard({ - escrow, - isLoading, -}: EscrowStatusCardProps) { - const formatAmount = (amount: number) => amount.toFixed(2); - - return ( - - -

Balance

-

- {isLoading || !escrow ? '—' : `$${formatAmount(escrow.balance)} USDC`} -

-
-
- ); -} diff --git a/components/organization/hackathons/rewards/PublishWinnersWizard.tsx b/components/organization/hackathons/rewards/PublishWinnersWizard.tsx index cd68ac0d7..e34755987 100644 --- a/components/organization/hackathons/rewards/PublishWinnersWizard.tsx +++ b/components/organization/hackathons/rewards/PublishWinnersWizard.tsx @@ -10,7 +10,6 @@ import { DialogClose, } from '@/components/ui/dialog'; import { Submission } from './types'; -import { HackathonEscrowData } from '@/lib/api/hackathons'; import { PrizeTier } from '@/components/organization/hackathons/new/tabs/schemas/rewardsSchema'; import { useWizardSteps } from '@/hooks/use-wizard-steps'; import { usePublishWinners } from '@/hooks/use-publish-winners'; @@ -18,13 +17,13 @@ import { AnnouncementStep } from './AnnouncementStep'; import { PreviewStep } from './PreviewStep'; import { WizardStepIndicator } from './WizardStepIndicator'; import { WizardFooter } from './WizardFooter'; +import RewardPayoutProgressModal from './RewardPayoutProgressModal'; interface PublishWinnersWizardProps { open: boolean; onOpenChange: (open: boolean) => void; submissions: Submission[]; prizeTiers: PrizeTier[]; - escrow: HackathonEscrowData | null; organizationId: string; hackathonId: string; onSuccess?: () => void; @@ -35,7 +34,6 @@ export default function PublishWinnersWizard({ onOpenChange, submissions, prizeTiers, - escrow, organizationId, hackathonId, onSuccess, @@ -64,6 +62,8 @@ export default function PublishWinnersWizard({ ); const [announcement, setAnnouncement] = useState(''); + // Drives the on-chain payout progress modal once the organizer commits. + const [isPayoutModalOpen, setIsPayoutModalOpen] = useState(false); const { currentStep, @@ -72,28 +72,56 @@ export default function PublishWinnersWizard({ currentStepIndex, handleNext, handleBack, - } = useWizardSteps({ open, escrow }); + } = useWizardSteps({ open }); - const { isPublishing, publishWinners } = usePublishWinners({ + const { + isPublishing, + publishWinners, + phase, + txHash, + isCompleted, + isFailed, + error, + reset, + } = usePublishWinners({ winners, prizeTiers, - escrow, organizationId, hackathonId, announcement, - onSuccess: () => { - onOpenChange(false); - if (onSuccess) { - onSuccess(); - } - }, + // Fire the page's refetch on completion. The wizard + modal stay open + // so the organizer sees the success state, then close on dismiss. + onSuccess, }); const handlePublish = async () => { + setIsPayoutModalOpen(true); + try { + await publishWinners(); + } catch { + // Pre-flight validation (missing wallet, no eligible winners, etc.) + // throws before the on-chain runner starts, so the runner phase stays + // `idle`. A toast already explained the problem — close the modal so it + // doesn't hang on a step list that will never advance. + setIsPayoutModalOpen(false); + reset(); + } + }; + + const handlePayoutClose = () => { + setIsPayoutModalOpen(false); + reset(); + // A settled payout (success or aborted failure) closes the wizard too. + onOpenChange(false); + }; + + const handlePayoutRetry = async () => { + reset(); try { await publishWinners(); } catch { - // Error is handled in the hook + setIsPayoutModalOpen(false); + reset(); } }; @@ -131,59 +159,73 @@ export default function PublishWinnersWizard({ }; return ( - - - - - - Reward Winners - - - - - - - - -
- {currentStep === 'announcement' && ( - - )} - - {currentStep === 'preview' && ( - setCurrentStep('announcement')} - getPrizeForRank={getPrizeForRank} - /> - )} -
- - onOpenChange(false)} - onBack={handleBack} - onNext={handleNext} - onPublish={handlePublish} - /> -
-
+ <> + + + + + + Reward Winners + + + + + + + + +
+ {currentStep === 'announcement' && ( + + )} + + {currentStep === 'preview' && ( + setCurrentStep('announcement')} + getPrizeForRank={getPrizeForRank} + /> + )} +
+ + onOpenChange(false)} + onBack={handleBack} + onNext={handleNext} + onPublish={handlePublish} + /> +
+
+ + + ); } diff --git a/components/organization/hackathons/rewards/RewardDistributionStatusBanner.tsx b/components/organization/hackathons/rewards/RewardDistributionStatusBanner.tsx deleted file mode 100644 index 3ac8f894b..000000000 --- a/components/organization/hackathons/rewards/RewardDistributionStatusBanner.tsx +++ /dev/null @@ -1,254 +0,0 @@ -'use client'; - -import React from 'react'; -import { - CheckCircle2, - XCircle, - Clock, - Loader2, - AlertTriangle, - RefreshCw, - Info, - Ban, -} from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { format } from 'date-fns'; -import { formatInTimeZone } from 'date-fns-tz'; -import type { - RewardDistributionStatusResponse, - RewardDistributionStatusEnum, -} from '@/lib/api/hackathons'; - -interface RewardDistributionStatusBannerProps { - distributionStatus: RewardDistributionStatusResponse; - isLoading?: boolean; - onRefresh?: () => void; -} - -/** - * Stellar stroop precision: 7 decimals - */ -const STROOP_FACTOR = 1e7; - -const STATUS_CONFIG: Record< - RewardDistributionStatusEnum, - { - icon: React.ReactNode; - label: string; - bgClass: string; - borderClass: string; - textClass: string; - iconClass: string; - } -> = { - NOT_TRIGGERED: { - icon: , - label: 'Not Triggered', - bgClass: 'bg-gray-900/60', - borderClass: 'border-gray-800', - textClass: 'text-gray-300', - iconClass: 'text-gray-400', - }, - PENDING_ADMIN_REVIEW: { - icon: , - label: 'Pending Admin Review', - bgClass: 'bg-amber-950/40', - borderClass: 'border-amber-800/60', - textClass: 'text-amber-300', - iconClass: 'text-amber-400', - }, - APPROVED: { - icon: , - label: 'Approved', - bgClass: 'bg-green-950/40', - borderClass: 'border-green-800/60', - textClass: 'text-green-300', - iconClass: 'text-green-400', - }, - REJECTED: { - icon: , - label: 'Rejected', - bgClass: 'bg-red-950/40', - borderClass: 'border-red-800/60', - textClass: 'text-red-300', - iconClass: 'text-red-400', - }, - EXECUTING: { - icon: , - label: 'Executing', - bgClass: 'bg-blue-950/40', - borderClass: 'border-blue-800/60', - textClass: 'text-blue-300', - iconClass: 'text-blue-400', - }, - COMPLETED: { - icon: , - label: 'Completed', - bgClass: 'bg-green-950/40', - borderClass: 'border-green-800/60', - textClass: 'text-green-300', - iconClass: 'text-green-400', - }, - FAILED: { - icon: , - label: 'Failed', - bgClass: 'bg-red-950/50', - borderClass: 'border-red-700/60', - textClass: 'text-red-300', - iconClass: 'text-red-400', - }, - PARTIAL_SUCCESS: { - icon: , - label: 'Partial Success', - bgClass: 'bg-orange-950/40', - borderClass: 'border-orange-800/60', - textClass: 'text-orange-300', - iconClass: 'text-orange-400', - }, -}; - -const formatDate = (val: string | null | undefined): string | null => { - if (!val) return null; - try { - return formatInTimeZone( - new Date(val), - 'UTC', - "MMM d, yyyy 'at' HH:mm 'UTC'" - ); - } catch { - return val; - } -}; - -export const RewardDistributionStatusBanner: React.FC< - RewardDistributionStatusBannerProps -> = ({ distributionStatus, isLoading, onRefresh }) => { - const { status } = distributionStatus; - const cfg = STATUS_CONFIG[status]; - - if (!cfg) return null; - - const triggeredAt = formatDate(distributionStatus.triggeredAt); - const adminDecisionAt = formatDate(distributionStatus.adminDecisionAt); - const updatedAt = formatDate(distributionStatus.updatedAt); - - return ( -
-
-
-

- Distribution Status -

-

- Current reward distribution state for this hackathon -

-
- {onRefresh && ( - - )} -
- -
- {/* Status Header */} -
- {cfg.icon} -
-

- {cfg.label} -

- {triggeredAt && ( -

- Triggered: {triggeredAt} -

- )} -
-
- - {/* Detail Fields */} -
- {distributionStatus.distributionId && ( -
- Distribution ID -

- {distributionStatus.distributionId} -

-
- )} - - {adminDecisionAt && ( -
- Admin Decision -

{adminDecisionAt}

-
- )} - - {updatedAt && ( -
- Last Updated -

{updatedAt}

-
- )} - - {distributionStatus.snapshot?.totalPrizePool != null && - distributionStatus.snapshot.totalPrizePool > 0 && ( -
- - Total Prize Pool - -

- {( - distributionStatus.snapshot.totalPrizePool / STROOP_FACTOR - ).toLocaleString('en-US', { maximumFractionDigits: 2 })}{' '} - {distributionStatus.snapshot.currency} -

-
- )} - - {distributionStatus.snapshot?.winners?.length > 0 && ( -
- Winners -

- {distributionStatus.snapshot.winners.length} recipient(s) -

-
- )} -
- - {/* Rejection reason */} - {distributionStatus.rejectionReason && ( -
-

- Rejection Reason -

-

- {distributionStatus.rejectionReason} -

-
- )} - - {/* Admin note */} - {distributionStatus.adminNote && ( -
-

Admin Note

-

- {distributionStatus.adminNote} -

-
- )} -
-
- ); -}; diff --git a/components/organization/hackathons/rewards/RewardPayoutProgressModal.tsx b/components/organization/hackathons/rewards/RewardPayoutProgressModal.tsx new file mode 100644 index 000000000..50e0f9e31 --- /dev/null +++ b/components/organization/hackathons/rewards/RewardPayoutProgressModal.tsx @@ -0,0 +1,240 @@ +'use client'; + +import React from 'react'; +import { + Loader2, + Check, + AlertTriangle, + ExternalLink, + PartyPopper, +} from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from '@/components/ui/dialog'; +import { BoundlessButton } from '@/components/buttons'; +import { getTransactionExplorerUrl } from '@/lib/wallet-utils'; +import type { EscrowRunPhase } from '@/features/hackathons'; +import type { FundingMode } from '@/features/hackathons'; + +interface RewardPayoutProgressModalProps { + open: boolean; + phase: EscrowRunPhase; + txHash: string | null; + error: string | null; + isCompleted: boolean; + isFailed: boolean; + /** + * Signing path. MANAGED (custodial) is the common case for hackathon + * payouts; EXTERNAL is kept for organizers funding from a connected + * wallet, which adds sign + submit steps. + */ + fundingMode: FundingMode; + onClose: () => void; + onRetry?: () => void; +} + +interface Step { + phase: EscrowRunPhase; + label: string; +} + +const MANAGED_STEPS: Step[] = [ + { phase: 'starting', label: 'Preparing payout' }, + { phase: 'polling', label: 'Paying winners on-chain' }, +]; + +const EXTERNAL_STEPS: Step[] = [ + { phase: 'starting', label: 'Preparing payout' }, + { phase: 'signing', label: 'Awaiting your signature' }, + { phase: 'submitting', label: 'Submitting transaction' }, + { phase: 'polling', label: 'Paying winners on-chain' }, +]; + +/** + * Step-by-step reward payout progress, driven by the EscrowOpRunner phase. + * Mirrors the funding modal so the organizer can see exactly where the + * on-chain `select_winners` payout is (preparing -> paying -> done) and + * recover cleanly on failure. + */ +export default function RewardPayoutProgressModal({ + open, + phase, + txHash, + error, + isCompleted, + isFailed, + fundingMode, + onClose, + onRetry, +}: RewardPayoutProgressModalProps) { + const steps = fundingMode === 'EXTERNAL' ? EXTERNAL_STEPS : MANAGED_STEPS; + const dismissable = isCompleted || isFailed; + + const phaseIndex = steps.findIndex(s => s.phase === phase); + const activeIndex = isCompleted + ? steps.length + : phaseIndex >= 0 + ? phaseIndex + : 0; + + return ( + { + // Only dismissable once the payout has settled; while in-flight the + // modal stays put so the organizer can't lose track of an on-chain op. + if (!next && dismissable) onClose(); + }} + > + { + if (!dismissable) e.preventDefault(); + }} + onEscapeKeyDown={e => { + if (!dismissable) e.preventDefault(); + }} + > + + + {isCompleted + ? 'Winners rewarded' + : isFailed + ? 'Payout failed' + : 'Rewarding winners'} + + + {isCompleted + ? 'Prizes have been paid out to the winners on-chain.' + : isFailed + ? 'No funds moved. You can retry the payout.' + : 'Keep this open while winners are paid on-chain.'} + + + + {isCompleted ? ( +
+
+ +
+ {txHash && } +
+ ) : isFailed ? ( +
+ +

+ {error || 'The payout transaction could not be completed.'} +

+
+ ) : ( +
    + {steps.map((step, i) => { + const state = + i < activeIndex + ? 'done' + : i === activeIndex + ? 'active' + : 'pending'; + return ( +
  1. + + + {step.label} + +
  2. + ); + })} + {txHash && ( +
  3. + +
  4. + )} +
+ )} + + + {isCompleted && ( + + Close + + )} + {isFailed && ( + <> + + Close + + {onRetry && ( + Retry + )} + + )} + +
+
+ ); +} + +function StepIcon({ state }: { state: 'done' | 'active' | 'pending' }) { + if (state === 'done') { + return ( + + + + ); + } + if (state === 'active') { + return ( + + + + ); + } + return ( + + + + ); +} + +function ExplorerLink({ txHash }: { txHash: string }) { + let href = ''; + try { + href = getTransactionExplorerUrl(txHash); + } catch { + href = ''; + } + if (!href) return null; + return ( + + View transaction + + + ); +} diff --git a/components/organization/hackathons/rewards/RewardsPageContent.tsx b/components/organization/hackathons/rewards/RewardsPageContent.tsx index 8ceef9a63..89fc50fd9 100644 --- a/components/organization/hackathons/rewards/RewardsPageContent.tsx +++ b/components/organization/hackathons/rewards/RewardsPageContent.tsx @@ -1,48 +1,35 @@ 'use client'; -import React, { useState } from 'react'; -import { - Megaphone, - CheckCircle2, - XCircle, - Clock, - Loader2, - AlertTriangle, - Info, - Ban, - ChevronRight, -} from 'lucide-react'; +import React from 'react'; +import { Megaphone, CheckCircle2, Trophy, Loader2 } from 'lucide-react'; import { BoundlessButton } from '@/components/buttons'; import PodiumSection from '@/components/organization/hackathons/rewards/PodiumSection'; import { TrackWinnersSection } from '@/components/organization/hackathons/rewards/TrackWinnersSection'; import SubmissionsList from '@/components/organization/hackathons/rewards/SubmissionsList'; -import EscrowStatusCard from '@/components/organization/hackathons/rewards/EscrowStatusCard'; -import { RewardDistributionStatusBanner } from '@/components/organization/hackathons/rewards/RewardDistributionStatusBanner'; -import BoundlessSheet from '@/components/sheet/boundless-sheet'; import { Submission } from '@/components/organization/hackathons/rewards/types'; -import type { - HackathonEscrowData, - HackathonTrackWinner, - RewardDistributionStatusResponse, - RewardDistributionStatusEnum, -} from '@/lib/api/hackathons'; +import type { HackathonTrackWinner } from '@/lib/api/hackathons'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { AlertCircle } from 'lucide-react'; interface RewardsPageContentProps { submissions: Submission[]; - escrow: HackathonEscrowData | null; - isLoadingEscrow: boolean; isLoadingSubmissions: boolean; maxRank: number; hasWinners: boolean; + /** Opens the Step 2 payout wizard. */ onPublishClick: () => void; onRankChange: (submissionId: string, newRank: number | null) => Promise; - distributionStatus?: RewardDistributionStatusResponse | null; - isLoadingDistributionStatus?: boolean; - onRefreshDistributionStatus?: () => void; + /** Step 1: makes the winners public (publishes judging results). */ + onPublishResults: () => void; + /** True while the Step 1 publish request is in flight. */ + isPublishingResults?: boolean; + /** Whether judging results have been published (gates Step 2). */ resultsPublished?: boolean; - escrowAddress?: string; + /** + * Whether the hackathon is funded on-chain (events contract published). + * Required, alongside `resultsPublished`, before winners can be paid. + */ + canReward?: boolean; /** * Per-track winners stamped by publishResults. Rendered in a * dedicated section below the rank-based podium. Empty pre-publish @@ -53,162 +40,108 @@ interface RewardsPageContentProps { export const RewardsPageContent: React.FC = ({ submissions, - escrow, - isLoadingEscrow, isLoadingSubmissions, maxRank, - hasWinners, onPublishClick, onRankChange, - distributionStatus, - isLoadingDistributionStatus, - onRefreshDistributionStatus, - resultsPublished, - escrowAddress, + onPublishResults, + isPublishingResults = false, + resultsPublished = false, + canReward = false, trackWinners = [], }) => { - const [isStatusSheetOpen, setIsStatusSheetOpen] = useState(false); - - const status = distributionStatus?.status; - const isNotTriggered = !distributionStatus || status === 'NOT_TRIGGERED'; - const isRejected = status === 'REJECTED' || status === 'FAILED'; - const isLocked = - status && - ['PENDING_ADMIN_REVIEW', 'APPROVED', 'EXECUTING'].includes(status); - - const showTriggerButton = (isNotTriggered || isRejected) && !isLocked; - const canTrigger = resultsPublished && !!escrowAddress; - - // Status color/icon mapping for the compact badge - const STATUS_BADGE: Record< - string, - { color: string; icon: React.ReactNode; label: string } - > = { - NOT_TRIGGERED: { - color: 'text-gray-400 border-gray-700 bg-gray-900/60', - icon: , - label: 'Not Triggered', - }, - PENDING_ADMIN_REVIEW: { - color: 'text-amber-400 border-amber-800/60 bg-amber-950/30', - icon: , - label: 'Pending Review', - }, - APPROVED: { - color: 'text-green-400 border-green-800/60 bg-green-950/30', - icon: , - label: 'Approved', - }, - REJECTED: { - color: 'text-red-400 border-red-800/60 bg-red-950/30', - icon: , - label: 'Rejected', - }, - EXECUTING: { - color: 'text-blue-400 border-blue-800/60 bg-blue-950/30', - icon: , - label: 'Executing', - }, - COMPLETED: { - color: 'text-green-400 border-green-800/60 bg-green-950/30', - icon: , - label: 'Completed', - }, - FAILED: { - color: 'text-red-400 border-red-800/60 bg-red-950/30', - icon: , - label: 'Failed', - }, - PARTIAL_SUCCESS: { - color: 'text-orange-400 border-orange-800/60 bg-orange-950/30', - icon: , - label: 'Partial Success', - }, - }; - const badge = status ? STATUS_BADGE[status] : null; + // Step 2 is unlocked only once results are public AND the hackathon is + // funded on-chain. Surface the precise blocker so the organizer knows + // which prerequisite is missing. + const canRewardWinners = resultsPublished && canReward; + const rewardDisabledHelper = !resultsPublished + ? 'Publish results first.' + : !canReward + ? 'Hackathon is not funded on-chain yet.' + : null; return (
- {/* 1. Compact Status Badge + Sheet */} - {distributionStatus && status !== 'NOT_TRIGGERED' && badge && ( - <> - + {/* Two-step organizer flow: publish results, then reward winners. */} +
+
+

Finalize Rewards

+

+ Make the winners public, then reward them on-chain. +

+
- -
- +
+ {/* Step 1 — Publish Results */} +
+
+ + 1 + +

+ Publish Results +

- - - )} - - {/* 2. Trigger Control Section / Requirements Alert */} - {showTriggerButton && ( -
- {!canTrigger && ( - - - Distribution Requirements - - To trigger reward distribution, you must: -
    - {!resultsPublished && ( -
  • Publish the judging results in the Judging tab.
  • + {resultsPublished ? ( +
    + + Results published +
    + ) : ( + <> +

    + Make the winners public, then reward them on-chain. +

    + + {isPublishingResults ? ( + + ) : ( + )} - {!escrowAddress && ( -
  • - Configure a valid Stellar Escrow address in Settings. -
  • - )} -
-
-
- )} - -
- - - {isRejected - ? 'Re-trigger Reward Distribution' - : 'Trigger Reward Distribution'} - + {isPublishingResults ? 'Publishing...' : 'Publish Results'} + + + )}
-
- )} -
-
-

Escrow Status

-

- View escrow balance, milestones, and funding status -

+ {/* Step 2 — Reward Winners */} +
+
+ + 2 + +

+ Reward Winners +

+
+

+ Pay the winners their prizes on-chain. +

+
+ + + Reward Winners + + {!canRewardWinners && rewardDisabledHelper && ( +

+ {rewardDisabledHelper} +

+ )} +
+
-
{submissions.length > 0 && ( diff --git a/components/organization/hackathons/rewards/WinnerFormItem.tsx b/components/organization/hackathons/rewards/WinnerFormItem.tsx deleted file mode 100644 index 87464b00a..000000000 --- a/components/organization/hackathons/rewards/WinnerFormItem.tsx +++ /dev/null @@ -1,75 +0,0 @@ -'use client'; - -import React from 'react'; -import { Input } from '@/components/ui/input'; -import { Label } from '@/components/ui/label'; -import type { Submission } from './types'; -import type { PrizeTier } from '@/components/organization/hackathons/new/tabs/schemas/rewardsSchema'; -import { extractRankFromPosition } from '@/lib/utils/prize-tier-matcher'; - -interface WinnerFormItemProps { - winner: Submission; - prizeTiers: PrizeTier[]; - walletAddress: string; - error?: string; - isLoading: boolean; - isEscrowFunded: boolean; - onWalletAddressChange: (submissionId: string, address: string) => void; -} - -export const WinnerFormItem: React.FC = ({ - winner, - prizeTiers, - walletAddress, - error, - isLoading, - isEscrowFunded, - onWalletAddressChange, -}) => { - const prizeTier = prizeTiers.find(tier => { - const tierRank = extractRankFromPosition(tier.place); - return tierRank === winner.rank; - }); - const prizeAmount = prizeTier ? parseFloat(prizeTier.prizeAmount || '0') : 0; - - const getRankSuffix = (rank: number) => { - if (rank === 1) return 'st'; - if (rank === 2) return 'nd'; - if (rank === 3) return 'rd'; - return 'th'; - }; - - return ( -
-
-
- -

- Prize: ${prizeAmount.toFixed(2)} USDC -

-
-
-
- - onWalletAddressChange(winner.id, e.target.value)} - disabled={isLoading || !isEscrowFunded} - className='font-mono text-white' - /> - {error &&

{error}

} -

- Stellar address starting with G (56 characters) -

-
-
- ); -}; diff --git a/components/organization/hackathons/settings/AdvancedSettingsTab.tsx b/components/organization/hackathons/settings/AdvancedSettingsTab.tsx index fc60f1380..463f81c0e 100644 --- a/components/organization/hackathons/settings/AdvancedSettingsTab.tsx +++ b/components/organization/hackathons/settings/AdvancedSettingsTab.tsx @@ -29,8 +29,9 @@ import { AlertDialogTrigger, } from '@/components/ui/alert-dialog'; import { Button } from '@/components/ui/button'; -import { Trash2, Sparkles } from 'lucide-react'; +import { Trash2, Sparkles, Ban } from 'lucide-react'; import { deleteHackathon } from '@/lib/api/hackathons'; +import { useCancelHackathon } from '@/hooks/hackathon/use-cancel-hackathon'; import { toast } from 'sonner'; import { api } from '@/lib/api/api'; @@ -65,6 +66,17 @@ export default function AdvancedSettingsTab({ const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [isSaving, setIsSaving] = useState(false); + const [showCancelDialog, setShowCancelDialog] = useState(false); + const { cancel, isCancelling } = useCancelHackathon( + organizationId, + hackathonId, + { + onSuccess: () => { + setShowCancelDialog(false); + void onSaveSuccess?.(); + }, + } + ); const form = useForm({ resolver: zodResolver(advancedSettingsSchema), @@ -437,6 +449,48 @@ export default function AdvancedSettingsTab({

+ + + + + + + + Cancel Hackathon + + + This cancels the hackathon on-chain and refunds all contributors + and the remaining escrow balance to the owner. Refunds are + processed on-chain and may take a few moments to settle. This + cannot be undone. + + + + + Keep Hackathon + + { + // Keep the dialog open while the op runs; close on success + // via the hook's onSuccess. + e.preventDefault(); + void cancel(); + }} + disabled={isCancelling} + className='bg-amber-600 text-white hover:bg-amber-700 disabled:cursor-not-allowed disabled:opacity-50' + > + {isCancelling ? 'Cancelling…' : 'Cancel Hackathon'} + + + + + +
+ ))} +
+ + + {update.isPending ? 'Saving…' : 'Save policy'} + +
+ ); +} diff --git a/components/organization/treasury/SpendInbox.tsx b/components/organization/treasury/SpendInbox.tsx new file mode 100644 index 000000000..1b76542c0 --- /dev/null +++ b/components/organization/treasury/SpendInbox.tsx @@ -0,0 +1,313 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { Loader2, Plus, Send } from 'lucide-react'; +import { toast } from 'sonner'; +import { BoundlessButton } from '@/components/buttons'; +import { Input } from '@/components/ui/input'; +import { formatAddress } from '@/lib/wallet-utils'; +import { signXdrWithKit } from '@/lib/wallet/wallet-kit'; +import { + useBuildSpendXdr, + useInitiateSpend, + useSpendDecision, + useSpendRequests, + useSubmitSignedXdr, + useTreasuryWallets, + type SpendRequest, + type SpendStatus, + type TreasuryWallet, +} from '@/features/treasury'; + +const STATUS_TONE: Record = { + PENDING: 'border-amber-900/50 bg-amber-950/30 text-amber-300', + APPROVED: 'border-blue-900/50 bg-blue-950/30 text-blue-300', + AWAITING_SIGNATURES: 'border-blue-900/50 bg-blue-950/30 text-blue-300', + SUBMITTED: 'border-blue-900/50 bg-blue-950/30 text-blue-300', + COMPLETED: 'border-green-900/50 bg-green-950/30 text-green-300', + REJECTED: 'border-red-900/50 bg-red-950/30 text-red-300', + FAILED: 'border-red-900/50 bg-red-950/30 text-red-300', + CANCELLED: 'border-gray-800 bg-gray-900 text-gray-400', +}; + +export default function SpendInbox({ + organizationId, +}: { + organizationId: string; +}) { + const { data: wallets } = useTreasuryWallets(organizationId); + const { data: spends, isLoading } = useSpendRequests(organizationId); + const initiate = useInitiateSpend(organizationId); + + const activeWallets = useMemo( + () => (wallets ?? []).filter(w => w.status === 'ACTIVE'), + [wallets] + ); + + const [showForm, setShowForm] = useState(false); + const [sourceWalletId, setSourceWalletId] = useState(''); + const [destination, setDestination] = useState(''); + const [amount, setAmount] = useState(''); + const [purpose, setPurpose] = useState(''); + + const submitNew = async () => { + if (!sourceWalletId || !destination || !amount || !purpose) { + toast.error('Fill in source, destination, amount, and purpose'); + return; + } + try { + await initiate.mutateAsync({ + sourceWalletId, + destination: destination.trim(), + amount: amount.trim(), + purpose: purpose.trim(), + }); + toast.success('Spend request created'); + setShowForm(false); + setDestination(''); + setAmount(''); + setPurpose(''); + } catch (err) { + toast.error( + err instanceof Error ? err.message : 'Could not create spend' + ); + } + }; + + return ( +
+
+

+ Move funds out of a treasury wallet with tiered approvals. +

+ setShowForm(v => !v)} + className='border-gray-700' + > + + + New spend + + +
+ + {showForm && ( +
+ + setDestination(e.target.value)} + placeholder='Destination G-address' + className='border-gray-700 bg-black text-white' + /> +
+ setAmount(e.target.value)} + placeholder='Amount (USDC)' + inputMode='decimal' + className='border-gray-700 bg-black text-white' + /> + setPurpose(e.target.value)} + placeholder='Purpose' + className='border-gray-700 bg-black text-white' + /> +
+ + {initiate.isPending ? 'Creating…' : 'Create request'} + +
+ )} + + {isLoading ? ( +
+ + Loading spend requests… +
+ ) : !spends || spends.length === 0 ? ( +

No spend requests yet.

+ ) : ( +
+ {spends.map(s => ( + w.id === s.sourceWalletId)} + /> + ))} +
+ )} +
+ ); +} + +function SpendRow({ + organizationId, + spend, + wallet, +}: { + organizationId: string; + spend: SpendRequest; + wallet?: TreasuryWallet; +}) { + const decision = useSpendDecision(organizationId); + const buildXdr = useBuildSpendXdr(organizationId); + const submitSigned = useSubmitSignedXdr(organizationId); + const [busy, setBusy] = useState(false); + + const approveCount = spend.approvals.filter( + a => a.action === 'approve' + ).length; + + const act = async (action: 'approve' | 'reject' | 'cancel' | 'execute') => { + try { + await decision.mutateAsync({ requestId: spend.id, action }); + toast.success(`Request ${action}d`); + } catch (err) { + toast.error(err instanceof Error ? err.message : `Could not ${action}`); + } + }; + + // Connected (Tier 2/3) execution: build XDR, sign in-browser, submit. + const executeConnected = async () => { + setBusy(true); + try { + const { unsignedXdr } = await buildXdr.mutateAsync(spend.id); + const signed = await signXdrWithKit(unsignedXdr, wallet?.publicKey); + await submitSigned.mutateAsync({ + requestId: spend.id, + signedXdr: signed, + }); + toast.success('Spend submitted on-chain'); + } catch (err) { + toast.error(err instanceof Error ? err.message : 'Could not submit'); + } finally { + setBusy(false); + } + }; + + const isConnected = wallet?.kind === 'CONNECTED'; + + return ( +
+
+
+

+ {spend.amount} {spend.currency} →{' '} + {formatAddress(spend.destination, 4)} +

+

+ {spend.purpose} · from {wallet?.label ?? 'wallet'} · {approveCount}/ + {spend.requiredApprovals} approvals +

+
+ + {spend.status.toLowerCase().replace('_', ' ')} + +
+ +
+ {spend.status === 'PENDING' && ( + <> + act('approve')} + disabled={decision.isPending} + /> + act('reject')} + disabled={decision.isPending} + /> + + )} + {spend.status === 'APPROVED' && + (isConnected ? ( + } + onClick={executeConnected} + disabled={busy} + /> + ) : ( + } + onClick={() => act('execute')} + disabled={decision.isPending} + /> + ))} + {spend.status === 'AWAITING_SIGNATURES' && isConnected && ( + } + onClick={executeConnected} + disabled={busy} + /> + )} + {(spend.status === 'PENDING' || + spend.status === 'APPROVED' || + spend.status === 'AWAITING_SIGNATURES') && ( + act('cancel')} + disabled={decision.isPending} + /> + )} + {spend.onChainTxHash && ( + + {formatAddress(spend.onChainTxHash, 6)} + + )} +
+
+ ); +} + +function ActionButton({ + label, + onClick, + disabled, + variant, + icon, +}: { + label: string; + onClick: () => void; + disabled?: boolean; + variant?: 'outline'; + icon?: React.ReactNode; +}) { + return ( + + + {icon} + {label} + + + ); +} diff --git a/components/organization/treasury/WalletsSection.tsx b/components/organization/treasury/WalletsSection.tsx new file mode 100644 index 000000000..3a64fb878 --- /dev/null +++ b/components/organization/treasury/WalletsSection.tsx @@ -0,0 +1,286 @@ +'use client'; + +import { useState } from 'react'; +import { + Copy, + Landmark, + Link2, + Loader2, + Plus, + ShieldCheck, + Star, + Wallet, +} from 'lucide-react'; +import { toast } from 'sonner'; +import { BoundlessButton } from '@/components/buttons'; +import { Input } from '@/components/ui/input'; +import { formatAddress } from '@/lib/wallet-utils'; +import { copyToClipboard } from '@/lib/utils'; +import { connectWallet } from '@/lib/wallet/wallet-kit'; +import { + useArchiveWallet, + useCreateManagedWallet, + useRegisterConnectedWallet, + useTreasuryWallets, + useUpdateWallet, + type TreasuryWallet, +} from '@/features/treasury'; + +export default function WalletsSection({ + organizationId, +}: { + organizationId: string; +}) { + const { + data: wallets, + isLoading, + error, + } = useTreasuryWallets(organizationId); + const createManaged = useCreateManagedWallet(organizationId); + const registerConnected = useRegisterConnectedWallet(organizationId); + + const [label, setLabel] = useState(''); + const [pendingConnect, setPendingConnect] = useState(null); + const [connectLabel, setConnectLabel] = useState(''); + + const handleCreate = async () => { + try { + await createManaged.mutateAsync(label.trim() || 'Main treasury'); + toast.success('Treasury wallet created'); + setLabel(''); + } catch (err) { + toast.error( + err instanceof Error ? err.message : 'Could not create wallet' + ); + } + }; + + const handleConnect = async () => { + try { + const { address } = await connectWallet(); + setPendingConnect(address); + } catch (err) { + toast.error(err instanceof Error ? err.message : 'Could not connect'); + } + }; + + const handleRegister = async () => { + if (!pendingConnect) return; + try { + await registerConnected.mutateAsync({ + publicKey: pendingConnect, + label: connectLabel.trim() || 'Connected wallet', + connectionMethod: 'walletkit_generic', + }); + toast.success('Wallet connected'); + setPendingConnect(null); + setConnectLabel(''); + } catch (err) { + toast.error(err instanceof Error ? err.message : 'Could not connect'); + } + }; + + return ( +
+
+ {/* Managed */} +
+

+ + Managed wallet +

+

+ Boundless-custodial. We sponsor activation, the USDC trustline, and + a fee float so it can transact. +

+
+ setLabel(e.target.value)} + placeholder='Label (e.g. Main treasury)' + maxLength={80} + className='border-gray-700 bg-black text-white' + /> + + + {createManaged.isPending ? ( + + ) : ( + + )} + Create wallet + + +
+
+ + {/* Connected */} +
+

+ + Connect a wallet +

+

+ Use your own external or multisig wallet. Needs a USDC trustline; + you sign in-browser. +

+
+ {pendingConnect ? ( + <> +

+ {formatAddress(pendingConnect, 6)} +

+ setConnectLabel(e.target.value)} + placeholder='Label' + maxLength={80} + className='border-gray-700 bg-black text-white' + /> +
+ + {registerConnected.isPending ? 'Connecting…' : 'Connect'} + + setPendingConnect(null)} + className='border-gray-700' + > + Cancel + +
+ + ) : ( + + + + Connect wallet + + + )} +
+
+
+ +
+

+ Wallets +

+ {isLoading ? ( +
+ + Loading wallets… +
+ ) : error ? ( +

+ Treasury is not available yet. Apply the treasury migration on the + backend. +

+ ) : !wallets || wallets.length === 0 ? ( +

+ No treasury wallets yet. Create or connect one above. +

+ ) : ( +
+ {wallets.map(w => ( + + ))} +
+ )} +
+
+ ); +} + +function WalletRow({ + organizationId, + wallet, +}: { + organizationId: string; + wallet: TreasuryWallet; +}) { + const updateWallet = useUpdateWallet(organizationId); + const archiveWallet = useArchiveWallet(organizationId); + const isManaged = wallet.kind === 'MANAGED'; + + return ( +
+
+ + {isManaged ? ( + + ) : ( + + )} + +
+

+ {wallet.label} + {wallet.isDefault && ( + + Default + + )} + {wallet.isMultisig && ( + + Multisig + + )} +

+

+ + · {wallet.status.toLowerCase()} +

+
+
+
+ {!wallet.isDefault && ( + + )} + +
+
+ ); +} diff --git a/components/providers/auth-provider.tsx b/components/providers/auth-provider.tsx deleted file mode 100644 index 26ba52a26..000000000 --- a/components/providers/auth-provider.tsx +++ /dev/null @@ -1,94 +0,0 @@ -'use client'; - -import { useAuthStore } from '@/lib/stores/auth-store'; -import React, { useEffect, useState } from 'react'; -import { reportError } from '@/lib/error-reporting'; -import AuthLoadingState from '../auth/AuthLoadingState'; - -interface AuthProviderProps { - children: React.ReactNode; -} - -export function AuthProvider({ children }: AuthProviderProps) { - const [isHydrated, setIsHydrated] = useState(false); - const { isAuthenticated, accessToken, refreshUser, clearAuth } = - useAuthStore(); - - useEffect(() => { - if (useAuthStore.persist.hasHydrated()) { - setIsHydrated(true); - return; - } - - const unsubscribe = useAuthStore.persist.onFinishHydration(() => { - setIsHydrated(true); - }); - - const timeout = setTimeout(() => { - setIsHydrated(true); - }, 2000); - - return () => { - unsubscribe(); - clearTimeout(timeout); - }; - }, []); - - useEffect(() => { - if (!isHydrated) return; - - const initializeAuth = async () => { - try { - // Only refresh if we have a token but no user data - if (accessToken && !isAuthenticated) { - try { - await refreshUser(); - } catch (err) { - reportError(err, { context: 'auth-refreshUser' }); - clearAuth(); - } - } - } catch (err) { - reportError(err, { context: 'auth-initializeAuth' }); - clearAuth(); - } - }; - - initializeAuth(); - }, [isHydrated, accessToken, isAuthenticated, refreshUser, clearAuth]); - - if (!isHydrated) { - return ; - } - - return <>{children}; -} - -export function useAuthHydration() { - const [isHydrated, setIsHydrated] = useState(false); - - useEffect(() => { - const unsubscribe = useAuthStore.persist.onFinishHydration(() => { - setIsHydrated(true); - }); - - return unsubscribe; - }, []); - - return isHydrated; -} - -export function AuthLoadingProvider({ - children, -}: { - children: React.ReactNode; -}) { - const isHydrated = useAuthHydration(); - const { isLoading } = useAuthStore(); - - if (!isHydrated || isLoading) { - return ; - } - - return <>{children}; -} diff --git a/features/hackathons/api/draft-client.ts b/features/hackathons/api/draft-client.ts new file mode 100644 index 000000000..2a513fc55 --- /dev/null +++ b/features/hackathons/api/draft-client.ts @@ -0,0 +1,51 @@ +/** + * Non-hook draft client calls on the typed openapi-fetch client. These keep the + * call signatures of the old lib/api/hackathons/draft.ts helpers so existing + * imperative callers only change their import path. + */ +import { apiClient, unwrapData } from '@/lib/api'; + +export interface DeleteDraftResult { + success: true; + message: string; + data: null; +} + +/** Delete a draft hackathon. Signature matches the legacy helper. */ +export const deleteDraft = async ( + draftId: string, + organizationId: string +): Promise => { + // 204 No Content on success; unwrapData throws a typed ApiError on failure. + await unwrapData( + await apiClient.DELETE( + '/api/organizations/{organizationId}/hackathons/draft/{id}', + { params: { path: { organizationId, id: draftId } } } + ) + ); + return { success: true, message: 'Deleted successfully', data: null }; +}; + +export interface AnnouncementAudiencePreview { + audienceSize: number; +} + +/** Preview how many subscribers would receive the launch announcement email. */ +export const previewAnnouncementAudience = async ( + draftIdOrHackathonId: string, + organizationId: string +): Promise => { + const data = await unwrapData( + await apiClient.GET( + '/api/organizations/{organizationId}/hackathons/hackathons/{id}/announcement-preview', + { params: { path: { organizationId, id: draftIdOrHackathonId } } } + ) + ); + // The announcement-preview response is not modelled in the OpenAPI schema yet, + // so `data` is untyped; the endpoint returns { audienceSize } at runtime. + return ( + (data as unknown as AnnouncementAudiencePreview | undefined) ?? { + audienceSize: 0, + } + ); +}; diff --git a/features/hackathons/api/escrow-client.ts b/features/hackathons/api/escrow-client.ts new file mode 100644 index 000000000..dd3829a3f --- /dev/null +++ b/features/hackathons/api/escrow-client.ts @@ -0,0 +1,194 @@ +/** + * Hackathon escrow API client (boundless-events contract), on the typed + * openapi-fetch client. Replaces the hand-typed axios layer at + * lib/api/hackathons/escrow.ts: request/response shapes now come from the + * backend-generated schema, and the response envelope is unwrapped by the + * apiClient middleware. + * + * Every action builds an EscrowOp the webapp drives through its lifecycle: + * PENDING_BUILD -> PENDING_SIGN -> PENDING_SUBMIT -> PENDING_CONFIRM + * -> COMPLETED | FAILED | CANCELLED + * + * MANAGED : backend signs with the caller's platform-held wallet + submits; + * the op returns in PENDING_CONFIRM. The webapp only polls. + * EXTERNAL : backend returns `unsignedXdr`; the webapp signs with a connected + * wallet and POSTs to submit-signed, then polls. + */ +import { apiClient, unwrapData } from '@/lib/api'; + +import type { + AnchorHackathonSubmissionRequest, + CancelHackathonEscrowRequest, + EscrowOpResponse, + PublishHackathonEscrowRequest, + RequestFundingOtpResponse, + SelectHackathonWinnersRequest, + SubmitSignedXdrRequest, + VerifyFundingOtpResponse, + WithdrawHackathonSubmissionRequest, +} from '../types'; + +// ── Organizer escrow operations (org-scoped) ───────────────────────────────── + +/** Publish a hackathon draft to the events contract (CREATE_EVENT). */ +export const publishHackathonEscrow = async ( + organizationId: string, + hackathonId: string, + body: PublishHackathonEscrowRequest +): Promise => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/publish', + { params: { path: { organizationId, id: hackathonId } }, body } + ) + ); + +/** Declare winners and trigger payout (SELECT_WINNERS). */ +export const selectHackathonWinners = async ( + organizationId: string, + hackathonId: string, + body: SelectHackathonWinnersRequest +): Promise => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/select-winners', + { params: { path: { organizationId, id: hackathonId } }, body } + ) + ); + +/** Cancel an active hackathon and refund contributors + owner. */ +export const cancelHackathonEscrow = async ( + organizationId: string, + hackathonId: string, + body: CancelHackathonEscrowRequest +): Promise => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/cancel', + { params: { path: { organizationId, id: hackathonId } }, body } + ) + ); + +/** + * Recover a hackathon stranded in DRAFT_AWAITING_FUNDING back to DRAFT so the + * organizer can fix the cause and republish. + */ +export const resetHackathonEscrowToDraft = async ( + organizationId: string, + hackathonId: string +) => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/reset-to-draft', + { params: { path: { organizationId, id: hackathonId } } } + ) + ); + +/** Submit a wallet-signed XDR for an organizer op (EXTERNAL path). */ +export const submitSignedHackathonEscrow = async ( + organizationId: string, + hackathonId: string, + opRowId: string, + body: SubmitSignedXdrRequest +): Promise => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/ops/{opRowId}/submit-signed', + { params: { path: { organizationId, id: hackathonId, opRowId } }, body } + ) + ); + +/** Poll the current state of an organizer escrow op. */ +export const getHackathonEscrowOp = async ( + organizationId: string, + hackathonId: string, + opRowId: string +): Promise => + unwrapData( + await apiClient.GET( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/ops/{opRowId}', + { params: { path: { organizationId, id: hackathonId, opRowId } } } + ) + ); + +// ── Funding step-up (email OTP) ────────────────────────────────────────────── + +/** Ask the backend to email a funding step-up code. */ +export const requestHackathonFundingOtp = async ( + organizationId: string, + hackathonId: string +): Promise => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/funding-otp/request', + { params: { path: { organizationId, id: hackathonId } } } + ) + ); + +/** Verify the emailed funding code; authorizes funding for a short window. */ +export const verifyHackathonFundingOtp = async ( + organizationId: string, + hackathonId: string, + code: string +): Promise => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/{id}/escrow/funding-otp/verify', + { params: { path: { organizationId, id: hackathonId } }, body: { code } } + ) + ); + +// ── Participant escrow operations (hackathon-scoped) ───────────────────────── + +/** Anchor an existing HackathonSubmission row on chain (SUBMIT). */ +export const anchorHackathonSubmission = async ( + hackathonId: string, + submissionId: string, + body: AnchorHackathonSubmissionRequest +): Promise => + unwrapData( + await apiClient.POST( + '/api/hackathons/{id}/escrow/submissions/{submissionId}/submit', + { params: { path: { id: hackathonId, submissionId } }, body } + ) + ); + +/** Withdraw an anchored submission (WITHDRAW_SUBMISSION). */ +export const withdrawHackathonSubmission = async ( + hackathonId: string, + submissionId: string, + body: WithdrawHackathonSubmissionRequest +): Promise => + unwrapData( + await apiClient.POST( + '/api/hackathons/{id}/escrow/submissions/{submissionId}/withdraw', + { params: { path: { id: hackathonId, submissionId } }, body } + ) + ); + +/** Submit a wallet-signed XDR for a participant op (EXTERNAL path). */ +export const submitSignedParticipantEscrow = async ( + hackathonId: string, + opRowId: string, + body: SubmitSignedXdrRequest +): Promise => + unwrapData( + await apiClient.POST( + '/api/hackathons/{id}/escrow/ops/{opRowId}/submit-signed', + { + params: { path: { id: hackathonId, opRowId } }, + body, + } + ) + ); + +/** Poll the current state of a participant escrow op. */ +export const getParticipantEscrowOp = async ( + hackathonId: string, + opRowId: string +): Promise => + unwrapData( + await apiClient.GET('/api/hackathons/{id}/escrow/ops/{opRowId}', { + params: { path: { id: hackathonId, opRowId } }, + }) + ); diff --git a/features/hackathons/api/keys.ts b/features/hackathons/api/keys.ts new file mode 100644 index 000000000..fd6af8dc7 --- /dev/null +++ b/features/hackathons/api/keys.ts @@ -0,0 +1,14 @@ +/** + * React Query key factory for the hackathons feature. Co-locating the keys + * keeps the hooks and any imperative `queryClient.invalidateQueries` calls in + * sync. + */ +export const hackathonKeys = { + all: ['hackathons'] as const, + drafts: (organizationId: string) => + [...hackathonKeys.all, 'drafts', organizationId] as const, + draft: (organizationId: string, id: string) => + [...hackathonKeys.all, 'draft', organizationId, id] as const, + escrowOp: (scope: string, opRowId: string) => + [...hackathonKeys.all, 'escrow-op', scope, opRowId] as const, +}; diff --git a/features/hackathons/api/use-draft.ts b/features/hackathons/api/use-draft.ts new file mode 100644 index 000000000..f12ced57c --- /dev/null +++ b/features/hackathons/api/use-draft.ts @@ -0,0 +1,117 @@ +'use client'; + +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; + +import { apiClient, unwrapData } from '@/lib/api'; + +import type { HackathonDraft, UpdateHackathonDraftBody } from '../types'; +import { hackathonKeys } from './keys'; + +/** Fetch a single draft. Disabled until both ids are present. */ +export function useDraft( + organizationId: string, + id: string | null | undefined +) { + return useQuery({ + queryKey: + organizationId && id + ? hackathonKeys.draft(organizationId, id) + : [...hackathonKeys.all, 'draft', 'idle'], + enabled: Boolean(organizationId && id), + queryFn: async (): Promise => + unwrapData( + await apiClient.GET( + '/api/organizations/{organizationId}/hackathons/draft/{id}', + { params: { path: { organizationId, id: id as string } } } + ) + ), + }); +} + +/** List an organization's drafts (DRAFT + DRAFT_AWAITING_FUNDING). */ +export function useDraftList(organizationId: string) { + return useQuery({ + queryKey: hackathonKeys.drafts(organizationId), + enabled: Boolean(organizationId), + queryFn: async (): Promise => + unwrapData( + await apiClient.GET( + '/api/organizations/{organizationId}/hackathons/drafts', + { params: { path: { organizationId } } } + ) + ), + }); +} + +/** Create an empty draft. */ +export function useCreateDraft(organizationId: string) { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async (): Promise => + unwrapData( + await apiClient.POST( + '/api/organizations/{organizationId}/hackathons/draft', + { params: { path: { organizationId } } } + ) + ), + onSuccess: draft => { + queryClient.setQueryData( + hackathonKeys.draft(organizationId, draft.id), + draft + ); + queryClient.invalidateQueries({ + queryKey: hackathonKeys.drafts(organizationId), + }); + }, + }); +} + +/** + * Update one or more draft sections in a single flat PATCH. Send one section + * for a per-step "Continue", or several for "Save draft". The draft id is passed + * per-call (so a create-then-update sequence can use the fresh id with no stale + * closure). Seeds the draft cache with the server copy so reads stay in sync. + */ +export function useUpdateDraft(organizationId: string) { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async ({ + id, + body, + }: { + id: string; + body: UpdateHackathonDraftBody; + }): Promise => + unwrapData( + await apiClient.PATCH( + '/api/organizations/{organizationId}/hackathons/draft/{id}', + { params: { path: { organizationId, id } }, body } + ) + ), + onSuccess: draft => { + queryClient.setQueryData( + hackathonKeys.draft(organizationId, draft.id), + draft + ); + }, + }); +} + +/** Delete a draft. */ +export function useDeleteDraft(organizationId: string) { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async (id: string): Promise => { + return unwrapData( + await apiClient.DELETE( + '/api/organizations/{organizationId}/hackathons/draft/{id}', + { params: { path: { organizationId, id } } } + ) + ); + }, + onSuccess: () => + queryClient.invalidateQueries({ + queryKey: hackathonKeys.drafts(organizationId), + }), + }); +} diff --git a/features/hackathons/api/use-escrow.ts b/features/hackathons/api/use-escrow.ts new file mode 100644 index 000000000..78993e766 --- /dev/null +++ b/features/hackathons/api/use-escrow.ts @@ -0,0 +1,343 @@ +'use client'; + +/** + * React Query hooks for the v2 hackathon escrow flow (boundless-events). + * + * Layered as: + * 1. useEscrowOp — polling primitive; watches an op to a terminal state. + * 2. mutation wrappers — usePublishHackathonEscrow / useSelectWinners / + * useCancelEscrow / useAnchorSubmission / ... + * 3. useEscrowOpRunner — orchestrates start -> (sign+submit for EXTERNAL) -> + * poll-to-terminal, and invalidates hackathon caches + * on COMPLETED. This replaces the old EscrowProvider + * that stored a TrustlessWork MultiReleaseEscrow. + * + * MANAGED ops come back already in PENDING_CONFIRM (backend signed+submitted), + * so the runner just polls. EXTERNAL ops come back in PENDING_SIGN with an + * `unsignedXdr`; the runner signs via the injected `signXdr` and posts it to + * submit-signed before polling. The signer is wired in Phase 7 (Freighter); + * omit it for the custodial/managed path. + */ +import { useCallback, useEffect, useRef, useState } from 'react'; +import { + useMutation, + useQuery, + useQueryClient, + type QueryKey, +} from '@tanstack/react-query'; +import { + anchorHackathonSubmission, + cancelHackathonEscrow, + getHackathonEscrowOp, + getParticipantEscrowOp, + publishHackathonEscrow, + selectHackathonWinners, + submitSignedHackathonEscrow, + submitSignedParticipantEscrow, + withdrawHackathonSubmission, +} from './escrow-client'; +import { + isTerminalEscrowStatus, + type AnchorHackathonSubmissionRequest, + type CancelHackathonEscrowRequest, + type EscrowOpResponse, + type EscrowOpStatus, + type PublishHackathonEscrowRequest, + type SelectHackathonWinnersRequest, + type WithdrawHackathonSubmissionRequest, +} from '../types'; + +// ─── Scope: organizer (org-scoped) vs participant (hackathon-scoped) ───────── + +export type EscrowOpScope = + | { kind: 'organizer'; organizationId: string; hackathonId: string } + | { kind: 'participant'; hackathonId: string }; + +function getOpForScope( + scope: EscrowOpScope, + opRowId: string +): Promise { + return scope.kind === 'organizer' + ? getHackathonEscrowOp(scope.organizationId, scope.hackathonId, opRowId) + : getParticipantEscrowOp(scope.hackathonId, opRowId); +} + +function submitSignedForScope( + scope: EscrowOpScope, + opRowId: string, + signedXdr: string +): Promise { + return scope.kind === 'organizer' + ? submitSignedHackathonEscrow( + scope.organizationId, + scope.hackathonId, + opRowId, + { signedXdr } + ) + : submitSignedParticipantEscrow(scope.hackathonId, opRowId, { signedXdr }); +} + +function escrowOpKey(scope: EscrowOpScope, opRowId: string): QueryKey { + return scope.kind === 'organizer' + ? [ + 'escrow-op', + 'organizer', + scope.organizationId, + scope.hackathonId, + opRowId, + ] + : ['escrow-op', 'participant', scope.hackathonId, opRowId]; +} + +// ─── 1. Polling primitive ──────────────────────────────────────────────────── + +export interface UseEscrowOpOptions { + enabled?: boolean; + /** Poll cadence while the op is non-terminal. Default 2500ms. */ + pollMs?: number; +} + +/** + * Poll an escrow op until it reaches a terminal state. Returns the standard + * react-query result; `data` is the latest EscrowOpResponse. + */ +export function useEscrowOp( + scope: EscrowOpScope, + opRowId: string | null | undefined, + options: UseEscrowOpOptions = {} +) { + const pollMs = options.pollMs ?? 2500; + return useQuery({ + queryKey: opRowId ? escrowOpKey(scope, opRowId) : ['escrow-op', 'idle'], + queryFn: () => getOpForScope(scope, opRowId as string), + enabled: !!opRowId && (options.enabled ?? true), + refetchInterval: query => { + const data = query.state.data as EscrowOpResponse | undefined; + if (!data) return pollMs; + return isTerminalEscrowStatus(data.status) ? false : pollMs; + }, + // Pending ops change server-side; never treat a non-terminal row as fresh. + staleTime: 0, + }); +} + +// ─── 2. Mutation wrappers ──────────────────────────────────────────────────── + +export function usePublishHackathonEscrow( + organizationId: string, + hackathonId: string +) { + return useMutation({ + mutationFn: (body: PublishHackathonEscrowRequest) => + publishHackathonEscrow(organizationId, hackathonId, body), + }); +} + +export function useSelectWinners(organizationId: string, hackathonId: string) { + return useMutation({ + mutationFn: (body: SelectHackathonWinnersRequest) => + selectHackathonWinners(organizationId, hackathonId, body), + }); +} + +export function useCancelEscrow(organizationId: string, hackathonId: string) { + return useMutation({ + mutationFn: (body: CancelHackathonEscrowRequest) => + cancelHackathonEscrow(organizationId, hackathonId, body), + }); +} + +export function useAnchorSubmission(hackathonId: string, submissionId: string) { + return useMutation({ + mutationFn: (body: AnchorHackathonSubmissionRequest) => + anchorHackathonSubmission(hackathonId, submissionId, body), + }); +} + +export function useWithdrawSubmission( + hackathonId: string, + submissionId: string +) { + return useMutation({ + mutationFn: (body: WithdrawHackathonSubmissionRequest) => + withdrawHackathonSubmission(hackathonId, submissionId, body), + }); +} + +// ─── 3. Orchestrating runner ───────────────────────────────────────────────── + +/** Sign an unsigned XDR for the EXTERNAL path. */ +export type SignXdrFn = ( + unsignedXdr: string, + signerHint?: string | null +) => Promise; + +export type EscrowRunPhase = + | 'idle' + | 'starting' + | 'signing' + | 'submitting' + | 'polling' + | 'completed' + | 'failed'; + +export interface UseEscrowOpRunnerOptions { + /** + * Signer for the EXTERNAL path. When the start op returns PENDING_SIGN with + * an unsignedXdr, the runner calls this then posts to submit-signed. Omit for + * MANAGED-only flows (the op is already PENDING_CONFIRM). + */ + signXdr?: SignXdrFn; + /** + * Query keys to invalidate when the op COMPLETES (e.g. hackathon detail so a + * status transition renders). Defaults to the whole `['hackathon']` tree. + */ + invalidateKeys?: QueryKey[]; + pollMs?: number; +} + +export interface EscrowOpRunner { + /** Kick off an op. `start` is the mutation call returning the built op. */ + run: ( + start: () => Promise + ) => Promise; + reset: () => void; + /** Latest op (polled if available, else the build result). */ + op: EscrowOpResponse | null; + status: EscrowOpStatus | 'IDLE'; + phase: EscrowRunPhase; + /** True while building/signing/submitting/confirming. */ + isRunning: boolean; + isCompleted: boolean; + isFailed: boolean; + isTerminal: boolean; + /** Friendly error text (contract errorCode or thrown message). */ + error: string | null; + txHash: string | null; +} + +const DEFAULT_INVALIDATE: QueryKey[] = [['hackathon']]; + +/** + * Drive a single escrow op from start to terminal state, handling the + * MANAGED-vs-EXTERNAL signing branch and cache invalidation on completion. + */ +export function useEscrowOpRunner( + scope: EscrowOpScope, + options: UseEscrowOpRunnerOptions = {} +): EscrowOpRunner { + const queryClient = useQueryClient(); + const [opRowId, setOpRowId] = useState(null); + const [startOp, setStartOp] = useState(null); + const [phase, setPhase] = useState('idle'); + const [error, setError] = useState(null); + // Guard so the terminal-side-effect (invalidate) fires once per op. + const settledRef = useRef(null); + + const { signXdr, pollMs } = options; + const invalidateKeys = options.invalidateKeys ?? DEFAULT_INVALIDATE; + + const poll = useEscrowOp(scope, opRowId, { + enabled: !!opRowId, + pollMs, + }); + + const op = poll.data ?? startOp; + const status: EscrowOpStatus | 'IDLE' = op?.status ?? 'IDLE'; + + // React to terminal transitions observed by the poller. + useEffect(() => { + if (!op || !opRowId) return; + if (!isTerminalEscrowStatus(op.status)) return; + if (settledRef.current === opRowId) return; + settledRef.current = opRowId; + + if (op.status === 'COMPLETED') { + setPhase('completed'); + invalidateKeys.forEach(key => + queryClient.invalidateQueries({ queryKey: key }) + ); + } else { + setPhase('failed'); + setError(prev => prev ?? op.errorCode ?? `Escrow op ${op.status}`); + } + // queryClient + invalidateKeys are stable enough; op.status is the trigger. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [op?.status, opRowId]); + + const reset = useCallback(() => { + setOpRowId(null); + setStartOp(null); + setPhase('idle'); + setError(null); + settledRef.current = null; + }, []); + + const run = useCallback( + async ( + start: () => Promise + ): Promise => { + setError(null); + settledRef.current = null; + setPhase('starting'); + try { + const built = await start(); + setStartOp(built); + setOpRowId(built.id); + + // EXTERNAL: the op needs a wallet signature before it can settle. + if (built.status === 'PENDING_SIGN' && built.unsignedXdr && signXdr) { + setPhase('signing'); + const signed = await signXdr(built.unsignedXdr, built.signerHint); + setPhase('submitting'); + const submitted = await submitSignedForScope(scope, built.id, signed); + setStartOp(submitted); + setPhase('polling'); + return submitted; + } + + if (built.status === 'PENDING_SIGN' && !signXdr) { + // External op with no signer available — can't progress. + setPhase('failed'); + setError( + 'This op needs a connected wallet signature, but no signer is ' + + 'configured. Use the managed wallet or connect a wallet.' + ); + return built; + } + + // MANAGED (already PENDING_CONFIRM) or terminal: let the poller finish. + setPhase(isTerminalEscrowStatus(built.status) ? 'polling' : 'polling'); + return built; + } catch (err) { + setPhase('failed'); + setError( + err instanceof Error ? err.message : 'Failed to run escrow op' + ); + return null; + } + }, + [scope, signXdr] + ); + + const isTerminal = status !== 'IDLE' && isTerminalEscrowStatus(status); + + return { + run, + reset, + op, + status, + phase, + isRunning: + phase === 'starting' || + phase === 'signing' || + phase === 'submitting' || + (phase === 'polling' && !isTerminal), + isCompleted: status === 'COMPLETED', + isFailed: + status === 'FAILED' || status === 'CANCELLED' || phase === 'failed', + isTerminal, + error, + txHash: op?.txHash ?? null, + }; +} diff --git a/features/hackathons/api/use-submission-anchor.ts b/features/hackathons/api/use-submission-anchor.ts new file mode 100644 index 000000000..5003c39cc --- /dev/null +++ b/features/hackathons/api/use-submission-anchor.ts @@ -0,0 +1,98 @@ +'use client'; + +import { useCallback } from 'react'; + +import { anchorHackathonSubmission } from './escrow-client'; +import { useEscrowOpRunner } from './use-escrow'; +import type { EscrowOpResponse } from '../types'; + +const SUBMISSION_CONTENT_BASE = + process.env.NEXT_PUBLIC_APP_URL?.replace(/\/$/, '') || 'https://boundless.fi'; + +/** + * Canonical, on-chain-stored content URI for a submission anchor. Deterministic + * from the ids so a retry produces the same value (the op_id is hash-locked on + * the backend, so re-anchoring is idempotent). + */ +export function buildSubmissionContentUri( + hackathonId: string, + submissionId: string +): string { + return `${SUBMISSION_CONTENT_BASE}/hackathons/${hackathonId}/submissions/${submissionId}`; +} + +export interface UseSubmissionAnchor { + /** + * Anchor a submission on-chain via the participant's Boundless-managed wallet. + * Resolves to the built op (or null if the start call threw). Track progress + * via `phase`/`isAnchoring`/`isAnchored`/`isFailed` rather than the return. + */ + anchor: (args: { + submissionId: string; + applicantAddress: string; + }) => Promise; + reset: () => void; + op: EscrowOpResponse | null; + /** Current escrow run phase (idle → starting → polling → completed/failed). */ + phase: ReturnType['phase']; + /** True while building/submitting/confirming on-chain. */ + isAnchoring: boolean; + /** True once the anchor op reached COMPLETED (submission is prize-eligible). */ + isAnchored: boolean; + isFailed: boolean; + error: string | null; + txHash: string | null; +} + +/** + * Anchor a hackathon submission on the boundless-events contract using the + * participant's **Boundless-managed** custodial wallet (MANAGED funding mode — + * there is never an in-browser signature for participants). + * + * Composes the shared {@link useEscrowOpRunner}: the backend signs + submits + * (sponsor-paid fee-bump), so the op returns `PENDING_CONFIRM` and the runner + * polls it to a terminal state — no `signXdr` is wired. A submission only + * becomes prize-eligible once this reaches `COMPLETED` (the backend sets + * `escrowAnchorStatus='active'` + `applicantAddress`, which is the exact address + * winners are later paid to via `select_winners`). + * + * SOLID: this hook owns *only* the on-chain anchoring concern. The caller is + * responsible for ensuring the managed wallet is ready and passing its address + * (so this stays decoupled from the wallet provider and trivially testable). + * + * @param hackathonId the hackathon **CUID** (not the slug — the participant + * escrow endpoint resolves `:id` by primary key). + */ +export function useSubmissionAnchor(hackathonId: string): UseSubmissionAnchor { + // MANAGED-only → no signer. On COMPLETED the runner invalidates the + // ['hackathon'] tree, which covers the participant's my-submission query and + // the hackathon detail so the anchored state renders. + const runner = useEscrowOpRunner({ kind: 'participant', hackathonId }); + + const anchor = useCallback( + (args: { + submissionId: string; + applicantAddress: string; + }): Promise => + runner.run(() => + anchorHackathonSubmission(hackathonId, args.submissionId, { + applicantAddress: args.applicantAddress, + contentUri: buildSubmissionContentUri(hackathonId, args.submissionId), + fundingMode: 'MANAGED', + }) + ), + [hackathonId, runner] + ); + + return { + anchor, + reset: runner.reset, + op: runner.op, + phase: runner.phase, + isAnchoring: runner.isRunning, + isAnchored: runner.isCompleted, + isFailed: runner.isFailed, + error: runner.error, + txHash: runner.txHash, + }; +} diff --git a/hooks/hackathon/use-submission.ts b/features/hackathons/api/use-submission.ts similarity index 78% rename from hooks/hackathon/use-submission.ts rename to features/hackathons/api/use-submission.ts index ae8503be3..c1359f7fb 100644 --- a/hooks/hackathon/use-submission.ts +++ b/features/hackathons/api/use-submission.ts @@ -1,6 +1,7 @@ 'use client'; -import { useState, useCallback, useEffect } from 'react'; +import { useState, useCallback } from 'react'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { createSubmission, updateSubmission, @@ -118,39 +119,55 @@ export function useSubmission({ autoFetch = true, }: UseSubmissionOptions) { const { isAuthenticated } = useAuthStatus(); - const [submission, setSubmission] = useState( - null - ); + const queryClient = useQueryClient(); const [isSubmitting, setIsSubmitting] = useState(false); - const [isFetching, setIsFetching] = useState(false); const [error, setError] = useState(null); - const fetchMySubmission = useCallback(async () => { - if (!isAuthenticated || !hackathonSlugOrId) { - setSubmission(null); - return; - } + // Single shared, cached "my submission" query — replaces the manual + // useEffect+fetch that re-fired on every render / StrictMode pass and once per + // component using this hook, hammering /my-submission into 429s. A 404 means + // "no submission yet": map it to empty data so React Query caches it rather + // than re-requesting (the global config also doesn't retry 4xx). + const myQuery = useQuery({ + queryKey: ['hackathon', hackathonSlugOrId, 'my-submission'], + queryFn: async () => { + try { + return await getMySubmission(hackathonSlugOrId); + } catch (err) { + const status = + (err as { status?: number })?.status ?? + (err as { response?: { status?: number } })?.response?.status; + if (status === 404) { + return { success: true, data: null } as Awaited< + ReturnType + >; + } + throw err; + } + }, + enabled: autoFetch && isAuthenticated && !!hackathonSlugOrId, + staleTime: 60_000, + }); - setIsFetching(true); - setError(null); + const submission: ParticipantSubmission | null = + myQuery.data?.success && myQuery.data.data ? myQuery.data.data : null; + const isFetching = myQuery.isFetching; - try { - const response = await getMySubmission(hackathonSlugOrId); + const setSubmissionCache = useCallback( + (next: ParticipantSubmission | null) => { + queryClient.setQueryData( + ['hackathon', hackathonSlugOrId, 'my-submission'], + { success: true, data: next } + ); + }, + [queryClient, hackathonSlugOrId] + ); - if (response.success && response.data) { - setSubmission(response.data); - } else { - setSubmission(null); - } - } catch (err) { - const errorMessage = - err instanceof Error ? err.message : 'Failed to fetch submission'; - setError(errorMessage); - setSubmission(null); - } finally { - setIsFetching(false); - } - }, [hackathonSlugOrId, isAuthenticated]); + const fetchMySubmission = useCallback(() => { + void queryClient.invalidateQueries({ + queryKey: ['hackathon', hackathonSlugOrId, 'my-submission'], + }); + }, [queryClient, hackathonSlugOrId]); const create = useCallback( async (data: SubmissionFormData) => { @@ -179,7 +196,7 @@ export function useSubmission({ ); if (response?.success && response?.data) { - setSubmission(response.data); + setSubmissionCache(response.data); toast.success(response.message || 'Submission created successfully!'); return response.data; } @@ -206,7 +223,7 @@ export function useSubmission({ setIsSubmitting(false); } }, - [hackathonSlugOrId, isAuthenticated, organizationId] + [hackathonSlugOrId, isAuthenticated, organizationId, setSubmissionCache] ); const update = useCallback( @@ -232,7 +249,7 @@ export function useSubmission({ const response = await updateSubmission(submissionId, payload); if (response?.success && response?.data) { - setSubmission(response.data); + setSubmissionCache(response.data); toast.success(response.message || 'Submission updated successfully!'); return response.data; } @@ -259,7 +276,7 @@ export function useSubmission({ setIsSubmitting(false); } }, - [hackathonSlugOrId, isAuthenticated] + [hackathonSlugOrId, isAuthenticated, setSubmissionCache] ); const remove = useCallback( @@ -274,7 +291,7 @@ export function useSubmission({ try { await deleteSubmission(submissionId); - setSubmission(null); + setSubmissionCache(null); toast.success('Submission deleted successfully'); return true; } catch (err) { @@ -292,18 +309,9 @@ export function useSubmission({ setIsSubmitting(false); } }, - [hackathonSlugOrId, isAuthenticated] + [hackathonSlugOrId, isAuthenticated, setSubmissionCache] ); - // Auto-fetch submission on mount and when dependencies change - useEffect(() => { - if (autoFetch && isAuthenticated && hackathonSlugOrId) { - fetchMySubmission(); - } else if (!isAuthenticated) { - setSubmission(null); - } - }, [autoFetch, isAuthenticated, hackathonSlugOrId, fetchMySubmission]); - return { submission, isSubmitting, diff --git a/features/hackathons/index.ts b/features/hackathons/index.ts new file mode 100644 index 000000000..4c6b37dda --- /dev/null +++ b/features/hackathons/index.ts @@ -0,0 +1,103 @@ +/** + * Hackathons feature public surface. Import from `@/features/hackathons` rather + * than reaching into the api/ internals. + */ + +// Types (aliased from the backend-generated schema). +export type { + HackathonDraft, + HackathonDraftData, + UpdateHackathonDraftBody, + InfoSection, + TimelineSection, + ParticipationSection, + RewardsSection, + ResourcesSection, + JudgingSection, + CollaborationSection, + DraftSection, + EscrowOpResponse, + EscrowOpStatus, + EscrowOpKind, + PublishHackathonEscrowRequest, + SelectHackathonWinnersRequest, + CancelHackathonEscrowRequest, + SubmitSignedXdrRequest, + AnchorHackathonSubmissionRequest, + WithdrawHackathonSubmissionRequest, + WinnerDistributionEntry, + HackathonWinnerSelection, + RequestFundingOtpResponse, + VerifyFundingOtpResponse, + FundingMode, +} from './types'; +export { + DRAFT_SECTIONS, + TERMINAL_ESCROW_STATUSES, + isTerminalEscrowStatus, +} from './types'; + +// Query keys. +export { hackathonKeys } from './api/keys'; + +// Draft hooks (React Query). +export { + useDraft, + useDraftList, + useCreateDraft, + useUpdateDraft, + useDeleteDraft, +} from './api/use-draft'; + +// Draft client (imperative helpers, legacy-compatible signatures). +export { deleteDraft, previewAnnouncementAudience } from './api/draft-client'; +export type { + DeleteDraftResult, + AnnouncementAudiencePreview, +} from './api/draft-client'; + +// Escrow client (typed openapi-fetch). +export { + publishHackathonEscrow, + selectHackathonWinners, + cancelHackathonEscrow, + resetHackathonEscrowToDraft, + submitSignedHackathonEscrow, + getHackathonEscrowOp, + requestHackathonFundingOtp, + verifyHackathonFundingOtp, + anchorHackathonSubmission, + withdrawHackathonSubmission, + submitSignedParticipantEscrow, + getParticipantEscrowOp, +} from './api/escrow-client'; + +// Escrow hooks (React Query: polling primitive, mutation wrappers, op runner). +export { + useEscrowOp, + useEscrowOpRunner, + usePublishHackathonEscrow, + useSelectWinners, + useCancelEscrow, + useAnchorSubmission, + useWithdrawSubmission, +} from './api/use-escrow'; +export type { + EscrowOpScope, + SignXdrFn, + EscrowRunPhase, + UseEscrowOpOptions, + UseEscrowOpRunnerOptions, + EscrowOpRunner, +} from './api/use-escrow'; + +// Participant submission anchoring (MANAGED on-chain anchor via the op runner). +export { + useSubmissionAnchor, + buildSubmissionContentUri, +} from './api/use-submission-anchor'; +export type { UseSubmissionAnchor } from './api/use-submission-anchor'; + +// Participant submission CRUD (my-submission query + create/update/delete). +export { useSubmission } from './api/use-submission'; +export type { SubmissionFormData } from './api/use-submission'; diff --git a/features/hackathons/types.ts b/features/hackathons/types.ts new file mode 100644 index 000000000..420e3e0e2 --- /dev/null +++ b/features/hackathons/types.ts @@ -0,0 +1,77 @@ +/** + * Hackathon feature types. + * + * Every server shape is aliased from the backend-generated OpenAPI schema + * (lib/api/generated/schema.d.ts), so they never drift from boundless-nestjs. + * Run `npm run codegen` after a backend DTO change to refresh them. Do not + * hand-write server DTOs here. + */ +import type { Schemas } from '@/lib/api'; + +// ── Draft ──────────────────────────────────────────────────────────────────── + +/** Full draft as returned by GET/PATCH /draft/:id. */ +export type HackathonDraft = Schemas['HackathonDraftResponseDto']; +/** Section-keyed draft payload (information, timeline, ...). */ +export type HackathonDraftData = Schemas['HackathonDraftDataDto']; +/** Flat draft-update body: send any subset of sections in one PATCH. */ +export type UpdateHackathonDraftBody = Schemas['UpdateHackathonDraftDto']; + +// Section DTOs (the wire shape the backend persists + returns). +export type InfoSection = Schemas['InfoFormData']; +export type TimelineSection = Schemas['TimelineFormData']; +export type ParticipationSection = Schemas['ParticipantFormData']; +export type RewardsSection = Schemas['RewardsFormData']; +export type ResourcesSection = Schemas['ResourcesFormData']; +export type JudgingSection = Schemas['JudgingFormData']; +export type CollaborationSection = Schemas['CollaborationFormData']; + +/** The seven editable wizard sections, in order. */ +export const DRAFT_SECTIONS = [ + 'information', + 'timeline', + 'participation', + 'rewards', + 'resources', + 'judging', + 'collaboration', +] as const; +export type DraftSection = (typeof DRAFT_SECTIONS)[number]; + +// ── Escrow ───────────────────────────────────────────────────────────────── + +/** The EscrowOp row returned by every hackathon escrow endpoint. */ +export type EscrowOpResponse = Schemas['HackathonEscrowOpResponseDto']; +/** Op lifecycle status (derived from the generated union). */ +export type EscrowOpStatus = EscrowOpResponse['status']; +/** Contract operation kind (derived from the generated union). */ +export type EscrowOpKind = EscrowOpResponse['kind']; + +export type PublishHackathonEscrowRequest = + Schemas['PublishHackathonEscrowDto']; +export type SelectHackathonWinnersRequest = + Schemas['SelectHackathonWinnersDto']; +export type CancelHackathonEscrowRequest = Schemas['CancelHackathonEscrowDto']; +export type SubmitSignedXdrRequest = Schemas['HackathonSubmitSignedXdrDto']; +export type AnchorHackathonSubmissionRequest = Schemas['SubmitHackathonDto']; +export type WithdrawHackathonSubmissionRequest = + Schemas['WithdrawHackathonSubmissionDto']; +export type WinnerDistributionEntry = Schemas['WinnerDistributionEntryDto']; +export type HackathonWinnerSelection = Schemas['HackathonWinnerSelectionDto']; +export type RequestFundingOtpResponse = Schemas['RequestFundingOtpResponseDto']; +export type VerifyFundingOtpResponse = Schemas['VerifyFundingOtpResponseDto']; + +/** Signing path for an escrow op. */ +export type FundingMode = NonNullable< + PublishHackathonEscrowRequest['fundingMode'] +>; + +/** Terminal op states. Polling should stop once one is reached. */ +export const TERMINAL_ESCROW_STATUSES: readonly EscrowOpStatus[] = [ + 'COMPLETED', + 'FAILED', + 'CANCELLED', +]; + +export const isTerminalEscrowStatus = (status: EscrowOpStatus): boolean => + TERMINAL_ESCROW_STATUSES.includes(status); diff --git a/features/treasury/api.ts b/features/treasury/api.ts new file mode 100644 index 000000000..b6af5b7bf --- /dev/null +++ b/features/treasury/api.ts @@ -0,0 +1,217 @@ +import { api } from '@/lib/api/api'; +import type { + BuildSpendXdrResult, + InitiateSpendInput, + SpendRequest, + SpendStatus, + TreasuryAuditPage, + TreasuryPolicy, + TreasuryPolicyRule, + TreasuryWallet, + WalletBalance, +} from './types'; + +// The NestJS global interceptor wraps payloads in { success, message, data }. +// Tolerate a bare payload too (matches lib/api/hackathons/escrow.ts). +interface Wrapped { + success?: boolean; + message?: string; + data: T; +} + +const unwrap = (body: T | Wrapped): T => + body && + typeof body === 'object' && + 'data' in body && + (body as Wrapped).data !== undefined + ? (body as Wrapped).data + : (body as T); + +const base = (organizationId: string) => + `/organizations/${organizationId}/treasury`; + +// ── Wallets ────────────────────────────────────────────────────────────── + +export const listTreasuryWallets = async ( + organizationId: string +): Promise => { + const { data } = await api.get>( + `${base(organizationId)}/wallets` + ); + return unwrap(data) ?? []; +}; + +export const createManagedTreasuryWallet = async ( + organizationId: string, + label: string +): Promise => { + const { data } = await api.post>( + `${base(organizationId)}/wallets/managed`, + { label } + ); + return unwrap(data); +}; + +export const registerConnectedWallet = async ( + organizationId: string, + body: { publicKey: string; label: string; connectionMethod: string } +): Promise => { + const { data } = await api.post>( + `${base(organizationId)}/wallets/connected`, + body + ); + return unwrap(data); +}; + +export const updateTreasuryWallet = async ( + organizationId: string, + walletId: string, + patch: { label?: string; isDefault?: boolean } +): Promise => { + const { data } = await api.patch>( + `${base(organizationId)}/wallets/${walletId}`, + patch + ); + return unwrap(data); +}; + +export const archiveTreasuryWallet = async ( + organizationId: string, + walletId: string +): Promise => { + const { data } = await api.post>( + `${base(organizationId)}/wallets/${walletId}/archive` + ); + return unwrap(data); +}; + +export const getWalletBalance = async ( + organizationId: string, + walletId: string +): Promise => { + const { data } = await api.get>( + `${base(organizationId)}/wallets/${walletId}/balance` + ); + return unwrap(data); +}; + +export const getDefaultTreasuryWallet = async ( + organizationId: string +): Promise => { + const { data } = await api.get>( + `${base(organizationId)}/default-wallet` + ); + return unwrap(data); +}; + +// ── Policy ─────────────────────────────────────────────────────────────── + +export const getTreasuryPolicy = async ( + organizationId: string +): Promise => { + const { data } = await api.get>( + `${base(organizationId)}/policy` + ); + return unwrap(data); +}; + +export const updateTreasuryPolicy = async ( + organizationId: string, + body: { rules: TreasuryPolicyRule[]; defaultWalletId?: string } +): Promise => { + const { data } = await api.put>( + `${base(organizationId)}/policy`, + body + ); + return unwrap(data); +}; + +// ── Spend requests ─────────────────────────────────────────────────────── + +export const listSpendRequests = async ( + organizationId: string, + status?: SpendStatus +): Promise => { + const query = status ? `?status=${status}` : ''; + const { data } = await api.get>( + `${base(organizationId)}/spend${query}` + ); + return unwrap(data) ?? []; +}; + +export const initiateSpend = async ( + organizationId: string, + body: InitiateSpendInput +): Promise => { + const { data } = await api.post>( + `${base(organizationId)}/spend`, + body + ); + return unwrap(data); +}; + +const spendAction = async ( + organizationId: string, + requestId: string, + action: 'approve' | 'reject' | 'cancel' | 'execute', + body?: { note?: string } +): Promise => { + const { data } = await api.post>( + `${base(organizationId)}/spend/${requestId}/${action}`, + body ?? {} + ); + return unwrap(data); +}; + +export const approveSpend = ( + organizationId: string, + requestId: string, + note?: string +) => spendAction(organizationId, requestId, 'approve', { note }); + +export const rejectSpend = ( + organizationId: string, + requestId: string, + note?: string +) => spendAction(organizationId, requestId, 'reject', { note }); + +export const cancelSpend = (organizationId: string, requestId: string) => + spendAction(organizationId, requestId, 'cancel'); + +export const executeSpend = (organizationId: string, requestId: string) => + spendAction(organizationId, requestId, 'execute'); + +export const buildSpendXdr = async ( + organizationId: string, + requestId: string +): Promise => { + const { data } = await api.post< + BuildSpendXdrResult | Wrapped + >(`${base(organizationId)}/spend/${requestId}/build-xdr`); + return unwrap(data); +}; + +export const submitSpendSignedXdr = async ( + organizationId: string, + requestId: string, + signedXdr: string +): Promise => { + const { data } = await api.post>( + `${base(organizationId)}/spend/${requestId}/submit-signed-xdr`, + { signedXdr } + ); + return unwrap(data); +}; + +// ── Audit log ──────────────────────────────────────────────────────────── + +export const getAuditLog = async ( + organizationId: string, + page = 1, + limit = 50 +): Promise => { + const { data } = await api.get< + TreasuryAuditPage | Wrapped + >(`${base(organizationId)}/audit-log?page=${page}&limit=${limit}`); + return unwrap(data); +}; diff --git a/features/treasury/index.ts b/features/treasury/index.ts new file mode 100644 index 000000000..8c6d67413 --- /dev/null +++ b/features/treasury/index.ts @@ -0,0 +1,20 @@ +export * from './types'; +export { treasuryKeys } from './keys'; +export * from './api'; +export { + useTreasuryWallets, + useCreateManagedWallet, + useRegisterConnectedWallet, + useUpdateWallet, + useArchiveWallet, + useWalletBalance, +} from './use-treasury-wallets'; +export { + useSpendRequests, + useInitiateSpend, + useSpendDecision, + useBuildSpendXdr, + useSubmitSignedXdr, +} from './use-treasury-spend'; +export { useTreasuryPolicy, useUpdatePolicy } from './use-treasury-policy'; +export { useAuditLog } from './use-treasury-audit'; diff --git a/features/treasury/keys.ts b/features/treasury/keys.ts new file mode 100644 index 000000000..8f20ec424 --- /dev/null +++ b/features/treasury/keys.ts @@ -0,0 +1,13 @@ +export const treasuryKeys = { + all: ['treasury'] as const, + wallets: (organizationId: string) => + ['treasury', 'wallets', organizationId] as const, + balance: (organizationId: string, walletId: string) => + ['treasury', 'balance', organizationId, walletId] as const, + policy: (organizationId: string) => + ['treasury', 'policy', organizationId] as const, + spends: (organizationId: string, status?: string) => + ['treasury', 'spends', organizationId, status ?? 'all'] as const, + audit: (organizationId: string, page: number) => + ['treasury', 'audit', organizationId, page] as const, +}; diff --git a/features/treasury/types.ts b/features/treasury/types.ts new file mode 100644 index 000000000..d01a528b0 --- /dev/null +++ b/features/treasury/types.ts @@ -0,0 +1,111 @@ +// Treasury feature types. Hand-written to mirror the backend treasury DTOs +// (boundless-nestjs treasury module). Migrate to generated OpenAPI types once +// the treasury endpoints are in the committed schema snapshot. + +export type TreasuryWalletKind = 'MANAGED' | 'CONNECTED'; +export type TreasuryWalletStatus = 'ACTIVE' | 'ARCHIVED' | 'NEEDS_REVIEW'; + +export interface TreasuryWallet { + id: string; + organizationId: string; + kind: TreasuryWalletKind; + publicKey: string; + label: string; + isDefault: boolean; + status: TreasuryWalletStatus; + isMultisig: boolean; + multisigThreshold: number | null; + connectionMethod: string | null; + lastVerifiedAt: string | null; + createdAt: string; + updatedAt: string; +} + +export interface WalletBalance { + publicKey: string; + usdc: string; + xlm: string; +} + +export interface TreasuryPolicyRule { + min_usdc: number; + max_usdc: number | null; + required_approvals: number; + approver_roles: string[]; +} + +export interface TreasuryPolicy { + organizationId: string; + defaultWalletId: string | null; + rules: TreasuryPolicyRule[]; + isDefault: boolean; + updatedAt: string | null; +} + +export type SpendStatus = + | 'PENDING' + | 'APPROVED' + | 'REJECTED' + | 'AWAITING_SIGNATURES' + | 'SUBMITTED' + | 'COMPLETED' + | 'FAILED' + | 'CANCELLED'; + +export interface SpendApproval { + user_id: string; + action: 'approve' | 'reject'; + note?: string; + timestamp: string; +} + +export interface SpendRequest { + id: string; + organizationId: string; + sourceWalletId: string; + destination: string; + amount: string; + currency: string; + purpose: string; + referenceType: string | null; + referenceId: string | null; + initiatorUserId: string; + requiredApprovals: number; + approvals: SpendApproval[]; + status: SpendStatus; + onChainTxHash: string | null; + createdAt: string; + approvedAt: string | null; +} + +export interface InitiateSpendInput { + sourceWalletId: string; + destination: string; + amount: string; + purpose: string; + referenceType?: string; + referenceId?: string; +} + +export interface TreasuryAuditEntry { + id: string; + action: string; + actorUserId: string | null; + actorKind: string; + walletId: string | null; + spendRequestId: string | null; + details: unknown; + createdAt: string; +} + +export interface TreasuryAuditPage { + data: TreasuryAuditEntry[]; + total: number; + page: number; + limit: number; +} + +export interface BuildSpendXdrResult { + unsignedXdr: string; + request: SpendRequest; +} diff --git a/features/treasury/use-treasury-audit.ts b/features/treasury/use-treasury-audit.ts new file mode 100644 index 000000000..13051e651 --- /dev/null +++ b/features/treasury/use-treasury-audit.ts @@ -0,0 +1,14 @@ +'use client'; + +import { useQuery } from '@tanstack/react-query'; +import { getAuditLog } from './api'; +import { treasuryKeys } from './keys'; + +export function useAuditLog(organizationId?: string, page = 1, limit = 50) { + return useQuery({ + queryKey: treasuryKeys.audit(organizationId ?? '', page), + queryFn: () => getAuditLog(organizationId as string, page, limit), + enabled: !!organizationId, + staleTime: 10_000, + }); +} diff --git a/features/treasury/use-treasury-policy.ts b/features/treasury/use-treasury-policy.ts new file mode 100644 index 000000000..86d44fadb --- /dev/null +++ b/features/treasury/use-treasury-policy.ts @@ -0,0 +1,29 @@ +'use client'; + +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { getTreasuryPolicy, updateTreasuryPolicy } from './api'; +import { treasuryKeys } from './keys'; +import type { TreasuryPolicyRule } from './types'; + +export function useTreasuryPolicy(organizationId?: string) { + return useQuery({ + queryKey: treasuryKeys.policy(organizationId ?? ''), + queryFn: () => getTreasuryPolicy(organizationId as string), + enabled: !!organizationId, + staleTime: 30_000, + }); +} + +export function useUpdatePolicy(organizationId: string) { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (body: { + rules: TreasuryPolicyRule[]; + defaultWalletId?: string; + }) => updateTreasuryPolicy(organizationId, body), + onSuccess: () => + void queryClient.invalidateQueries({ + queryKey: treasuryKeys.policy(organizationId), + }), + }); +} diff --git a/features/treasury/use-treasury-spend.ts b/features/treasury/use-treasury-spend.ts new file mode 100644 index 000000000..07ccc5d71 --- /dev/null +++ b/features/treasury/use-treasury-spend.ts @@ -0,0 +1,85 @@ +'use client'; + +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { + approveSpend, + buildSpendXdr, + cancelSpend, + executeSpend, + initiateSpend, + listSpendRequests, + rejectSpend, + submitSpendSignedXdr, +} from './api'; +import { treasuryKeys } from './keys'; +import type { InitiateSpendInput, SpendStatus } from './types'; + +export function useSpendRequests( + organizationId?: string, + status?: SpendStatus +) { + return useQuery({ + queryKey: treasuryKeys.spends(organizationId ?? '', status), + queryFn: () => listSpendRequests(organizationId as string, status), + enabled: !!organizationId, + staleTime: 10_000, + }); +} + +function useSpendInvalidation(organizationId: string) { + const queryClient = useQueryClient(); + return () => + queryClient.invalidateQueries({ + queryKey: ['treasury', 'spends', organizationId], + }); +} + +export function useInitiateSpend(organizationId: string) { + const invalidate = useSpendInvalidation(organizationId); + return useMutation({ + mutationFn: (body: InitiateSpendInput) => + initiateSpend(organizationId, body), + onSuccess: () => void invalidate(), + }); +} + +/** approve / reject / cancel / execute, keyed by action. */ +export function useSpendDecision(organizationId: string) { + const invalidate = useSpendInvalidation(organizationId); + return useMutation({ + mutationFn: (vars: { + requestId: string; + action: 'approve' | 'reject' | 'cancel' | 'execute'; + note?: string; + }) => { + switch (vars.action) { + case 'approve': + return approveSpend(organizationId, vars.requestId, vars.note); + case 'reject': + return rejectSpend(organizationId, vars.requestId, vars.note); + case 'cancel': + return cancelSpend(organizationId, vars.requestId); + case 'execute': + return executeSpend(organizationId, vars.requestId); + } + }, + onSuccess: () => void invalidate(), + }); +} + +export function useBuildSpendXdr(organizationId: string) { + const invalidate = useSpendInvalidation(organizationId); + return useMutation({ + mutationFn: (requestId: string) => buildSpendXdr(organizationId, requestId), + onSuccess: () => void invalidate(), + }); +} + +export function useSubmitSignedXdr(organizationId: string) { + const invalidate = useSpendInvalidation(organizationId); + return useMutation({ + mutationFn: (vars: { requestId: string; signedXdr: string }) => + submitSpendSignedXdr(organizationId, vars.requestId, vars.signedXdr), + onSuccess: () => void invalidate(), + }); +} diff --git a/features/treasury/use-treasury-wallets.ts b/features/treasury/use-treasury-wallets.ts new file mode 100644 index 000000000..1bec32d57 --- /dev/null +++ b/features/treasury/use-treasury-wallets.ts @@ -0,0 +1,85 @@ +'use client'; + +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { + archiveTreasuryWallet, + createManagedTreasuryWallet, + getWalletBalance, + listTreasuryWallets, + registerConnectedWallet, + updateTreasuryWallet, +} from './api'; +import { treasuryKeys } from './keys'; + +/** List an organization's treasury wallets (default first). */ +export function useTreasuryWallets(organizationId?: string) { + return useQuery({ + queryKey: treasuryKeys.wallets(organizationId ?? ''), + queryFn: () => listTreasuryWallets(organizationId as string), + enabled: !!organizationId, + staleTime: 30_000, + }); +} + +function useWalletInvalidation(organizationId: string) { + const queryClient = useQueryClient(); + return () => + queryClient.invalidateQueries({ + queryKey: treasuryKeys.wallets(organizationId), + }); +} + +/** Create a Tier 1 managed treasury wallet. */ +export function useCreateManagedWallet(organizationId: string) { + const invalidate = useWalletInvalidation(organizationId); + return useMutation({ + mutationFn: (label: string) => + createManagedTreasuryWallet(organizationId, label), + onSuccess: () => void invalidate(), + }); +} + +/** Register a connected (Tier 2/3) wallet. */ +export function useRegisterConnectedWallet(organizationId: string) { + const invalidate = useWalletInvalidation(organizationId); + return useMutation({ + mutationFn: (body: { + publicKey: string; + label: string; + connectionMethod: string; + }) => registerConnectedWallet(organizationId, body), + onSuccess: () => void invalidate(), + }); +} + +/** Update a wallet label / default flag. */ +export function useUpdateWallet(organizationId: string) { + const invalidate = useWalletInvalidation(organizationId); + return useMutation({ + mutationFn: (vars: { + walletId: string; + patch: { label?: string; isDefault?: boolean }; + }) => updateTreasuryWallet(organizationId, vars.walletId, vars.patch), + onSuccess: () => void invalidate(), + }); +} + +/** Archive a wallet. */ +export function useArchiveWallet(organizationId: string) { + const invalidate = useWalletInvalidation(organizationId); + return useMutation({ + mutationFn: (walletId: string) => + archiveTreasuryWallet(organizationId, walletId), + onSuccess: () => void invalidate(), + }); +} + +/** Live USDC + XLM balance for a wallet. */ +export function useWalletBalance(organizationId: string, walletId?: string) { + return useQuery({ + queryKey: treasuryKeys.balance(organizationId, walletId ?? ''), + queryFn: () => getWalletBalance(organizationId, walletId as string), + enabled: !!organizationId && !!walletId, + staleTime: 15_000, + }); +} diff --git a/hooks/hackathon/use-cancel-hackathon.ts b/hooks/hackathon/use-cancel-hackathon.ts new file mode 100644 index 000000000..2ac5d19bd --- /dev/null +++ b/hooks/hackathon/use-cancel-hackathon.ts @@ -0,0 +1,78 @@ +'use client'; + +import { useEffect, useRef, useState } from 'react'; +import { toast } from 'sonner'; +import { useWalletContext } from '@/components/providers/wallet-provider'; +import { useCancelEscrow, useEscrowOpRunner } from '@/features/hackathons'; +import { signXdrWithKit } from '@/lib/wallet/wallet-kit'; +import type { FundingMode } from '@/features/hackathons'; + +interface UseCancelHackathonOptions { + /** Signing path. Defaults to MANAGED (custodial). */ + fundingMode?: FundingMode; + onSuccess?: () => void; +} + +/** + * Cancels a funded hackathon on the events contract. + * + * The cancel op refunds partner contributions then the owner residual. For + * MANAGED the backend signs + submits the start-cancel tx; the paged + * batch-refund + finalize steps are driven server-side, so we poll the + * returned op to COMPLETED as an "initiated" signal and let the backend + * settle the refunds. + */ +export function useCancelHackathon( + organizationId: string, + hackathonId: string, + options: UseCancelHackathonOptions = {} +) { + const { walletAddress } = useWalletContext(); + const fundingMode: FundingMode = options.fundingMode ?? 'MANAGED'; + const cancelMutation = useCancelEscrow(organizationId, hackathonId); + const runner = useEscrowOpRunner( + { kind: 'organizer', organizationId, hackathonId }, + fundingMode === 'EXTERNAL' ? { signXdr: signXdrWithKit } : undefined + ); + + const [started, setStarted] = useState(false); + const onSuccessRef = useRef(options.onSuccess); + onSuccessRef.current = options.onSuccess; + + useEffect(() => { + if (!started) return; + if (runner.isCompleted) { + setStarted(false); + toast.success( + 'Hackathon cancellation submitted. Refunds are processing on-chain.' + ); + onSuccessRef.current?.(); + } else if (runner.isFailed) { + setStarted(false); + toast.error( + runner.error || 'Failed to cancel the hackathon. Please try again.' + ); + } + }, [started, runner.isCompleted, runner.isFailed, runner.error]); + + const cancel = async () => { + if (!walletAddress) { + toast.error('Please connect your wallet to cancel this hackathon.'); + return; + } + setStarted(true); + const op = await runner.run(() => + cancelMutation.mutateAsync({ + ownerAddress: walletAddress, + fundingMode, + }) + ); + if (!op) setStarted(false); // run() already surfaced the error + }; + + return { + cancel, + isCancelling: started && (cancelMutation.isPending || runner.isRunning), + phase: runner.phase, + }; +} diff --git a/hooks/hackathon/use-delete-hackathon.ts b/hooks/hackathon/use-delete-hackathon.ts index d1a6c0917..35007d24d 100644 --- a/hooks/hackathon/use-delete-hackathon.ts +++ b/hooks/hackathon/use-delete-hackathon.ts @@ -2,7 +2,7 @@ import { useState, useCallback } from 'react'; import { deleteHackathon } from '@/lib/api/hackathons'; -import { deleteDraft } from '@/lib/api/hackathons/draft'; +import { deleteDraft } from '@/features/hackathons'; import { useAuthStatus } from '@/hooks/use-auth'; import { toast } from 'sonner'; diff --git a/hooks/hackathon/use-hackathons-list.ts b/hooks/hackathon/use-hackathons-list.ts index 8c075db2a..012edecfd 100644 --- a/hooks/hackathon/use-hackathons-list.ts +++ b/hooks/hackathon/use-hackathons-list.ts @@ -1,14 +1,10 @@ 'use client'; import * as React from 'react'; -import { - getPublicHackathonsList, - type Hackathon, - type PublicHackathonsListData, -} from '@/lib/api/hackathons'; +import { useInfiniteQuery, keepPreviousData } from '@tanstack/react-query'; +import { getPublicHackathonsList, type Hackathon } from '@/lib/api/hackathons'; import type { HackathonFilters } from './use-hackathon-filters'; import { mapSortToAPI, mapStatusToAPI } from './use-hackathon-filters'; -import { reportError } from '@/lib/error-reporting'; type SortOption = | 'newest' @@ -37,223 +33,154 @@ interface UseHackathonsListReturn { refetch: () => void; } -export const useHackathonsList: ( - options: UseHackathonsListOptions -) => UseHackathonsListReturn = (options: UseHackathonsListOptions = {}) => { - const { initialPage = 1, pageSize = 10, initialFilters = {} } = options; +// ─── Client-side helpers (API doesn't support these dimensions) ────────────── - const [hackathons, setHackathons] = React.useState([]); - const [featuredHackathons, setFeaturedHackathons] = React.useState< - Hackathon[] - >([]); - const [loading, setLoading] = React.useState(true); - const [loadingMore, setLoadingMore] = React.useState(false); - const [error, setError] = React.useState(null); - const [currentPage, setCurrentPage] = React.useState(initialPage); - const [hasMore, setHasMore] = React.useState(true); - const [totalCount, setTotalCount] = React.useState(0); - const [filters, setFilters] = - React.useState(initialFilters); - - // Update filters when initialFilters change - React.useEffect(() => { - setFilters(initialFilters); - }, [initialFilters]); - - // Get hackathon deadline in milliseconds - const getHackathonDeadline = React.useCallback( - (hackathon: Hackathon): number => { - try { - if (hackathon?.submissionDeadline) { - return new Date(hackathon?.submissionDeadline).getTime(); - } - } catch { - // Handle error silently - } - return 0; - }, - [] - ); - - // Get prize pool total - const getPrizePoolTotal = React.useCallback( - (hackathon: Hackathon): number => { - if (hackathon?.prizeTiers && hackathon?.prizeTiers.length > 0) { - return hackathon?.prizeTiers.reduce((sum, tier) => { - const raw = tier.prizeAmount ?? (tier as { amount?: string }).amount; - const parsed = Number(raw); - return sum + (Number.isFinite(parsed) ? parsed : 0); - }, 0); - } - return 0; - }, - [] - ); - - // Sort hackathons for reverse sort options (client-side only) - const sortHackathons = React.useCallback( - (hackathonsList: Hackathon[], sortOption?: SortOption): Hackathon[] => { - if (!sortOption) return hackathonsList; - - const sorted = [...hackathonsList]; - - // Only handle reverse sort options that API doesn't support - switch (sortOption) { - case 'prize_pool_low': - return sorted.sort( - (a, b) => getPrizePoolTotal(a) - getPrizePoolTotal(b) - ); - case 'deadline_far': - return sorted.sort((a, b) => { - const aDeadline = getHackathonDeadline(a); - const bDeadline = getHackathonDeadline(b); - if (aDeadline === 0) return 1; - if (bDeadline === 0) return -1; - return bDeadline - aDeadline; - }); - default: - // Other sorts are handled by API - return sorted; - } - }, - [getHackathonDeadline, getPrizePoolTotal] - ); +function getHackathonDeadline(hackathon: Hackathon): number { + try { + if (hackathon?.submissionDeadline) { + return new Date(hackathon.submissionDeadline).getTime(); + } + } catch { + // ignore unparseable dates + } + return 0; +} - // Filter hackathons by location (client-side only, API doesn't support it) - const filterByLocation = React.useCallback( - (hackathonsList: Hackathon[], location?: string): Hackathon[] => { - if (!location) return hackathonsList; +function getPrizePoolTotal(hackathon: Hackathon): number { + if (hackathon?.prizeTiers && hackathon.prizeTiers.length > 0) { + return hackathon.prizeTiers.reduce((sum, tier) => { + const raw = tier.prizeAmount ?? (tier as { amount?: string }).amount; + const parsed = Number(raw); + return sum + (Number.isFinite(parsed) ? parsed : 0); + }, 0); + } + return 0; +} - let filtered = [...hackathonsList]; +/** Reverse-sort options the API can't do server-side (others are API-sorted). */ +function sortHackathons( + list: Hackathon[], + sortOption?: SortOption +): Hackathon[] { + if (!sortOption) return list; + const sorted = [...list]; + switch (sortOption) { + case 'prize_pool_low': + return sorted.sort((a, b) => getPrizePoolTotal(a) - getPrizePoolTotal(b)); + case 'deadline_far': + return sorted.sort((a, b) => { + const aDeadline = getHackathonDeadline(a); + const bDeadline = getHackathonDeadline(b); + if (aDeadline === 0) return 1; + if (bDeadline === 0) return -1; + return bDeadline - aDeadline; + }); + default: + return sorted; + } +} - if (location === 'virtual') { - filtered = filtered.filter(h => h.venueType === 'VIRTUAL'); - } else if (location === 'physical') { - filtered = filtered.filter(h => h.venueType === 'PHYSICAL'); - } else { - // Filter by country/city/state if provided - filtered = filtered.filter(h => { - const country = h.country?.toLowerCase(); - const city = h.city?.toLowerCase(); - const state = h.state?.toLowerCase(); - const searchLocation = location.toLowerCase(); +function filterByLocation(list: Hackathon[], location?: string): Hackathon[] { + if (!location) return list; + if (location === 'virtual') { + return list.filter(h => h.venueType === 'VIRTUAL'); + } + if (location === 'physical') { + return list.filter(h => h.venueType === 'PHYSICAL'); + } + const searchLocation = location.toLowerCase(); + return list.filter(h => { + const country = h.country?.toLowerCase(); + const city = h.city?.toLowerCase(); + const state = h.state?.toLowerCase(); + return ( + country?.includes(searchLocation) || + city?.includes(searchLocation) || + state?.includes(searchLocation) + ); + }); +} - return ( - country?.includes(searchLocation) || - city?.includes(searchLocation) || - state?.includes(searchLocation) - ); - }); - } +// ─── Hook ──────────────────────────────────────────────────────────────────── + +/** + * Public hackathons list, backed by React Query (`useInfiniteQuery`). + * + * The query key is **value-based** — built from the mapped API params, not the + * `initialFilters` object reference. That's the whole fix for the page firing + * `/hackathons?page=1&limit=10` multiple times: `useHackathonFilters` hands a + * fresh object every render, which used to churn local state + re-run a manual + * fetch effect. With a structural key, identical filter *values* resolve to one + * cached query, so the list loads once per unique filter set (deduped across any + * component that calls this hook). + * + * Location and reverse-sort are client-only dimensions; they are deliberately + * NOT in the key, so toggling them re-derives from the already-fetched pages + * instead of hitting the API again. + */ +export const useHackathonsList = ( + options: UseHackathonsListOptions = {} +): UseHackathonsListReturn => { + const { pageSize = 10, initialFilters = {} } = options; + + const apiParams = { + limit: pageSize, + status: mapStatusToAPI(initialFilters.status), + category: initialFilters.category, + search: initialFilters.search, + sort: mapSortToAPI(initialFilters.sort), + }; - return filtered; - }, - [] + const query = useInfiniteQuery({ + queryKey: ['hackathons', 'list', apiParams], + queryFn: ({ pageParam }) => + getPublicHackathonsList({ ...apiParams, page: pageParam }), + initialPageParam: 1, + getNextPageParam: (lastPage, allPages) => + lastPage.hasMore ? allPages.length + 1 : undefined, + placeholderData: keepPreviousData, + staleTime: 60_000, + }); + + const rawHackathons = React.useMemo( + () => (query.data?.pages ?? []).flatMap(page => page.hackathons ?? []), + [query.data] ); - // Fetch hackathons from public API - const fetchHackathons = React.useCallback( - async (page: number, currentFilters: HackathonFilters, append = false) => { - try { - if (append) { - setLoadingMore(true); - } else { - setLoading(true); - } - setError(null); - - // Map UI filters to API format - const apiStatus = mapStatusToAPI(currentFilters.status); - const apiSort = mapSortToAPI(currentFilters.sort); - - // Build API filters - const apiFilters = { - page, - limit: pageSize, - status: apiStatus, - category: currentFilters.category, - search: currentFilters.search, - sort: apiSort, - }; - - // Call public API - const response: PublicHackathonsListData = - await getPublicHackathonsList(apiFilters); - let hackathonsList = response.hackathons || []; - - // Apply client-side location filtering (API doesn't support it) - hackathonsList = filterByLocation( - hackathonsList, - currentFilters.location - ); - - // Apply client-side reverse sorting for options API doesn't support - if ( - currentFilters.sort === 'prize_pool_low' || - currentFilters.sort === 'deadline_far' - ) { - hackathonsList = sortHackathons( - hackathonsList, - currentFilters.sort as SortOption - ); - } - - // Separate featured hackathons (currently empty - no featured logic implemented) - setFeaturedHackathons([]); - - // Update state - setTotalCount(response.total || 0); - setHasMore(response.hasMore ?? false); - - if (append) { - setHackathons(prev => [...prev, ...hackathonsList]); - } else { - setHackathons(hackathonsList); - } - } catch (err) { - reportError(err, { - context: 'useHackathonsList-fetch', - page: String(page), - }); - const errorMessage = - err instanceof Error ? err.message : 'Failed to fetch hackathons'; - setError(errorMessage); - } finally { - setLoading(false); - setLoadingMore(false); - } - }, - [pageSize, filterByLocation, sortHackathons, mapStatusToAPI, mapSortToAPI] - ); + // Apply client-side location filter + reverse sort to the accumulated pages. + const hackathons = React.useMemo(() => { + let list = filterByLocation(rawHackathons, initialFilters.location); + if ( + initialFilters.sort === 'prize_pool_low' || + initialFilters.sort === 'deadline_far' + ) { + list = sortHackathons(list, initialFilters.sort as SortOption); + } + return list; + }, [rawHackathons, initialFilters.location, initialFilters.sort]); - // Fetch hackathons when filters change - React.useEffect(() => { - setCurrentPage(1); - setHasMore(true); - fetchHackathons(1, filters); - }, [filters, fetchHackathons]); + const pages = query.data?.pages ?? []; + const totalCount = + pages.length > 0 ? (pages[pages.length - 1].total ?? 0) : 0; const loadMore = React.useCallback(() => { - if (!loadingMore && hasMore) { - const nextPage = currentPage + 1; - setCurrentPage(nextPage); - fetchHackathons(nextPage, filters, true); + if (query.hasNextPage && !query.isFetchingNextPage) { + void query.fetchNextPage(); } - }, [loadingMore, hasMore, currentPage, filters, fetchHackathons]); + }, [query]); const refetch = React.useCallback(() => { - setCurrentPage(1); - fetchHackathons(1, filters); - }, [filters, fetchHackathons]); + void query.refetch(); + }, [query]); return { hackathons, - featuredHackathons, - loading, - loadingMore, - error, - hasMore, - currentPage, + featuredHackathons: [], + loading: query.isLoading, + loadingMore: query.isFetchingNextPage, + error: query.error instanceof Error ? query.error.message : null, + hasMore: query.hasNextPage, + currentPage: pages.length || 1, totalCount, loadMore, refetch, diff --git a/hooks/hackathon/use-register-hackathon.ts b/hooks/hackathon/use-register-hackathon.ts deleted file mode 100644 index 75ddc2264..000000000 --- a/hooks/hackathon/use-register-hackathon.ts +++ /dev/null @@ -1,130 +0,0 @@ -'use client'; - -import { useState, useCallback, useEffect } from 'react'; -import { registerForHackathon, type Participant } from '@/lib/api/hackathons'; -import { useAuthStatus } from '@/hooks/use-auth'; -import { toast } from 'sonner'; - -interface UseRegisterHackathonOptions { - hackathon?: { - id: string; - slug: string; - isParticipant: boolean; - } | null; - hackathonSlugOrId?: string; - organizationId?: string; - autoCheck?: boolean; // Kept for backward compatibility -} - -export function useRegisterHackathon({ - hackathon, - hackathonSlugOrId, - organizationId, - autoCheck = true, -}: UseRegisterHackathonOptions) { - const { isAuthenticated } = useAuthStatus(); - const [participant, setParticipant] = useState(null); - const [isRegistering, setIsRegistering] = useState(false); - const [isChecking, setIsChecking] = useState(false); - const [error, setError] = useState(null); - const [hasCheckedInitially, setHasCheckedInitially] = useState(false); - - // Get registration status: prefer hackathon.isParticipant, fallback to manual checking - const isRegistered = hackathon?.isParticipant ?? false; - const hackathonId = hackathon?.id || hackathonSlugOrId; - - const checkStatus = useCallback(async () => { - // Skip manual checking if we have hackathon.isParticipant - if (hackathon || !isAuthenticated || !hackathonId) { - if (!hackathon) { - setHasCheckedInitially(true); - } - return; - } - - setIsChecking(true); - setError(null); - - try { - // const response = await checkRegistrationStatus( - // hackathonId, - // organizationId - // ); - - // Note: This manual checking is now fallback only - // The preferred way is to use hackathon.isParticipant from the API response - setHasCheckedInitially(true); - } catch (err) { - const errorMessage = - err instanceof Error - ? err.message - : 'Failed to check registration status'; - setError(errorMessage); - setHasCheckedInitially(true); - } finally { - setIsChecking(false); - } - }, [hackathonId, organizationId, isAuthenticated, hackathon]); - - const register = useCallback(async () => { - if (!isAuthenticated) { - toast.error('Please sign in to register for hackathons'); - throw new Error('Authentication required'); - } - - if (!hackathon?.id) { - toast.error('Hackathon ID is required'); - throw new Error('Hackathon ID is required'); - } - - setIsRegistering(true); - setError(null); - - try { - const response = await registerForHackathon(hackathon.id, organizationId); - - if (response.success && response.data) { - // Update participant data after successful registration - setParticipant(response.data); - toast.success('Successfully registered for hackathon!'); - return response.data; - } else { - throw new Error(response.message || 'Registration failed'); - } - } catch (err) { - const errorMessage = - err instanceof Error ? err.message : 'Failed to register for hackathon'; - setError(errorMessage); - toast.error(errorMessage); - throw err; - } finally { - setIsRegistering(false); - } - }, [hackathon?.id, organizationId, isAuthenticated]); - - // Auto-check registration status on mount when we don't have hackathon.isParticipant - useEffect(() => { - if (!hackathon && autoCheck && isAuthenticated && hackathonId) { - checkStatus(); - } else if (!hackathon && !isAuthenticated) { - setHasCheckedInitially(true); - } - }, [autoCheck, isAuthenticated, hackathonId, checkStatus, hackathon]); - - return { - isRegistered, - participant, - isRegistering, - isChecking, - error, - register, - checkStatus, - hasCheckedInitially, - // Expose setters for immediate updates - setParticipant, - hasSubmitted: - participant?.submission?.status === 'SUBMITTED' || - participant?.submission?.status === 'SHORTLISTED' || - participant?.submission?.status === 'DISQUALIFIED', - }; -} diff --git a/hooks/hackathon/use-team-posts.ts b/hooks/hackathon/use-team-posts.ts index 615a5c214..c9b286b8e 100644 --- a/hooks/hackathon/use-team-posts.ts +++ b/hooks/hackathon/use-team-posts.ts @@ -5,7 +5,6 @@ import { AxiosError } from 'axios'; import { toast } from 'sonner'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useAuthStatus } from '@/hooks/use-auth'; -import { useAuthStore } from '@/lib/stores/auth-store'; import { getTeamPosts, createTeamPost, @@ -39,8 +38,7 @@ export function useTeamPosts({ organizationId, autoFetch = true, }: UseTeamPostsProps) { - const { isAuthenticated } = useAuthStatus(); - const { user } = useAuthStore(); + const { isAuthenticated, user } = useAuthStatus(); const currentUserId = user?.id; const queryClient = useQueryClient(); // After a team mutation, the React Query–backed pages (FindTeam, diff --git a/hooks/use-auth.ts b/hooks/use-auth.ts index 31edbd99d..b057d27c2 100644 --- a/hooks/use-auth.ts +++ b/hooks/use-auth.ts @@ -2,14 +2,17 @@ import { useRouter } from 'next/navigation'; import { useEffect, useMemo, useCallback } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { authClient } from '@/lib/auth-client'; -import { getMe } from '@/lib/api/auth'; +import { getMe, ME_QUERY_KEY } from '@/lib/api/auth'; import { GetMeResponse } from '@/lib/api/types'; -const AUTH_PROFILE_QUERY_KEY = ['auth', 'me'] as const; +// Shared with OrganizationProvider so a single `/users/me` query backs both the +// session profile and the org list. Stable (no userId suffix); logout clears it +// via removeQueries, so there's no cross-account cache leak. +const AUTH_PROFILE_QUERY_KEY = ME_QUERY_KEY; function useAuthProfileQuery(sessionUserId: string | null | undefined) { return useQuery({ - queryKey: [...AUTH_PROFILE_QUERY_KEY, sessionUserId ?? null], + queryKey: AUTH_PROFILE_QUERY_KEY, queryFn: getMe, enabled: !!sessionUserId, staleTime: 60 * 1000, diff --git a/hooks/use-follow.ts b/hooks/use-follow.ts index 4b5d629ee..4e2c3b338 100644 --- a/hooks/use-follow.ts +++ b/hooks/use-follow.ts @@ -1,4 +1,5 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useState, useCallback } from 'react'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { EntityType, UseFollowReturn } from '@/types/follow'; import { followApi } from '@/lib/api/follow'; import { useOptionalAuth } from './use-auth'; @@ -9,31 +10,30 @@ export const useFollow = ( initialIsFollowing = false ): UseFollowReturn => { const { user } = useOptionalAuth(); - const [isFollowing, setIsFollowing] = useState(initialIsFollowing); + const queryClient = useQueryClient(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); - const checkFollowStatus = useCallback(async () => { - try { + // Shared, cached follow-status query. Replaces a manual useEffect that re-ran + // whenever the `user` object identity changed (every auth refresh) and once + // per component using this hook — which rate-limited /follows/.../check (429). + // The stable string key dedupes across components and caches the result; the + // global QueryClient config doesn't retry 4xx. + const statusQuery = useQuery({ + queryKey: ['follow', entityType, entityId], + queryFn: async () => { const response = await followApi.checkFollowStatus(entityType, entityId); - // Backend returns { success: true, data: { isFollowing: true }, ... } - // api.get returns { data: { success: true, data: { isFollowing: true } }, ... } - // Backend returns { success: true, data: { isFollowing: true }, ... } - // api.get returns { data: { success: true, data: { isFollowing: true } }, ... } - const isFollowingStatus = - response.data?.data?.isFollowing ?? response.data?.isFollowing ?? false; - setIsFollowing(isFollowingStatus); - } catch { - // Silently fail for status check - don't set error state - } - }, [entityType, entityId]); + // Backend returns { success, data: { isFollowing } }; the axios layer + // wraps it once more, so both shapes are unwrapped here. + return ( + response.data?.data?.isFollowing ?? response.data?.isFollowing ?? false + ); + }, + enabled: !!user && !!entityId, + staleTime: 60_000, + }); - // Check follow status on mount if user is authenticated - useEffect(() => { - if (user && entityId) { - checkFollowStatus(); - } - }, [user, entityId, checkFollowStatus]); + const isFollowing = statusQuery.data ?? initialIsFollowing; const follow = useCallback(async () => { if (!user) { @@ -46,7 +46,7 @@ export const useFollow = ( try { await followApi.followEntity(entityType, entityId); - setIsFollowing(true); + queryClient.setQueryData(['follow', entityType, entityId], true); } catch (err: unknown) { const errorMessage = err instanceof Error ? err.message : 'Failed to follow'; @@ -55,7 +55,7 @@ export const useFollow = ( } finally { setIsLoading(false); } - }, [user, entityType, entityId]); + }, [user, entityType, entityId, queryClient]); const unfollow = useCallback(async () => { if (!user) { @@ -68,7 +68,7 @@ export const useFollow = ( try { await followApi.unfollowEntity(entityType, entityId); - setIsFollowing(false); + queryClient.setQueryData(['follow', entityType, entityId], false); } catch (err: unknown) { const errorMessage = err instanceof Error ? err.message : 'Failed to unfollow'; @@ -77,7 +77,7 @@ export const useFollow = ( } finally { setIsLoading(false); } - }, [user, entityType, entityId]); + }, [user, entityType, entityId, queryClient]); const toggleFollow = useCallback(async () => { if (isFollowing) { diff --git a/hooks/use-hackathon-draft.ts b/hooks/use-hackathon-draft.ts index 470654026..6187dc125 100644 --- a/hooks/use-hackathon-draft.ts +++ b/hooks/use-hackathon-draft.ts @@ -1,6 +1,5 @@ import { useState, useEffect, useRef } from 'react'; import { toast } from 'sonner'; -import { useHackathons } from '@/hooks/use-hackathons'; import { transformFromApiFormat } from '@/lib/utils/hackathon-form-transforms'; import type { InfoFormData } from '@/components/organization/hackathons/new/tabs/schemas/infoSchema'; import type { TimelineFormData } from '@/components/organization/hackathons/new/tabs/schemas/timelineSchema'; @@ -14,6 +13,13 @@ import { STEP_ORDER, } from '@/components/organization/hackathons/new/constants'; import { isStepDataValid } from '@/lib/utils/hackathon-step-validation'; +import { + DRAFT_SECTIONS, + useCreateDraft, + useDraft, + useUpdateDraft, + type UpdateHackathonDraftBody, +} from '@/features/hackathons'; interface StepData { information?: InfoFormData; @@ -31,6 +37,13 @@ interface UseHackathonDraftProps { onDraftLoaded?: (formData: StepData, firstIncompleteStep: StepKey) => void; } +/** + * Wizard draft orchestration on React Query. Loads an existing draft (resume + * flow) via `useDraft`, creates on first save via `useCreateDraft`, and persists + * sections through the single flat `useUpdateDraft` PATCH (one section for a + * per-step Continue, several for Save draft). Server state lives in the query + * cache; only the in-progress form snapshot is local. + */ export const useHackathonDraft = ({ organizationId, initialDraftId, @@ -38,140 +51,60 @@ export const useHackathonDraft = ({ }: UseHackathonDraftProps) => { const [draftId, setDraftId] = useState(initialDraftId || null); const [stepData, setStepData] = useState({}); - const [isLoadingDraft, setIsLoadingDraft] = useState(false); - const [isSavingDraft, setIsSavingDraft] = useState(false); - const draftInitializedRef = useRef(null); - - const { - initializeDraftAction, - updateDraftStepAction, - fetchDraft, - currentDraft, - currentLoading, - currentError, - } = useHackathons({ - organizationId, - autoFetch: false, - }); - useEffect(() => { - const loadDraft = async () => { - if (!initialDraftId || !organizationId) return; + // Fires onDraftLoaded once per resumed draft id. + const loadedRef = useRef(null); - setIsLoadingDraft(true); - try { - await fetchDraft(initialDraftId); - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : 'Failed to load draft'; - toast.error(errorMessage); - } finally { - setIsLoadingDraft(false); - } - }; - - loadDraft(); - }, [initialDraftId, organizationId, fetchDraft]); + const orgId = organizationId ?? ''; + // Only fetch for the resume flow (an initial draft id in the URL). Fresh + // drafts keep their form state locally until the first save. + const draftQuery = useDraft(orgId, initialDraftId); + const createDraft = useCreateDraft(orgId); + const updateDraft = useUpdateDraft(orgId); useEffect(() => { - if ( - currentDraft && - initialDraftId && - currentDraft.id === initialDraftId && - draftInitializedRef.current !== currentDraft.id - ) { - const formData = transformFromApiFormat(currentDraft); - setStepData(formData); - draftInitializedRef.current = currentDraft.id; - - const firstIncompleteStep = - STEP_ORDER.find(key => !isStepDataValid(key, formData)) ?? 'review'; - - if (onDraftLoaded) { - onDraftLoaded(formData, firstIncompleteStep); - } - } else if (currentDraft && currentDraft.id === initialDraftId) { - console.log('⏭️ Draft already initialized, skipping'); // Debug - } - }, [currentDraft?.id, initialDraftId, onDraftLoaded]); + const draft = draftQuery.data; + if (!draft || !initialDraftId || draft.id !== initialDraftId) return; + if (loadedRef.current === draft.id) return; + loadedRef.current = draft.id; + + const formData = transformFromApiFormat(draft); + setStepData(formData); + if (!draftId) setDraftId(draft.id); + + const firstIncompleteStep = + STEP_ORDER.find(key => !isStepDataValid(key, formData)) ?? 'review'; + onDraftLoaded?.(formData, firstIncompleteStep); + }, [draftQuery.data, initialDraftId, draftId, onDraftLoaded]); + + /** Resolve the draft id, creating an empty draft on first use. */ + const ensureDraftId = async (): Promise => { + if (draftId) return draftId; + const draft = await createDraft.mutateAsync(); + setDraftId(draft.id); + return draft.id; + }; const saveDraft = async () => { if (!organizationId) { toast.error('Organization ID is required'); return; } - - setIsSavingDraft(true); try { - if (draftId) { - // Save all current steps to the draft - if (stepData.information) { - await updateDraftStepAction( - draftId, - 'information', - stepData.information, - true - ); - } - if (stepData.timeline) { - await updateDraftStepAction( - draftId, - 'timeline', - stepData.timeline, - true - ); + const id = await ensureDraftId(); + const body = {} as UpdateHackathonDraftBody; + for (const section of DRAFT_SECTIONS) { + const value = stepData[section]; + if (value !== undefined) { + (body as Record)[section] = value; } - if (stepData.participation) { - await updateDraftStepAction( - draftId, - 'participation', - stepData.participation, - true - ); - } - if (stepData.rewards) { - await updateDraftStepAction( - draftId, - 'rewards', - stepData.rewards, - true - ); - } - if (stepData.resources) { - await updateDraftStepAction( - draftId, - 'resources', - stepData.resources, - true - ); - } - if (stepData.judging) { - await updateDraftStepAction( - draftId, - 'judging', - stepData.judging, - true - ); - } - if (stepData.collaboration) { - await updateDraftStepAction( - draftId, - 'collaboration', - stepData.collaboration, - true - ); - } - toast.success('Draft saved successfully'); - } else { - // Initialize new draft - const draft = await initializeDraftAction(organizationId); - setDraftId(draft.id); - toast.success('Draft created successfully'); } + if (Object.keys(body).length > 0) { + await updateDraft.mutateAsync({ id, body }); + } + toast.success('Draft saved successfully'); } catch { toast.error('Failed to save draft'); throw new Error('Failed to save draft'); - } finally { - setIsSavingDraft(false); } }; @@ -191,32 +124,29 @@ export const useHackathonDraft = ({ return; } - const updatedStepData = { ...stepData, [stepKey]: data }; - - if (draftId) { - // Update specific step using new API - await updateDraftStepAction(draftId, stepKey, data, true); - } else { - // Initialize draft if it doesn't exist - const draft = await initializeDraftAction(organizationId); - - setDraftId(draft.id); - // Then update the step - await updateDraftStepAction(draft.id, stepKey, data, true); - } + const id = await ensureDraftId(); + await updateDraft.mutateAsync({ + id, + body: { [stepKey]: data } as UpdateHackathonDraftBody, + }); + const updatedStepData = { ...stepData, [stepKey]: data }; setStepData(updatedStepData); return updatedStepData; }; return { draftId, + /** Server-side draft status ('DRAFT' | 'DRAFT_AWAITING_FUNDING'); undefined for an unsaved /new draft. */ + draftStatus: draftQuery.data?.status, stepData, setStepData, - isLoadingDraft: isLoadingDraft || (initialDraftId && currentLoading), + isLoadingDraft: Boolean(initialDraftId) && draftQuery.isLoading, currentError: - initialDraftId && currentError && !currentDraft ? currentError : null, - isSavingDraft, + initialDraftId && draftQuery.error + ? draftQuery.error.message || 'Failed to load draft' + : null, + isSavingDraft: createDraft.isPending || updateDraft.isPending, saveDraft, saveStep, }; diff --git a/hooks/use-hackathon-publish.ts b/hooks/use-hackathon-publish.ts index 1b4b3367e..d5609182a 100644 --- a/hooks/use-hackathon-publish.ts +++ b/hooks/use-hackathon-publish.ts @@ -1,9 +1,26 @@ -import { useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useRouter } from 'next/navigation'; import { toast } from 'sonner'; import { useWalletContext } from '@/components/providers/wallet-provider'; -import { getTotalPrizePoolForFunding } from '@/lib/utils/hackathon-escrow'; -import type { Hackathon } from '@/lib/api/hackathons'; +import { + buildWinnerDistribution, + calculateTotalPrizeAmount, + getTotalPrizePoolForFunding, +} from '@/lib/utils/hackathon-escrow'; +import { getTokenAddress } from '@/lib/config/tokens'; +import { + useEscrowOpRunner, + usePublishHackathonEscrow, +} from '@/features/hackathons'; +import { signXdrWithKit } from '@/lib/wallet/wallet-kit'; +import { getDraft, getHackathon } from '@/lib/api/hackathons'; +import { getHackathonEscrowOp } from '@/features/hackathons'; +import type { FundingMode } from '@/features/hackathons'; +import { + clearPublishOpId, + persistPublishOpId, + readPublishOpId, +} from '@/lib/utils/publish-op-storage'; import type { RewardsFormData } from '@/components/organization/hackathons/new/tabs/schemas/rewardsSchema'; import type { InfoFormData } from '@/components/organization/hackathons/new/tabs/schemas/infoSchema'; import type { TimelineFormData } from '@/components/organization/hackathons/new/tabs/schemas/timelineSchema'; @@ -24,11 +41,21 @@ interface UseHackathonPublishProps { organizationId: string; stepData: StepData; draftId?: string | null; - publishDraftAction: ( - draftId: string, - organizationId: string, - options?: { skipAnnouncement?: boolean; announcementSubject?: string } - ) => Promise; + /** Signing path. Defaults to MANAGED (custodial). */ + fundingMode?: FundingMode; + /** + * For EXTERNAL funding, the connected wallet that will fund + sign (from the + * Stellar Wallets Kit). This becomes the on-chain owner/source, NOT the + * platform-managed wallet. Ignored for MANAGED. + */ + externalOwnerAddress?: string | null; + /** + * For MANAGED funding from an organization treasury wallet: the treasury + * wallet to fund + sign with (backend signs custodially). When set, its + * address becomes the on-chain owner and we forward its id as sourceWalletId. + * Omit to fund from the caller's personal managed wallet. + */ + treasurySource?: { walletId: string; address: string } | null; } export interface PublishResponseData { @@ -36,31 +63,191 @@ export interface PublishResponseData { slug: string; publishedAt: string; message: string; + /** Kept for the published modal; empty in the events-contract flow. */ escrowAddress: string; transactionHash: string | null; } +/** + * Publishes a hackathon draft onto the boundless-events contract. + * + * Replaces the legacy TrustlessWork `publishDraft` call. The draft IS a + * Hackathon row in DRAFT status, so we hit the v2 escrow surface directly: + * + * 1. POST .../hackathons/:draftId/escrow/publish (CREATE_EVENT). MANAGED has + * the backend sign + submit; the op comes back PENDING_CONFIRM. + * 2. Poll the op to COMPLETED (the backend subscriber flips the hackathon + * DRAFT_AWAITING_FUNDING -> UPCOMING on settle). + * 3. Fetch the now-public hackathon for its slug, stash the published-modal + * payload, and navigate to the org hackathon page. + */ export const useHackathonPublish = ({ organizationId, stepData, draftId, - publishDraftAction, + fundingMode = 'MANAGED', + externalOwnerAddress, + treasurySource, }: UseHackathonPublishProps) => { const router = useRouter(); - const { walletAddress } = useWalletContext(); - const [isPublishing, setIsPublishing] = useState(false); + const { walletAddress, balances } = useWalletContext(); + const hackathonId = draftId || ''; + const isExternal = fundingMode === 'EXTERNAL'; + const usingTreasury = !isExternal && !!treasurySource; + + // The on-chain owner/source. EXTERNAL funds from the connected wallet; a + // treasury source funds from the org treasury wallet; otherwise the caller's + // personal platform-held custodial wallet. + const ownerAddress = isExternal + ? (externalOwnerAddress ?? null) + : usingTreasury + ? treasurySource!.address + : walletAddress; + + const publishMutation = usePublishHackathonEscrow( + organizationId, + hackathonId + ); + const runner = useEscrowOpRunner( + { kind: 'organizer', organizationId, hackathonId }, + // EXTERNAL: sign the returned XDR with the connected wallet (Wallet Kit). + // MANAGED needs no signer (the backend signs with the custodial wallet). + isExternal ? { signXdr: signXdrWithKit } : undefined + ); + + const [hasStarted, setHasStarted] = useState(false); const [publishResponse, setPublishResponse] = useState(null); + // Ensures the completion side-effect (fetch slug + navigate) runs once. + const finalizedRef = useRef(false); + + useEffect(() => { + if (!hasStarted || finalizedRef.current) return; + + if (runner.isCompleted) { + finalizedRef.current = true; + void (async () => { + // The op settled; the hackathon is now UPCOMING with a slug. Fetch it + // so the success view's "View hackathon" link can resolve the slug. + let slug = ''; + let publishedAt = new Date().toISOString(); + try { + const res = await getHackathon(hackathonId); + slug = res.data?.slug ?? ''; + publishedAt = res.data?.publishedAt ?? publishedAt; + } catch { + // Non-fatal: the View link falls back to the hackathon id. + } + + const responseData: PublishResponseData = { + id: hackathonId, + slug, + publishedAt, + message: 'Hackathon published successfully', + escrowAddress: '', + transactionHash: runner.txHash, + }; + setPublishResponse(responseData); + clearPublishOpId(hackathonId); + toast.success('Hackathon published!', { duration: 3000 }); + // Success renders in place via FundingProgressModal; the organizer + // navigates from there. No sessionStorage hand-off / full-page redirect. + setHasStarted(false); + })(); + } else if (runner.isFailed) { + finalizedRef.current = true; + // The backend sends the hackathon back to DRAFT on a failed CREATE_EVENT, + // so drop the stale op id; the next attempt starts a fresh publish. + clearPublishOpId(hackathonId); + toast.error(runner.error || 'Failed to publish hackathon'); + setHasStarted(false); + } + }, [ + hasStarted, + runner.isCompleted, + runner.isFailed, + runner.error, + runner.txHash, + hackathonId, + organizationId, + router, + ]); - const publish = async (publishOptions?: { - skipAnnouncement?: boolean; - announcementSubject?: string; - }): Promise => { + const publish = async ( + // Announce options are accepted for call-site compatibility; the events + // publish endpoint doesn't take them (announcements move to the UPCOMING + // transition on the backend). + _publishOptions?: { + skipAnnouncement?: boolean; + announcementSubject?: string; + } + ): Promise => { if (!organizationId) { toast.error('Organization ID is required'); return null; } + if (!draftId) { + toast.error('Draft ID is required'); + return null; + } + if (!ownerAddress) { + toast.error( + isExternal + ? 'Connect a wallet to fund externally.' + : 'Please connect your wallet first' + ); + return null; + } + + // Pre-flight: a prior publish may have already moved the hackathon out of + // DRAFT. The backend rejects re-publishing a DRAFT_AWAITING_FUNDING row, so + // resume the in-flight op (or report the terminal state) instead. + // + // Use the org-scoped draft GET, NOT the public getHackathon — the public + // endpoint 404s for non-live (DRAFT / DRAFT_AWAITING_FUNDING) hackathons, + // which would leave currentStatus undefined and fall through to a 400. + let currentStatus: string | undefined; + try { + const res = await getDraft(organizationId, hackathonId); + currentStatus = res.data?.status; + } catch { + // Non-fatal: fall through to the normal publish path. + } + + if ( + currentStatus === 'UPCOMING' || + currentStatus === 'ACTIVE' || + currentStatus === 'JUDGING' || + currentStatus === 'COMPLETED' + ) { + clearPublishOpId(hackathonId); + toast.success('This hackathon is already published.'); + router.push(`/organizations/${organizationId}/hackathons/${hackathonId}`); + return null; + } + if (currentStatus === 'DRAFT_AWAITING_FUNDING') { + // Funding is mid-flight. Resume polling the existing op rather than + // re-issuing publish (which 400s). + const storedOpRowId = readPublishOpId(hackathonId); + if (!storedOpRowId) { + toast.info( + 'This hackathon is already being funded on-chain. It will finish ' + + 'publishing shortly, or return to draft if the transaction fails — ' + + 'refresh in a moment to check.' + ); + return null; + } + finalizedRef.current = false; + setHasStarted(true); + toast.info('Resuming hackathon funding…'); + await runner.run(() => + getHackathonEscrowOp(organizationId, hackathonId, storedOpRowId) + ); + return null; + } + + // ---- Normal DRAFT publish path ---- if ( !stepData.information || !stepData.timeline || @@ -72,12 +259,10 @@ export const useHackathonPublish = ({ toast.error('Please complete all steps before publishing'); return null; } - - if (!walletAddress) { - toast.error('Please connect your wallet first'); + if (!stepData.timeline.submissionDeadline) { + toast.error('A submission deadline is required before publishing'); return null; } - if ( !stepData.rewards.prizeTiers || stepData.rewards.prizeTiers.length === 0 @@ -86,81 +271,88 @@ export const useHackathonPublish = ({ return null; } - const totalPrizeAmount = getTotalPrizePoolForFunding(stepData.rewards); - if (totalPrizeAmount === 0) { + const budget = calculateTotalPrizeAmount(stepData.rewards); + if (!(budget > 0)) { toast.error('Total prize amount must be greater than zero'); return null; } - if (!draftId) { - toast.error('Draft ID is required'); + // Pre-flight: create_event debits budget + platform fee from the owner's + // USDC. Catch an insufficient/missing balance here with a clear message + // instead of surfacing a raw contract host error from the chain. + const required = getTotalPrizePoolForFunding(stepData.rewards); + const usdcEntry = balances.find(b => b.asset_code === 'USDC'); + const usdcBalance = parseFloat(usdcEntry?.balance ?? '0'); + const fmtUsdc = (n: number) => + n.toLocaleString('en-US', { maximumFractionDigits: 2 }); + // Only block when balances have loaded; otherwise let the on-chain build be + // the gate (the backend surfaces a clear error either way). EXTERNAL and + // treasury sources fund from a different wallet than the caller's personal + // managed wallet, so its loaded balances don't apply. + if ( + !isExternal && + !usingTreasury && + balances.length > 0 && + usdcBalance < required + ) { + toast.error( + usdcEntry + ? `Insufficient USDC. Publishing locks ${fmtUsdc(required)} USDC ` + + `(${fmtUsdc(budget)} prizes + ${fmtUsdc(required - budget)} fee), ` + + `but your wallet has ${fmtUsdc(usdcBalance)} USDC.` + : `Your wallet has no USDC. Publishing locks ${fmtUsdc(required)} USDC ` + + `(${fmtUsdc(budget)} prizes + ${fmtUsdc(required - budget)} fee). ` + + `Add USDC (and a USDC trustline) before publishing.` + ); return null; } - setIsPublishing(true); - + let tokenAddress: string; try { - toast.info('Publishing hackathon...'); - // The backend now handles the custodial wallet and escrow logic - const response = await publishDraftAction( - draftId, - organizationId, - publishOptions + tokenAddress = getTokenAddress('USDC'); + } catch (err) { + toast.error( + err instanceof Error ? err.message : 'Prize token is not configured' ); + return null; + } - // Handle different response formats - // Could be: { success, message, data: {...} } or direct Hackathon object - let hackathon = response; - - if (!hackathon || !hackathon.id) { - throw new Error('Invalid publish response: missing hackathon ID'); - } - - // Prepare response data from hackathon object - const responseData: PublishResponseData = { - id: hackathon.id, - slug: hackathon.slug || '', - publishedAt: hackathon.publishedAt || new Date().toISOString(), - message: hackathon.message || 'Hackathon published successfully', - escrowAddress: hackathon.escrowAddress || '', - transactionHash: hackathon.transactionHash || null, - }; - - setPublishResponse(responseData); - - // Show success toast and navigate to hackathon page; store payload so the page can open the published modal - toast.success(`Hackathon published!`, { duration: 3000 }); - const payload = { organizationId, ...responseData }; - try { - sessionStorage.setItem( - 'boundless_hackathon_published', - JSON.stringify(payload) - ); - } catch { - // ignore - } - router.push( - `/organizations/${organizationId}/hackathons/${responseData.id}` - ); + const winnerDistribution = buildWinnerDistribution(stepData.rewards); - return responseData; - } catch (error) { - let errorMessage = 'Failed to publish hackathon'; + finalizedRef.current = false; + setHasStarted(true); + setPublishResponse(null); + toast.info('Publishing hackathon...'); - if (error instanceof Error) { - errorMessage = error.message; - } + const op = await runner.run(async () => { + const created = await publishMutation.mutateAsync({ + ownerAddress, + tokenAddress, + budget: String(budget), + winnerDistribution, + fundingMode, + sourceWalletId: usingTreasury ? treasurySource!.walletId : undefined, + }); + // Persist so a reload / retry can resume polling this op. + persistPublishOpId(hackathonId, created.id); + return created; + }); - toast.error(errorMessage); - throw error; - } finally { - setIsPublishing(false); + if (!op) { + // run() already surfaced the error via runner.error -> toast effect. + setHasStarted(false); } + return null; }; return { - isPublishing, + isPublishing: hasStarted && (publishMutation.isPending || runner.isRunning), publish, publishResponse, + /** Live escrow op state for richer publish UI. */ + escrowStatus: runner.status, + escrowPhase: runner.phase, + escrowError: runner.error, + escrowTxHash: runner.txHash, }; }; diff --git a/hooks/use-hackathon-rewards.ts b/hooks/use-hackathon-rewards.ts index ec4240cd0..a4b3aa5c5 100644 --- a/hooks/use-hackathon-rewards.ts +++ b/hooks/use-hackathon-rewards.ts @@ -1,12 +1,10 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import pLimit from 'p-limit'; // Import Hackathon types import { getJudgingSubmissions, getHackathon, - getHackathonEscrow, type Hackathon, - type HackathonEscrowData, type HackathonTrackWinner, } from '@/lib/api/hackathons'; import { getHackathonWinners } from '@/lib/api/hackathon'; @@ -67,14 +65,10 @@ const getDefaultPrizeTiers = (): PrizeTier[] => [ interface UseHackathonRewardsReturn { submissions: Submission[]; setSubmissions: React.Dispatch>; - escrow: HackathonEscrowData | null; prizeTiers: PrizeTier[]; - contractId: string | null; isLoading: boolean; - isLoadingEscrow: boolean; isLoadingSubmissions: boolean; error: string | null; - refreshEscrow: () => Promise; refetchHackathon: () => Promise; resultsPublished: boolean; hackathon: Hackathon | null; @@ -91,57 +85,13 @@ export const useHackathonRewards = ( hackathonId: string ): UseHackathonRewardsReturn => { const [submissions, setSubmissions] = useState([]); - const [escrow, setEscrow] = useState(null); const [prizeTiers, setPrizeTiers] = useState([]); - const [contractId, setContractId] = useState(null); const [isLoading, setIsLoading] = useState(true); - const [isLoadingEscrow, setIsLoadingEscrow] = useState(true); const [isLoadingSubmissions, setIsLoadingSubmissions] = useState(true); const [error, setError] = useState(null); const [hackathon, setHackathon] = useState(null); const [trackWinners, setTrackWinners] = useState([]); - const isFetchingEscrowRef = useRef(false); - const lastFetchedContractIdRef = useRef(null); - - const fetchEscrowData = useCallback( - async (contractIdToFetch: string) => { - if ( - isFetchingEscrowRef.current || - lastFetchedContractIdRef.current === contractIdToFetch - ) { - return; - } - - isFetchingEscrowRef.current = true; - lastFetchedContractIdRef.current = contractIdToFetch; - setIsLoadingEscrow(true); - - try { - const response = await getHackathonEscrow(organizationId, hackathonId); - - if (response.success && response.data) { - setEscrow(response.data); - } else { - setEscrow(null); - } - } catch { - setEscrow(null); - lastFetchedContractIdRef.current = null; - } finally { - setIsLoadingEscrow(false); - isFetchingEscrowRef.current = false; - } - }, - [organizationId, hackathonId] - ); - - const refreshEscrow = useCallback(async () => { - if (!contractId) return; - lastFetchedContractIdRef.current = null; - await fetchEscrowData(contractId); - }, [contractId, fetchEscrowData]); - const fetchHackathon = useCallback(async () => { try { const response = await getHackathon(hackathonId); @@ -217,12 +167,6 @@ export const useHackathonRewards = ( ); setPrizeTiers(tiers); } - - const hackathonContractId = - fetchedHackathon.contractId || fetchedHackathon.escrowAddress || null; - if (hackathonContractId) { - setContractId(hackathonContractId); - } } } catch { setPrizeTiers(getDefaultPrizeTiers()); @@ -235,19 +179,6 @@ export const useHackathonRewards = ( } }, [organizationId, hackathonId, fetchHackathon]); - useEffect(() => { - if (contractId) { - if (escrow && escrow.contractId === contractId) { - lastFetchedContractIdRef.current = contractId; - return; - } - fetchEscrowData(contractId); - } else { - setIsLoadingEscrow(false); - setEscrow(null); - } - }, [contractId, escrow, fetchEscrowData]); - useEffect(() => { const fetchSubmissions = async () => { setIsLoadingSubmissions(true); @@ -512,14 +443,10 @@ export const useHackathonRewards = ( return { submissions, setSubmissions, - escrow, prizeTiers, - contractId, isLoading, - isLoadingEscrow, isLoadingSubmissions, error, - refreshEscrow, refetchHackathon: fetchHackathon, resultsPublished: !!hackathon?.resultsPublished, hackathon, diff --git a/hooks/use-hackathon-steps.ts b/hooks/use-hackathon-steps.ts index d03b19285..e5c606e3c 100644 --- a/hooks/use-hackathon-steps.ts +++ b/hooks/use-hackathon-steps.ts @@ -1,4 +1,7 @@ -import { useState, useCallback } from 'react'; +'use client'; + +import { useCallback, useState } from 'react'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import type { StepKey, StepData, @@ -23,10 +26,25 @@ interface UseHackathonStepsReturn { ) => void; } +function isStepKey(value: string | null | undefined): value is StepKey { + return !!value && (STEP_ORDER as readonly string[]).includes(value); +} + +/** + * Wizard step state. The active step is URL-driven via the `?step=` query param, + * so refresh, browser back/forward, and bookmarking all resume the right step. + * The per-step status map (active/completed/pending) stays local UI state. + */ export const useHackathonSteps = ( initialActiveTab: StepKey = 'information' ): UseHackathonStepsReturn => { - const [activeTab, setActiveTab] = useState(initialActiveTab); + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + + const urlStep = searchParams.get('step'); + const activeTab: StepKey = isStepKey(urlStep) ? urlStep : initialActiveTab; + const [steps, setSteps] = useState>({ information: { status: 'active', isCompleted: false }, timeline: { status: 'pending', isCompleted: false }, @@ -38,9 +56,28 @@ export const useHackathonSteps = ( review: { status: 'pending', isCompleted: false }, }); - const getCurrentStepIndex = useCallback(() => { - return STEP_ORDER.indexOf(activeTab); - }, [activeTab]); + // Write the active step to the URL. `push` for explicit navigation (so the + // back button steps through), `replace` for programmatic syncs (auto-resume). + const writeStep = useCallback( + (stepKey: StepKey, mode: 'push' | 'replace' = 'push') => { + const params = new URLSearchParams(searchParams.toString()); + params.set('step', stepKey); + const url = `${pathname}?${params.toString()}`; + if (mode === 'replace') router.replace(url, { scroll: false }); + else router.push(url, { scroll: false }); + }, + [searchParams, pathname, router] + ); + + const setActiveTab = useCallback( + (tab: StepKey) => writeStep(tab, 'push'), + [writeStep] + ); + + const getCurrentStepIndex = useCallback( + () => STEP_ORDER.indexOf(activeTab), + [activeTab] + ); const canAccessStep = useCallback( (stepKey: StepKey) => { @@ -89,18 +126,23 @@ export const useHackathonSteps = ( })); } - setActiveTab(stepKey); + writeStep(stepKey, 'push'); } }, - [canAccessStep, getCurrentStepIndex] + [canAccessStep, getCurrentStepIndex, writeStep] ); const setStepsFromDraft = useCallback( (stepsState: Record, activeStep: StepKey) => { setSteps(stepsState); - setActiveTab(activeStep); + // Respect an explicit ?step= in the URL (a refresh / bookmark). Only fall + // back to the computed first-incomplete step when the URL has none, and + // do it as a replace so auto-resume doesn't add a history entry. + if (!isStepKey(searchParams.get('step'))) { + writeStep(activeStep, 'replace'); + } }, - [] + [searchParams, writeStep] ); const updateStepCompletion = useCallback( @@ -126,10 +168,10 @@ export const useHackathonSteps = ( }); if (nextStep) { - setActiveTab(nextStep); + writeStep(nextStep, 'push'); } }, - [] + [writeStep] ); return { diff --git a/hooks/use-hackathons.ts b/hooks/use-hackathons.ts index d40717871..f0759bd63 100644 --- a/hooks/use-hackathons.ts +++ b/hooks/use-hackathons.ts @@ -4,7 +4,7 @@ import { useState, useEffect, useCallback, useRef } from 'react'; import { initializeDraft, updateDraftStep, - publishDraft, + updateDraftSteps, getDraft, getDrafts, updateHackathon, @@ -78,11 +78,10 @@ export interface UseHackathonsReturn { data: any, autoSave?: boolean ) => Promise; - publishDraftAction: ( + updateDraftStepsAction: ( draftId: string, - organizationId: string, - options?: { skipAnnouncement?: boolean; announcementSubject?: string } - ) => Promise; + steps: { step: string; data: any }[] + ) => Promise; fetchDraft: (draftId: string) => Promise; fetchDrafts: (page?: number, limit?: number) => Promise; @@ -330,9 +329,29 @@ export function useHackathons( setCurrentHackathon(response.data); setCurrentDraft(null); } catch (error) { - const errorMessage = - error instanceof Error ? error.message : 'Failed to fetch hackathon'; - setCurrentError(errorMessage); + // The public hackathon GET 404s for non-live hackathons. Fall back to + // the org-scoped draft GET so a hackathon mid-publish + // (DRAFT_AWAITING_FUNDING) still renders on the management page, where + // the publish-status banner resumes it. + try { + const draftRes = await getDraft(organizationId, hackathonId); + const draft = draftRes.data; + const mapped = { + id: draft.id, + name: draft.data?.information?.name || 'Untitled Hackathon', + slug: draft.data?.information?.slug || '', + status: draft.status, + organizationId, + } as unknown as Hackathon; + setCurrentHackathon(mapped); + setCurrentDraft(draft); + } catch { + const errorMessage = + error instanceof Error + ? error.message + : 'Failed to fetch hackathon'; + setCurrentError(errorMessage); + } } finally { setCurrentLoading(false); isFetchingCurrentRef.current = false; @@ -445,46 +464,44 @@ export function useHackathons( [organizationId, currentDraft] ); - // Publish Draft (New API) - const publishDraftAction = useCallback( + // Update several draft steps in one transactional PATCH (New API) + const updateDraftStepsAction = useCallback( async ( draftId: string, - organizationId: string, - options?: { skipAnnouncement?: boolean; announcementSubject?: string } - ): Promise => { - setHackathonsLoading(true); - setHackathonsError(null); - - try { - const response = await publishDraft(draftId, organizationId, options); - - // Extract data from API response wrapper if it exists - const hackathon = response?.data || response; + steps: { step: string; data: any }[] + ): Promise => { + if (!organizationId) { + throw new Error('Organization ID is required'); + } - if (!hackathon || !hackathon.id) { - throw new Error('Invalid publish response: missing hackathon ID'); - } + setDraftsLoading(true); + setDraftsError(null); - setHackathons(prev => [hackathon, ...prev]); - setCurrentHackathon(hackathon); - // Optionally remove from drafts if it was a draft - if (currentDraft) { - setDrafts(prev => prev.filter(d => d.id !== currentDraft.id)); - setCurrentDraft(null); + try { + const response = await updateDraftSteps(organizationId, draftId, steps); + if (response.data) { + setDrafts(prev => + prev.map(draft => (draft.id === draftId ? response.data! : draft)) + ); + if (currentDraft?.id === draftId) { + setCurrentDraft(response.data); + } + return response.data; + } else { + throw new Error('No draft data received'); } - return hackathon; } catch (error) { const errorMessage = error instanceof Error ? error.message - : 'Failed to publish hackathon'; - setHackathonsError(errorMessage); + : 'Failed to update draft steps'; + setDraftsError(errorMessage); throw error; } finally { - setHackathonsLoading(false); + setDraftsLoading(false); } }, - [currentDraft] + [organizationId, currentDraft] ); // Update Hackathon @@ -651,7 +668,7 @@ export function useHackathons( // Actions - Drafts initializeDraftAction, updateDraftStepAction, - publishDraftAction, + updateDraftStepsAction, fetchDraft, fetchDrafts, diff --git a/hooks/use-publish-winners.ts b/hooks/use-publish-winners.ts index 953f9bef4..64bb3d793 100644 --- a/hooks/use-publish-winners.ts +++ b/hooks/use-publish-winners.ts @@ -1,57 +1,75 @@ -import { useState, useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { toast } from 'sonner'; -import { v4 as uuidv4 } from 'uuid'; -import { triggerRewardDistribution } from '@/lib/api/hackathons'; -import { validateStellarAddress } from '@/lib/utils/stellar-address-validation'; +import { useWalletContext } from '@/components/providers/wallet-provider'; import { validatePrizeTiers } from '@/lib/utils/prize-tier-validation'; -import { extractRankFromPosition } from '@/lib/utils/hackathon-escrow'; +import { useEscrowOpRunner, useSelectWinners } from '@/features/hackathons'; +import { signXdrWithKit } from '@/lib/wallet/wallet-kit'; +import type { + FundingMode, + HackathonWinnerSelection, +} from '@/features/hackathons'; import type { Submission } from '@/components/organization/hackathons/rewards/types'; import type { PrizeTier } from '@/components/organization/hackathons/new/tabs/schemas/rewardsSchema'; -import type { HackathonEscrowData } from '@/lib/api/hackathons'; interface UsePublishWinnersProps { winners: Submission[]; prizeTiers: PrizeTier[]; - escrow: HackathonEscrowData | null; organizationId: string; hackathonId: string; - announcement: string; + /** Retained for the wizard's announcement step; not sent to select_winners. */ + announcement?: string; + /** Signing path. Defaults to MANAGED (custodial). */ + fundingMode?: FundingMode; onSuccess?: () => void; } +/** + * Rewards hackathon winners via the events contract's `select_winners` op. + * + * Replaces the legacy `triggerRewardDistribution` admin-review flow. Builds a + * position-keyed selection list from the overall (rank-based) winners, signs + + * submits MANAGED, then polls the op to COMPLETED — at which point the backend + * has paid each winner and moved the hackathon to COMPLETED. + * + * Track-prize payouts are not part of the on-chain winner_distribution + * (which is overall-position based) and are handled separately. + */ export const usePublishWinners = ({ winners, prizeTiers, - escrow, organizationId, hackathonId, - announcement, + fundingMode = 'MANAGED', onSuccess, }: UsePublishWinnersProps) => { - const [isPublishing, setIsPublishing] = useState(false); + const { walletAddress } = useWalletContext(); + const selectMutation = useSelectWinners(organizationId, hackathonId); + const runner = useEscrowOpRunner( + { kind: 'organizer', organizationId, hackathonId }, + fundingMode === 'EXTERNAL' ? { signXdr: signXdrWithKit } : undefined + ); - // Keep the idempotency key consistent across retries even if the page reloads - const idempotencyKeyRef = useRef(null); + const [started, setStarted] = useState(false); + const onSuccessRef = useRef(onSuccess); + onSuccessRef.current = onSuccess; - if (!idempotencyKeyRef.current) { - if (typeof window !== 'undefined') { - const storageKey = `publish-idempotency-${hackathonId}`; - let key = sessionStorage.getItem(storageKey); - if (!key) { - key = uuidv4(); - sessionStorage.setItem(storageKey, key); - } - idempotencyKeyRef.current = key; - } else { - idempotencyKeyRef.current = uuidv4(); + useEffect(() => { + if (!started) return; + if (runner.isCompleted) { + setStarted(false); + toast.success('Winners rewarded! Payouts settled on-chain.'); + onSuccessRef.current?.(); + } else if (runner.isFailed) { + setStarted(false); + toast.error( + runner.error || 'Failed to reward winners. Please try again.' + ); } - } + }, [started, runner.isCompleted, runner.isFailed, runner.error]); const publishWinners = async () => { - setIsPublishing(true); - try { - // 1. Initial Local Validations + // 1. Prize tiers must cover the winning ranks. const tierValidation = validatePrizeTiers(winners, prizeTiers); if (!tierValidation.valid) { const ranksStr = tierValidation.missingRanks @@ -60,35 +78,58 @@ export const usePublishWinners = ({ `${r}${r === 1 ? 'st' : r === 2 ? 'nd' : r === 3 ? 'rd' : 'th'}` ) .join(', '); - throw new Error( `No prize tier found for rank${tierValidation.missingRanks.length > 1 ? 's' : ''} ${ranksStr}. ` + - `Please configure prize tiers in the Rewards tab before publishing winners.` + 'Please configure prize tiers in the Rewards tab before publishing winners.' ); } - if (!escrow?.isFunded) { - throw new Error('Escrow is not funded. Please fund the escrow first.'); + // 2. The organizer's browser wallet is only used for the EXTERNAL + // signing path. MANAGED select_winners is signed server-side by the + // event manager (the org treasury), so no connected wallet is needed. + if (fundingMode === 'EXTERNAL' && !walletAddress) { + throw new Error('Please connect your wallet to reward winners.'); } - // 2. Trigger Reward Distribution - await triggerRewardDistribution(organizationId, hackathonId, { - idempotencyKey: idempotencyKeyRef.current || uuidv4(), - organizerNote: announcement || undefined, - }); + // 3. Build position-keyed selections from the overall (rank-based) + // winners. The payout recipient is resolved server-side = the + // submitter's (team leader's) Boundless managed wallet, so we only + // send the winning submission id + its position — no anchored address + // or prior on-chain submission anchor is required. + const selections: HackathonWinnerSelection[] = []; + const seenPositions = new Set(); - toast.success( - 'Reward distribution successfully triggered! Pending admin review.' - ); - - // Cleanup idempotency key since distribution succeeded - if (typeof window !== 'undefined') { - sessionStorage.removeItem(`publish-idempotency-${hackathonId}`); + for (const w of winners) { + if (w.rank == null) continue; // track winners aren't on-chain positions + const submissionId = w.submissionId || w.id; + if (!submissionId) continue; + if (seenPositions.has(w.rank)) { + throw new Error( + `Two winners are assigned to position ${w.rank}. Each position can ` + + 'have only one winner.' + ); + } + seenPositions.add(w.rank); + selections.push({ submissionId, position: w.rank }); } - if (onSuccess) { - onSuccess(); + if (selections.length === 0) { + throw new Error('No eligible overall winners to reward.'); } + + // 4. Kick off the on-chain payout; completion is handled by the poller. + setStarted(true); + const op = await runner.run(() => + selectMutation.mutateAsync({ + // ownerAddress is a hint only — the backend resolves and signs with + // the on-chain event manager. Send it when a wallet is connected + // (required for EXTERNAL; harmless fallback for MANAGED). + ...(walletAddress ? { ownerAddress: walletAddress } : {}), + selections, + fundingMode, + }) + ); + if (!op) setStarted(false); // run() already surfaced the error return true; } catch (error) { const errorMessage = @@ -97,13 +138,19 @@ export const usePublishWinners = ({ : 'Failed to publish winners. Please try again.'; toast.error(errorMessage); throw error; - } finally { - setIsPublishing(false); } }; return { - isPublishing, + isPublishing: started && (selectMutation.isPending || runner.isRunning), publishWinners, + // Runner state, surfaced for the payout progress modal. + phase: runner.phase, + txHash: runner.txHash, + isCompleted: runner.isCompleted, + isFailed: runner.isFailed, + error: runner.error, + /** Clear the runner so the modal closes / a retry starts fresh. */ + reset: runner.reset, }; }; diff --git a/hooks/use-reward-distribution-status.ts b/hooks/use-reward-distribution-status.ts deleted file mode 100644 index 8bdd2f877..000000000 --- a/hooks/use-reward-distribution-status.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { useState, useEffect, useCallback } from 'react'; -import { - getRewardDistributionStatus, - type RewardDistributionStatusResponse, -} from '@/lib/api/hackathons'; - -interface UseRewardDistributionStatusReturn { - distributionStatus: RewardDistributionStatusResponse | null; - isLoading: boolean; - error: string | null; - refetch: () => Promise; -} - -export const useRewardDistributionStatus = ( - organizationId: string, - hackathonId: string -): UseRewardDistributionStatusReturn => { - const [distributionStatus, setDistributionStatus] = - useState(null); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - const fetchStatus = useCallback(async () => { - if (!organizationId || !hackathonId) { - setIsLoading(false); - setError(null); - return; - } - setIsLoading(true); - setError(null); - try { - const data = await getRewardDistributionStatus( - organizationId, - hackathonId - ); - setDistributionStatus(data); - } catch (err: any) { - // 404 means "no active distribution" – treat as NOT_TRIGGERED silently - if (err?.response?.status === 404 || err?.status === 404) { - setDistributionStatus({ - distributionId: null, - status: 'NOT_TRIGGERED', - snapshot: { - idempotencyKey: '', - winners: [], - totalPrizePool: 0, - platformFee: 0, - totalRequired: 0, - currency: 'USDC', - escrowAddress: '', - winnersChecksum: '', - snapshotAt: '', - organizerNote: null, - }, - triggeredAt: '', - adminDecisionAt: null, - adminNote: null, - adminUserId: null, - rejectionReason: null, - updatedAt: '', - }); - } else { - setError( - err instanceof Error - ? err.message - : 'Failed to fetch distribution status' - ); - } - } finally { - setIsLoading(false); - } - }, [organizationId, hackathonId]); - - useEffect(() => { - fetchStatus(); - }, [fetchStatus]); - - return { distributionStatus, isLoading, error, refetch: fetchStatus }; -}; diff --git a/hooks/use-wizard-steps.ts b/hooks/use-wizard-steps.ts index 63729b5e0..cc41cf1fc 100644 --- a/hooks/use-wizard-steps.ts +++ b/hooks/use-wizard-steps.ts @@ -1,5 +1,4 @@ -import { useState, useEffect, useMemo, useRef } from 'react'; -import type { HackathonEscrowData } from '@/lib/api/hackathons'; +import { useState, useEffect, useRef } from 'react'; export type WizardStep = 'announcement' | 'preview'; @@ -18,10 +17,9 @@ const STEPS: Array<{ id: WizardStep; name: string; description: string }> = [ interface UseWizardStepsProps { open: boolean; - escrow: HackathonEscrowData | null; } -export const useWizardSteps = ({ open, escrow }: UseWizardStepsProps) => { +export const useWizardSteps = ({ open }: UseWizardStepsProps) => { const [currentStep, setCurrentStep] = useState('announcement'); const initializedRef = useRef(false); diff --git a/instrumentation-client.ts b/instrumentation-client.ts deleted file mode 100644 index 8861ee532..000000000 --- a/instrumentation-client.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as Sentry from '@sentry/nextjs'; - -const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN; - -if (dsn) { - Sentry.init({ - dsn, - sendDefaultPii: false, - tracesSampleRate: process.env.NODE_ENV === 'development' ? 1.0 : 0.1, - replaysSessionSampleRate: 0.1, - replaysOnErrorSampleRate: 1.0, - integrations: [ - Sentry.replayIntegration({ - maskAllText: true, - blockAllMedia: true, - }), - ], - environment: process.env.NODE_ENV, - }); -} - -export const onRouterTransitionStart = - typeof Sentry.captureRouterTransitionStart === 'function' - ? Sentry.captureRouterTransitionStart - : () => {}; diff --git a/instrumentation.ts b/instrumentation.ts deleted file mode 100644 index 964f937c4..000000000 --- a/instrumentation.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as Sentry from '@sentry/nextjs'; - -export async function register() { - if (process.env.NEXT_RUNTIME === 'nodejs') { - await import('./sentry.server.config'); - } - - if (process.env.NEXT_RUNTIME === 'edge') { - await import('./sentry.edge.config'); - } -} - -export const onRequestError = Sentry.captureRequestError; diff --git a/lib/api/auth.ts b/lib/api/auth.ts index bc67adc1b..abe488494 100644 --- a/lib/api/auth.ts +++ b/lib/api/auth.ts @@ -12,9 +12,30 @@ import { GetMeResponse } from '@/lib/api/types'; * For client-side usage, cookies are automatically sent via withCredentials * For server-side usage, use getMeServer() from '@/lib/api/auth-server' instead */ +/** + * Canonical React Query key for the current user (`/users/me`). Shared by the + * auth-profile hook (use-auth) and OrganizationProvider so a single getMe serves + * both the session profile and the org list, instead of two cache entries each + * hitting the same endpoint. + */ +export const ME_QUERY_KEY = ['users', 'me'] as const; + +let inFlightGetMe: Promise | null = null; export const getMe = async (): Promise => { - const res = await api.get>('/users/me'); - return res.data.data as GetMeResponse; + // Single-flight: concurrent callers (e.g. the auth store and OrganizationProvider + // both initializing on a page load) share one in-flight `/users/me` request + // instead of each firing their own. Cleared once it settles, so later + // (sequential) calls still fetch fresh. + if (inFlightGetMe) return inFlightGetMe; + inFlightGetMe = (async () => { + const res = await api.get>('/users/me'); + return res.data.data as GetMeResponse; + })(); + try { + return await inFlightGetMe; + } finally { + inFlightGetMe = null; + } }; /** diff --git a/lib/api/client.ts b/lib/api/client.ts new file mode 100644 index 000000000..06409f048 --- /dev/null +++ b/lib/api/client.ts @@ -0,0 +1,166 @@ +import createClient, { type Middleware } from 'openapi-fetch'; + +import type { ApiFieldError, ApiMeta, paths } from './openapi'; + +/** + * Single typed API client (modeled on boundless-platform's `@/lib/api`). New and + * migrated code calls the backend through `apiClient` + `unwrapData`; the + * response-envelope unwrap and error normalization live here so feature hooks + * stay one line. The legacy axios client (`lib/api/api.ts`) stays for code that + * hasn't migrated yet. + * + * The backend wraps every REST response in `{ success, message, data, meta }` + * while the generated types describe the inner `data`. The middleware unwraps + * the envelope before openapi-fetch parses the body; `meta` (pagination, + * requestId) is stashed per-response and read back with `getResponseMeta`. + * + * Base URL: v1's auth (better-auth) + axios are cross-origin against the backend + * (the session cookie lives on the backend domain), so this client targets the + * same absolute backend origin with `credentials: 'include'`. A same-origin Next + * rewrite would drop that cookie; adopting it requires migrating auth same-origin + * first (a later step). + */ +const backendOrigin = ( + process.env.NEXT_PUBLIC_API_URL || 'https://staging-api.boundlessfi.xyz' +) + .replace(/\/$/, '') + .replace(/\/api$/i, ''); + +const metaStore = new WeakMap(); + +interface SuccessEnvelope { + success: true; + message?: string; + data?: unknown; + meta?: ApiMeta; +} + +interface ErrorEnvelope { + success: false; + message?: string; + errors?: ApiFieldError[]; + meta?: ApiMeta; +} + +function isEnvelope(value: unknown): value is SuccessEnvelope | ErrorEnvelope { + return ( + typeof value === 'object' && + value !== null && + 'success' in value && + typeof (value as { success: unknown }).success === 'boolean' + ); +} + +function rebuild(payload: unknown, source: Response, meta?: ApiMeta): Response { + const headers = new Headers(source.headers); + // Body size changes after unwrapping, so let the runtime recompute it. + headers.delete('content-length'); + headers.set('content-type', 'application/json'); + + const next = new Response(JSON.stringify(payload ?? null), { + status: source.status, + statusText: source.statusText, + headers, + }); + + if (meta) { + metaStore.set(next, meta); + } + + return next; +} + +const envelopeMiddleware: Middleware = { + async onResponse({ response }) { + if (!response.headers.get('content-type')?.includes('application/json')) { + return undefined; + } + + const body = await response + .clone() + .json() + .catch(() => undefined); + + if (!isEnvelope(body)) { + return undefined; + } + + if (body.success) { + return rebuild(body.data ?? null, response, body.meta); + } + + return rebuild( + { message: body.message ?? 'Request failed', errors: body.errors ?? [] }, + response, + body.meta + ); + }, +}; + +export const apiClient = createClient({ + baseUrl: backendOrigin, + credentials: 'include', +}); + +apiClient.use(envelopeMiddleware); + +/** Read the `meta` block (pagination, requestId) for a completed response. */ +export function getResponseMeta(response: Response): ApiMeta | undefined { + return metaStore.get(response); +} + +/** Normalized error thrown by feature hooks when a request fails. */ +export class ApiError extends Error { + readonly status: number; + readonly fieldErrors: ApiFieldError[]; + readonly requestId?: string; + + constructor( + message: string, + status: number, + fieldErrors: ApiFieldError[] = [], + requestId?: string + ) { + super(message); + this.name = 'ApiError'; + this.status = status; + this.fieldErrors = fieldErrors; + this.requestId = requestId; + } +} + +/** Build an `ApiError` from a normalized openapi-fetch error and its response. */ +export function toApiError(error: unknown, response: Response): ApiError { + const meta = getResponseMeta(response); + + if (error && typeof error === 'object') { + const body = error as { message?: string; errors?: ApiFieldError[] }; + return new ApiError( + body.message ?? 'Request failed', + response.status, + body.errors ?? [], + meta?.requestId + ); + } + + return new ApiError('Request failed', response.status, [], meta?.requestId); +} + +interface ApiResult { + data?: T; + error?: unknown; + response: Response; +} + +/** + * Unwrap an openapi-fetch result: return the typed `data`, or throw an + * `ApiError` built from the normalized error envelope. Use inside query and + * mutation functions so feature hooks stay a single line. + */ +export function unwrapData(result: ApiResult): T { + if (result.error) { + throw toApiError(result.error, result.response); + } + + return result.data as T; +} diff --git a/lib/api/generated/schema.d.ts b/lib/api/generated/schema.d.ts new file mode 100644 index 000000000..a3d9c4760 --- /dev/null +++ b/lib/api/generated/schema.d.ts @@ -0,0 +1,36197 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + '/api': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['AppController_getHello']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['NotificationsController_getNotifications']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications/unread-count': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['NotificationsController_getUnreadCount']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications/{id}/read': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put: operations['NotificationsController_markAsRead']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications/read-all': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put: operations['NotificationsController_markAllAsRead']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete: operations['NotificationsController_deleteNotification']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications/preferences': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['NotificationsController_getPreferences']; + put: operations['NotificationsController_updatePreferences']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications/test': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['NotificationsController_sendTestNotification']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/notifications/test-marketing-cron': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['NotificationsController_triggerMarketingCron']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/settings': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get user settings */ + get: operations['SettingsController_getSettings']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/settings/notifications': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update notification settings */ + put: operations['SettingsController_updateNotificationSettings']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/settings/privacy': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update privacy settings */ + put: operations['SettingsController_updatePrivacySettings']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/settings/appearance': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update appearance settings */ + put: operations['SettingsController_updateAppearanceSettings']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/earnings/public': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get public earnings for a user (profile page) + * @description Returns visibility-filtered earnings for the given username: total earned, breakdown by source, and completed activities only. No pending/claimable amounts or entityIds. + */ + get: operations['EarningsController_getEarningsPublic']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/earnings': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get current user earnings + * @description Returns summary (total earned, pending/completed withdrawal), breakdown by source (hackathons, grants, crowdfunding, bounties), and activity feed. + */ + get: operations['EarningsController_getEarnings']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/earnings/withdraw': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Request withdrawal / claim + * @description Submit a withdrawal. Payout always goes to the user's linked wallet. Claiming (release flow) is for crowdfunding and grants; for crowdfunding, response may include pendingReleases to sign and submit via confirm-release. Hackathon winners do not claim here—admin releases and funds go to their wallet. + */ + post: operations['EarningsController_withdraw']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/earnings/withdraw/confirm-release': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit signed release transaction (crowdfunding) + * @description After withdraw returns pendingReleases, creator signs the unsigned XDR with their wallet and submits here. On success, the milestone is marked released. + */ + post: operations['EarningsController_confirmRelease']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/me': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get current user dashboard with overview, chart, and activities graph */ + get: operations['UserController_getProfile']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/public': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Public test endpoint */ + get: operations['UserController_getPublic']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/optional': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Optional authentication test endpoint */ + get: operations['UserController_getOptional']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/{username}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user profile by username + * @description Get a user profile by their username. Accessible to anyone without authentication. + */ + get: operations['UserController_getUserByUsername']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/{username}/followers': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user followers + * @description Get a list of users who follow this profile + */ + get: operations['UserController_getUserFollowers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/{username}/following': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get users followed by this profile + * @description Get a list of entities (users, projects, organizations) followed by this user + */ + get: operations['UserController_getUserFollowing']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/profile': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get current user profile */ + get: operations['ProfileController_getProfile']; + /** Update current user profile */ + put: operations['ProfileController_updateProfile']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/profile/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get user profile statistics */ + get: operations['ProfileController_getProfileStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/profile/activity': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get user activity */ + get: operations['ProfileController_getActivity']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/profile/avatar': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Upload user avatar */ + post: operations['ProfileController_uploadAvatar']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/preferences': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get user preferences */ + get: operations['PreferencesController_getPreferences']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/preferences/language': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update language preference */ + put: operations['PreferencesController_updateLanguage']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/preferences/timezone': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update timezone preference */ + put: operations['PreferencesController_updateTimezone']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/preferences/categories': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update category preferences */ + put: operations['PreferencesController_updateCategoryPreferences']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/preferences/skills': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update skill preferences */ + put: operations['PreferencesController_updateSkillPreferences']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get paginated list of users (Admin only) */ + get: operations['UsersController_getUsers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get user by ID */ + get: operations['UsersController_getUser']; + /** Update user by ID */ + put: operations['UsersController_updateUser']; + post?: never; + /** Delete user by ID (Admin only) */ + delete: operations['UsersController_deleteUser']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/users/{id}/profile': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get user profile by ID */ + get: operations['UsersController_getUserProfile']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/single': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Upload a single file + * @description Upload a single file to Cloudinary with optional transformations and metadata + */ + post: operations['UploadController_uploadSingle']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/multiple': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Upload multiple files + * @description Upload multiple files to Cloudinary with optional folder and tags + */ + post: operations['UploadController_uploadMultiple']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/{publicId}/{resourceType}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete a file + * @description Delete a file from Cloudinary storage + */ + delete: operations['UploadController_deleteFile']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/info/{publicId}/{resourceType}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get file information + * @description Get detailed information about a file from Cloudinary + */ + get: operations['UploadController_getFileInfo']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/search': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Search files + * @description Search files in Cloudinary with optional filters + */ + get: operations['UploadController_searchFiles']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/optimize/{publicId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Generate optimized URL + * @description Generate an optimized URL with transformations for a file + */ + get: operations['UploadController_generateOptimizedUrl']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/responsive/{publicId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Generate responsive URLs + * @description Generate multiple URLs with different sizes for responsive images + */ + get: operations['UploadController_generateResponsiveUrls']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/avatar/{publicId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Generate avatar URL + * @description Generate a square cropped avatar URL with automatic optimizations + */ + get: operations['UploadController_generateAvatarUrl']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/logo/{publicId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Generate logo URL + * @description Generate a logo URL with fit cropping and automatic optimizations + */ + get: operations['UploadController_generateLogoUrl']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/banner/{publicId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Generate banner URL + * @description Generate a banner URL with fill cropping and automatic optimizations + */ + get: operations['UploadController_generateBannerUrl']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/upload/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get usage statistics + * @description Get Cloudinary usage statistics for the account + */ + get: operations['UploadController_getUsageStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/register': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AuthController_register']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/login': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AuthController_login']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/refresh': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AuthController_refreshToken']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/logout': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AuthController_logout']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/me': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['AuthController_getProfile']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/verify-stellar-signature': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AuthController_verifyStellarSignature']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/oauth/google': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OAuthController_googleAuth']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/oauth/google/callback': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OAuthController_googleAuthCallback']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/oauth/github': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OAuthController_githubAuth']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/oauth/github/callback': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OAuthController_githubAuthCallback']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/oauth/twitter': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OAuthController_twitterAuth']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/oauth/twitter/callback': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OAuthController_twitterAuthCallback']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/follows/{entityType}/{entityId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['FollowsController_followEntity']; + delete: operations['FollowsController_unfollowEntity']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/follows/user/{userId}/following': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['FollowsController_getUserFollowing']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/follows/entity/{entityType}/{entityId}/followers': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['FollowsController_getEntityFollowers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/follows/user/{userId}/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['FollowsController_getFollowStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/follows/{entityType}/{entityId}/check': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['FollowsController_isFollowing']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/chat/history': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get chat message history */ + get: operations['ChatController_getMessages']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/messages/conversations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List my conversations */ + get: operations['MessagesController_listConversations']; + put?: never; + /** Start or get existing conversation */ + post: operations['MessagesController_startOrGetConversation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/messages/conversations/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get one conversation (thread header) */ + get: operations['MessagesController_getConversation']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/messages/conversations/{id}/messages': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List messages in a conversation */ + get: operations['MessagesController_listMessages']; + put?: never; + /** Send a message */ + post: operations['MessagesController_sendMessage']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/messages/conversations/{id}/read': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Mark conversation as read */ + patch: operations['MessagesController_markConversationRead']; + trace?: never; + }; + '/api/crowdfunding/validate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Validate campaign data + * @description Validate campaign data before creation. returns 200 if valid, 400 if invalid. + */ + post: operations['CampaignsController_validateCampaign']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List crowdfunding campaigns + * @description Get a paginated list of crowdfunding campaigns with optional filtering + */ + get: operations['CampaignsController_getCampaigns']; + put?: never; + /** + * Create a crowdfunding campaign + * @description Create a new crowdfunding campaign. This will also create the associated project automatically. + */ + post: operations['CampaignsController_createCampaign']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/trigger-cron': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Trigger campaign transition cron + * @description Manually trigger the campaign transition cron job for testing purposes. + */ + get: operations['CampaignsController_triggerCron']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/me': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List authenticated user's campaigns + * @description Get a paginated list of crowdfunding campaigns created by the authenticated user + */ + get: operations['CampaignsController_getMyCampaigns']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/s/{slug}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign by slug + * @description Get detailed information about a specific crowdfunding campaign by its URL slug + */ + get: operations['CampaignsController_getCampaignBySlug']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign details + * @description Get detailed information about a specific crowdfunding campaign + */ + get: operations['CampaignsController_getCampaign']; + /** + * Update campaign + * @description Update a crowdfunding campaign. Only campaign owners can update campaigns. + */ + put: operations['CampaignsController_updateCampaign']; + post?: never; + /** + * Delete campaign + * @description Delete a crowdfunding campaign. Only campaign owners can delete campaigns that are in draft/reviewing phase and have no contributions. + */ + delete: operations['CampaignsController_deleteCampaign']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/statistics': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign statistics + * @description Get funding statistics and progress for a campaign + */ + get: operations['CampaignsController_getCampaignStatistics']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/escrow': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Update escrow details + * @description Update escrow details including transaction hash, address, and status. Only campaign owners can update escrow details. + */ + put: operations['CampaignsController_updateEscrowDetails']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get all invitations for a campaign */ + get: operations['CampaignsController_getInvitations']; + put?: never; + /** Invite a team member to the campaign */ + post: operations['CampaignsController_inviteTeamMember']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/invitations/accept': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Accept a campaign team invitation */ + post: operations['CampaignsController_acceptInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/contribute': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Contribute to campaign + * @description Make a contribution to a crowdfunding campaign + */ + post: operations['ContributionsController_contributeToCampaign']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/contributions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign contributions + * @description Get paginated list of contributions for a campaign + */ + get: operations['ContributionsController_getCampaignContributions']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/contributions/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get contribution statistics + * @description Get contribution statistics and analytics for a campaign + */ + get: operations['ContributionsController_getContributionStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/milestones': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign milestones + * @description Get all milestones for a crowdfunding campaign + */ + get: operations['MilestonesController_getCampaignMilestones']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/milestones/{milestoneId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get milestone details + * @description Get detailed information about a specific milestone + */ + get: operations['MilestonesController_getMilestone']; + /** + * Submit milestone for review + * @description Submit milestone with proof of work for review. Creators: Provide proof of work files/links and optional notes. Data will be strictly validated. Milestone will be marked as SUBMITTED status for admin review. + */ + put: operations['MilestonesController_updateMilestone']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/milestones/{milestoneId}/validate-submission': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Validate milestone submission data + * @description Strictly validate milestone submission data (proof of work files/links) for creator submissions without performing any side effects. Creators submit milestones for review with proof of work. Admin reviews and approves later. Returns validated data if successful, or detailed error messages if validation fails. Use this before blockchain interaction to ensure data integrity. + */ + post: operations['MilestonesController_validateMilestoneSubmission']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/{id}/milestones/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get milestone statistics + * @description Get milestone completion statistics for a campaign + */ + get: operations['MilestonesController_getMilestoneStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/submit-for-review': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Submit a DRAFT campaign to admin review */ + post: operations['BuilderCrowdfundingV2Controller_submitForReview']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/withdraw-submission': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Withdraw a pending review back to DRAFT (D4) */ + post: operations['BuilderCrowdfundingV2Controller_withdrawSubmission']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/revise-and-resubmit': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Resubmit a REVIEW_REJECTED campaign (D5: unlimited retries) */ + post: operations['BuilderCrowdfundingV2Controller_reviseAndResubmit']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/escrow/publish': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Publish a VOTE_PASSED campaign to the events contract */ + post: operations['BuilderCrowdfundingV2Controller_publish']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/escrow/cancel': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Cancel a campaign and refund backers */ + post: operations['BuilderCrowdfundingV2Controller_cancel']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/escrow/claim-milestone': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Claim a milestone payout (reviewStatus must be APPROVED) */ + post: operations['BuilderCrowdfundingV2Controller_claimMilestone']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/escrow/contribute': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Build (and optionally submit) an add_funds op against the campaign */ + post: operations['BackerCrowdfundingV2Controller_contribute']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/vote': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Read the campaign vote tally */ + get: operations['CommunityCrowdfundingV2Controller_getTally']; + put?: never; + /** Cast or change vote on a VOTING campaign */ + post: operations['CommunityCrowdfundingV2Controller_castVote']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/vote/me': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Read the caller's current vote (or null) */ + get: operations['CommunityCrowdfundingV2Controller_getMyVote']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/admin/approve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a submitted campaign; assigns reviewer */ + post: operations['AdminCrowdfundingV2Controller_approve']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/admin/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject a submitted campaign with optional reason */ + post: operations['AdminCrowdfundingV2Controller_reject']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/admin/pause': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Pause a live campaign (D7) */ + post: operations['AdminCrowdfundingV2Controller_pause']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/crowdfunding/campaigns/{id}/v2/admin/unpause': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Unpause a campaign and restore previous status */ + post: operations['AdminCrowdfundingV2Controller_unpause']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get current user wallet */ + get: operations['WalletController_getWallet']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/details': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get wallet details including balances and transactions */ + get: operations['WalletController_getWalletDetails']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/balance/{address}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get USDC + XLM balance for any Stellar address + * @description Public on-chain balances for an arbitrary G-address. Used by funding flows to pre-check the selected wallet before submitting on-chain. + */ + get: operations['WalletController_getAddressBalance']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/sync': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Sync wallet with blockchain */ + post: operations['WalletController_syncWallet']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/create': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Create a new wallet for the current user */ + post: operations['WalletController_createWallet']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/activate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Activate wallet on Stellar with sponsored reserves + * @description Creates the on-chain account and configured trustlines (default: USDC) in a single sponsored transaction. The platform sponsor account pays all XLM reserves and the network fee. Idempotent: safe to retry if a prior call failed. + */ + post: operations['WalletController_activate']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/admin/reclaim-dormant': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Admin: reclaim sponsor XLM from dormant zero-balance wallets + * @description Finds wallets that have been idle for the given window with zero on-chain balances, and merges each one back into the sponsor account. Frees ~1 XLM per account and ~0.5 XLM per trustline. Defaults to dryRun=true; set dryRun=false to actually submit. The wallet row is preserved (isActivated reset to false), so a returning user can re-activate at the same address. + */ + post: operations['WalletController_reclaimDormant']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/trustline/supported': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List assets that can have a trustline added (e.g. USDC, EURC) */ + get: operations['WalletController_getSupportedTrustlines']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/trustline': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Add a trustline for a supported asset (e.g. USDC) */ + post: operations['WalletController_addTrustline']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/send/validate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Validate destination address before sending + * @description Returns whether the destination is a valid Stellar address, activated on the network, has a trustline for the given asset (for non-XLM), and whether the address requires a memo (e.g. exchange shared deposit address). + */ + get: operations['WalletController_validateSendDestination']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/send': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Send funds from your wallet to a Stellar address + * @description Sends funds from your Boundless wallet to a destination. Requires identity verification (KYC). Validates: your wallet is activated, destination is activated, destination has trustline for the asset (if not XLM), optional memo. Requires sufficient balance and XLM for network fee when sending non-XLM. + */ + post: operations['WalletController_send']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/wallet/payout': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Send payout from platform (Admin only) + * @description Sends funds from the Boundless platform wallet to a destination. Validates: destination activated, trustline for asset, memo when required, platform balance. Idempotent when idempotencyKey is provided. + */ + post: operations['WalletPayoutController_sendPayout']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List comments with filters */ + get: operations['CommentsController_listComments']; + put?: never; + /** Create a comment */ + post: operations['CommentsController_createComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get comment by ID */ + get: operations['CommentsController_getComment']; + /** Update comment (author only) */ + put: operations['CommentsController_updateComment']; + post?: never; + /** Delete comment (author or moderator only) */ + delete: operations['CommentsController_deleteComment']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/entity/{entityType}/{entityId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get comments for an entity */ + get: operations['CommentsController_getCommentsByEntity']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/{id}/reactions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get reactions for comment */ + get: operations['CommentsController_getReactions']; + put?: never; + /** Add reaction to comment */ + post: operations['CommentsController_addReaction']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/{id}/reactions/{reactionType}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Remove reaction from comment */ + delete: operations['CommentsController_removeReaction']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/{id}/report': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Report a comment */ + post: operations['CommentsController_reportComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/queue': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get moderation queue (moderators only) */ + get: operations['CommentModerationController_getModerationQueue']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/reports': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get all reports (moderators only) */ + get: operations['CommentModerationController_getReports']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/reports/{id}/resolve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Resolve a report (moderators only) */ + post: operations['CommentModerationController_resolveReport']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/{id}/approve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a comment (moderators only) */ + post: operations['CommentModerationController_approveComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/{id}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject/Hide a comment (moderators only) */ + post: operations['CommentModerationController_rejectComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/{id}/hide': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Hide a comment (moderators only) */ + post: operations['CommentModerationController_hideComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/{id}/restore': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Restore a hidden comment (moderators only) */ + post: operations['CommentModerationController_restoreComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/api/comments/moderation/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get moderation statistics (moderators only) */ + get: operations['CommentModerationController_getModerationStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get published hackathons + * @description Retrieves a paginated list of published hackathons with optional filtering + */ + get: operations['HackathonsController_getHackathons']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/fee-estimate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get fee estimate for prize pool + * @description Returns platform fee breakdown for a given total prize pool (USDC). Used by the Rewards step when creating a hackathon. + */ + get: operations['HackathonsController_getFeeEstimate']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/winners': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon winners + * @description Retrieves ranked winners for a hackathon with prize details + */ + get: operations['HackathonsController_getWinners']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/results': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get public judging results + * @description Retrieves aggregated judging results after results are published + */ + get: operations['HackathonsController_getPublicResults']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon by ID or slug + * @description Retrieves a published hackathon by its ID or slug + */ + get: operations['HackathonsController_getHackathon']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{slug}/contributors': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List public partner contributors for a hackathon + * @description Returns confirmed partner contributions where the partner opted in to be shown publicly, plus the total amount contributed. + */ + get: operations['HackathonsController_getPublicContributors']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/follow': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Follow or unfollow a hackathon + * @description Toggles follow status for a published hackathon + */ + post: operations['HackathonsController_followHackathon']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/join': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Join a hackathon + * @description Register as a participant for a published hackathon + */ + post: operations['HackathonsController_joinHackathon']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/leave': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Leave a hackathon + * @description Remove yourself as a participant from a hackathon + */ + delete: operations['HackathonsController_leaveHackathon']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/participants': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon participants + * @description Retrieve list of participants for a hackathon by ID or slug + */ + get: operations['HackathonsController_getHackathonParticipants']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/submissions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon submissions + * @description Retrieves submissions for a hackathon (organizer only) + */ + get: operations['HackathonsSubmissionsController_getHackathonSubmissions']; + put?: never; + /** + * Create a hackathon submission + * @description Submit a project to a hackathon + */ + post: operations['HackathonsSubmissionsController_createSubmission']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/submissions/explore': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Explore hackathon submissions + * @description Retrieves all submissions for a hackathon for public viewing + */ + get: operations['HackathonsSubmissionsController_exploreHackathonSubmissions']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/my-submission': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get my submission for a hackathon + * @description Retrieve the current user's submission for a hackathon + */ + get: operations['HackathonsSubmissionsController_getMySubmission']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/submissions/{submissionId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get a submission by ID + * @description Retrieve details of a specific submission + */ + get: operations['HackathonsSubmissionsController_getSubmissionById']; + put?: never; + post?: never; + /** + * Withdraw a hackathon submission + * @description Delete your submission before the deadline + */ + delete: operations['HackathonsSubmissionsController_deleteSubmission']; + options?: never; + head?: never; + /** + * Update a hackathon submission + * @description Update your submission before the deadline + */ + patch: operations['HackathonsSubmissionsController_updateSubmission']; + trace?: never; + }; + '/api/hackathons/{id}/discussions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon discussions + * @description Retrieve real-time comments and discussions for a hackathon + */ + get: operations['HackathonsDiscussionsController_getHackathonDiscussions']; + put?: never; + /** + * Post a comment in hackathon discussion + * @description Create a new comment in the hackathon discussion thread + */ + post: operations['HackathonsDiscussionsController_createHackathonComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/discussions/{commentId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete a discussion comment + * @description Remove your own comment from the hackathon discussion + */ + delete: operations['HackathonsDiscussionsController_deleteHackathonComment']; + options?: never; + head?: never; + /** + * Update a discussion comment + * @description Edit your own comment in the hackathon discussion + */ + patch: operations['HackathonsDiscussionsController_updateHackathonComment']; + trace?: never; + }; + '/api/hackathons/discussions/{commentId}/react': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * React to a comment + * @description Add or toggle a reaction (like, love, etc.) to a discussion comment + */ + post: operations['HackathonsDiscussionsController_reactToComment']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/discussions/{commentId}/replies': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get comment replies + * @description Retrieve replies to a specific comment + */ + get: operations['HackathonsDiscussionsController_getCommentReplies']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/teams': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon teams + * @description Retrieve all teams for a hackathon with optional filtering + */ + get: operations['HackathonsTeamsController_getHackathonTeams']; + put?: never; + /** + * Create a team + * @description Create a new team for the hackathon. Team is closed by default unless skills are specified. + */ + post: operations['HackathonsTeamsController_createTeam']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get team details + * @description Get detailed information about a specific team + */ + get: operations['HackathonsTeamsController_getTeam']; + put?: never; + post?: never; + /** + * Disband a team (leader only) + * @description Disband the team and remove all members. Refuses if the team has already submitted — withdraw the submission first. + */ + delete: operations['HackathonsTeamsController_disbandTeam']; + options?: never; + head?: never; + /** + * Update team + * @description Update team information (leader only). Team opens when skills are added, closes when removed. + */ + patch: operations['HackathonsTeamsController_updateTeam']; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}/join': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Join a team + * @description Join an existing open team + */ + post: operations['HackathonsTeamsController_joinTeam']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}/members/{userId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Remove a member from the team (leader only) + * @description Team leader removes a specific member. Leaders cannot remove themselves — they must transfer leadership first or disband the team. + */ + delete: operations['HackathonsTeamsController_removeTeamMember']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}/leave': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Leave a team + * @description Leave your current team. Leaders must transfer leadership first if team has other members. + */ + post: operations['HackathonsTeamsController_leaveTeam']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/my-team': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get my team + * @description Get your team in this hackathon + */ + get: operations['HackathonsTeamsController_getMyTeam']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}/invite': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Invite a user to join team + * @description Team leader can invite hackathon participants to join the team. Invitation expires in 7 days. + */ + post: operations['HackathonsTeamsController_inviteToTeam']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/my-invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get my team invitations + * @description Get all team invitations received by the current user + */ + get: operations['HackathonsTeamsController_getMyInvitations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/invitations/{inviteId}/accept': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Accept team invitation + * @description Accept a pending team invitation and join the team + */ + post: operations['HackathonsTeamsController_acceptInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/invitations/{inviteId}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Reject team invitation + * @description Reject a pending team invitation + */ + post: operations['HackathonsTeamsController_rejectInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/invitations/{inviteId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Cancel team invitation + * @description Team leader can cancel a pending invitation + */ + delete: operations['HackathonsTeamsController_cancelInvitation']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}/invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get team invitations + * @description Team leader can view all invitations sent by the team (pending, accepted, rejected) + */ + get: operations['HackathonsTeamsController_getTeamInvitations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}/roles/toggle-hired': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Toggle role hired status + * @description Team leader can toggle whether a role has been filled (hired) or is still open + */ + patch: operations['HackathonsTeamsController_toggleRoleHiredStatus']; + trace?: never; + }; + '/api/hackathons/{id}/teams/{teamId}/transfer-leadership': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Transfer team leadership + * @description Current team leader can transfer leadership to another team member. This action is logged in audit logs for accountability. + */ + post: operations['HackathonsTeamsController_transferLeadership']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/draft/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon draft details + * @description Retrieves the current state of a hackathon draft for editing + */ + get: operations['OrganizationHackathonsDraftsController_getDraft']; + put?: never; + post?: never; + /** + * Delete hackathon draft + * @description Deletes a hackathon draft by ID for an organization + */ + delete: operations['OrganizationHackathonsDraftsController_deleteDraft']; + options?: never; + head?: never; + /** + * Update one or more sections of a hackathon draft + * @description Applies any subset of wizard sections in a single PATCH. Send one section for a per-step "Continue", or several for "Save draft". Each present section is validated and transformed independently, then merged into one write. + */ + patch: operations['OrganizationHackathonsDraftsController_updateDraft']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get organization's published hackathons + * @description Retrieves all published hackathons for an organization with pagination + */ + get: operations['OrganizationHackathonsDraftsController_getOrganizationHackathons']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/draft': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a new hackathon draft for an organization + * @description Creates a new hackathon in draft status that can be edited by organization members + */ + post: operations['OrganizationHackathonsDraftsController_createDraft']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/drafts': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get organization's hackathon drafts + * @description Retrieves all draft hackathons for an organization that the user has access to + */ + get: operations['OrganizationHackathonsDraftsController_getOrganizationDrafts']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/hackathons/{id}/announcement-preview': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Preview the marketing announcement audience size + * @description Returns the number of recipients that would receive the launch announcement email if the hackathon were published right now. Useful for the publish UI. + */ + get: operations['OrganizationHackathonsDraftsController_previewAnnouncementAudience']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/visibility': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update hackathon submission visibility settings + * @description Allows organizers to change who can view submissions and which statuses are visible. + */ + patch: operations['OrganizationHackathonsSubmissionsController_updateVisibilitySettings']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/review': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Review a submission + * @description Update submission status (shortlist or move back to submitted). Organizer only. + */ + patch: operations['OrganizationHackathonsSubmissionsController_reviewSubmission']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/participants': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon participants (organization) + * @description Returns detailed participant data for organizers, including submission details. + */ + get: operations['OrganizationHackathonsSubmissionsController_getOrganizationHackathonParticipants']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/score-override': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Organizer: Override submission scoring + * @description Organizer directly assigns criterion-based scores to a submission. Validates rubric compliance but bypasses judge assignment and conflict-of-interest checks. Use when correcting judge scores or assigning administrative evaluations. Organizer only. + */ + post: operations['OrganizationHackathonsSubmissionsController_scoreSubmissionOverride']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/disqualify': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Disqualify a submission + * @description Mark a submission as disqualified with a reason. Organizer only. + */ + post: operations['OrganizationHackathonsSubmissionsController_disqualifySubmission']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/bulk-action': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Perform bulk action on submissions + * @description Update status of multiple submissions at once (shortlist, approve, disqualify). Organizer only. + */ + post: operations['OrganizationHackathonsSubmissionsController_bulkSubmissionAction']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/rank': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Set submission rank + * @description Assign a rank to a submission for leaderboard positioning. Organizer only. + */ + patch: operations['OrganizationHackathonsSubmissionsController_setSubmissionRank']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/analytics': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon analytics + * @description Retrieves summary metrics, trend data, and timeline for a hackathon. Organizer only. + */ + get: operations['OrganizationHackathonsSubmissionsController_getAnalytics']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/announcements': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon announcements + * @description Retrieves all announcements for a hackathon. Drafts are only visible to organizers. + */ + get: operations['HackathonsAnnouncementsController_getAnnouncements']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/announcements/{announcementId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get announcement details + * @description Retrieves details of a specific announcement + */ + get: operations['HackathonsAnnouncementsController_getAnnouncement']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/announcements': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a hackathon announcement + * @description Creates a new announcement for an organization hackathon + */ + post: operations['OrganizationHackathonsAnnouncementsController_createAnnouncement']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/announcements/{announcementId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete a hackathon announcement + * @description Deletes an announcement for an organization hackathon + */ + delete: operations['OrganizationHackathonsAnnouncementsController_deleteAnnouncement']; + options?: never; + head?: never; + /** + * Update a hackathon announcement + * @description Updates an existing announcement for an organization hackathon + */ + patch: operations['OrganizationHackathonsAnnouncementsController_updateAnnouncement']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/announcements/{announcementId}/publish': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Publish a draft announcement + * @description Publishes a draft announcement for an organization hackathon + */ + post: operations['OrganizationHackathonsAnnouncementsController_publishAnnouncement']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/judging/criteria': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon judging criteria + * @description Retrieves the criteria used for judging this hackathon + */ + get: operations['HackathonsJudgingController_getCriteria']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/judging/score': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Judge: Submit criterion-based scores + * @description Allows an assigned judge to submit criterion-based scores for a submission. Enforces: (1) judge assignment verification, (2) conflict-of-interest checks, (3) rubric compliance validation. + */ + post: operations['HackathonsJudgingController_submitScore']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/judging/submissions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get submissions for judging + * @description Retrieves shortlisted submissions with the current judge's scores and criteria + */ + get: operations['HackathonsJudgingController_getJudgingSubmissions']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/judges': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon judges + * @description Retrieves the list of judges assigned to the hackathon + */ + get: operations['OrganizationHackathonsJudgingController_getJudges']; + put?: never; + /** + * Add a judge to a hackathon + * @description Assigns a user as a judge for the hackathon + */ + post: operations['OrganizationHackathonsJudgingController_addJudge']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/judges/{userId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Remove a judge from a hackathon + * @description Removes a user from the judging panel + */ + delete: operations['OrganizationHackathonsJudgingController_removeJudge']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/results': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get aggregated judging results + * @description Retrieves the ranked results for the hackathon based on judging scores + */ + get: operations['OrganizationHackathonsJudgingController_getResults']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/submissions/{submissionId}/scores': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get individual judge scores for a submission + * @description Retrieves all judge scores and comments for a project + */ + get: operations['OrganizationHackathonsJudgingController_getIndividualScores']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/winners': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get winner ranking + * @description Retrieves the ranked results sorted by average score + */ + get: operations['OrganizationHackathonsJudgingController_getWinnerRanking']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/coverage': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Full judges × submissions coverage matrix + * @description Returns every shortlisted submission with the set of active judges who scored it, plus per-judge totals. Used by the organizer dashboard to render a heatmap that surfaces idle judges (columns of mostly empty cells) and orphan submissions (rows with 0-1 scores) at a glance — both block a defensible publish. The view-only `/completeness` endpoint stays unchanged for the publish-confirmation flow. + */ + get: operations['OrganizationHackathonsJudgingController_judgingCoverage']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/preview-allocation': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Preview the allocator outcome before publishing + * @description Read-only dry run of the publish-results allocator. Returns the overall placements + per-track winners that would be stamped on publish, including EXCLUSIVE stacking effects (a track leader losing because they already claimed an overall placement). Also surfaces the publish gates (deadline, completeness, partner allocation) so the UI can render a "what is blocking publish?" panel without trying to publish. + */ + get: operations['OrganizationHackathonsJudgingController_previewAllocation']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/completeness': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Preview judging completeness + * @description Returns which submissions are short any active judge, and which judges still have outstanding work. The frontend uses this to render the publish-results confirmation dialog before the organizer commits. + */ + get: operations['OrganizationHackathonsJudgingController_judgingCompleteness']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/publish-results': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Publish results + * @description Finalizes the ranks and marks results as public. Rejects (400) if any active judge has not scored every shortlisted submission, unless the request body includes `acceptPartial: true`. + */ + post: operations['OrganizationHackathonsJudgingController_publishResults']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List judge invitations for this hackathon */ + get: operations['OrganizationHackathonsJudgingController_listInvitations']; + put?: never; + /** + * Invite a judge by email + * @description Sends an email-based invitation. The recipient is NOT added to the organization; on acceptance they become a hackathon-scoped judge only. + */ + post: operations['OrganizationHackathonsJudgingController_inviteJudge']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/invitations/{invitationId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Cancel (revoke) a pending judge invitation */ + delete: operations['OrganizationHackathonsJudgingController_cancelInvitation']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/invitations/{invitationId}/resend': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Resend a pending judge invitation + * @description Rotates the invitation token so any previously-leaked link is invalidated, then re-emails the recipient. + */ + post: operations['OrganizationHackathonsJudgingController_resendInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List my pending judge invitations + * @description Returns pending, non-expired invitations sent to the authenticated user's email. + */ + get: operations['JudgeController_myInvitations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/invitations/{token}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Preview an invitation by token + * @description Public endpoint so an invitee can see who invited them and which hackathon before signing in. Reveals only the invitation summary — never anything that requires auth. + */ + get: operations['JudgeController_previewInvitation']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/invitations/{token}/accept': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Accept a judge invitation + * @description Creates the HackathonJudge assignment. The authenticated user is NOT added to the hosting organization — judge access is hackathon-scoped only. + */ + post: operations['JudgeController_acceptInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/invitations/{token}/decline': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Decline a judge invitation */ + post: operations['JudgeController_declineInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List hackathons I'm assigned to judge + * @description Returns all hackathons where the authenticated user has an active judge assignment. + */ + get: operations['JudgeController_myHackathons']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons/{hackathonId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get judge-scoped hackathon overview + * @description Returns hackathon overview tailored to a judge: dates, criteria, my progress. Never includes peer signals or organization-management data. + */ + get: operations['JudgeController_overview']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons/{hackathonId}/submissions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List submissions for scoring + * @description Returns shortlisted submissions with only the calling judge's own scores. Peer-derived signals (averageScore, judgeCount) are intentionally omitted to preserve blind scoring. + */ + get: operations['JudgeController_submissions']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons/{hackathonId}/submissions/{submissionId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get one submission with my score + * @description Returns a single submission plus the calling judge's own score (if any). Peer scores remain hidden until results are published. + */ + get: operations['JudgeController_submission']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons/{hackathonId}/submissions/{submissionId}/neighbors': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Queue neighbors for the scoring page + * @description Returns the previous and next submissions in the canonical queue, plus the next unscored one (wrapping to the start if needed), plus totals. Single round trip so the scoring page can render "X of N" and auto-advance without fetching the full queue. + */ + get: operations['JudgeController_neighbors']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons/{hackathonId}/criteria': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get judging criteria for this hackathon */ + get: operations['JudgeController_criteria']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons/{hackathonId}/results': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Final results for this hackathon + * @description Returns the published ranking. Returns `{ resultsPublished: false, results: [] }` until the organizer publishes — never leaks scores prematurely. + */ + get: operations['JudgeController_results']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/judge/hackathons/{hackathonId}/submissions/{submissionId}/score': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit (or update) my scores for a submission + * @description Upserts the calling judge's scores for the given submission. Rubric validation and the judging window are enforced by the underlying service. + */ + post: operations['JudgeController_score']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/statistics': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get hackathon statistics (organizers only) + * @description Retrieves participation and engagement statistics for a hackathon. Only organizers of the hackathon can access this. + */ + get: operations['OrganizationHackathonsUpdatesController_getHackathonStatistics']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/content': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update published hackathon content + * @description Updates published hackathon information and/or collaboration data. + */ + patch: operations['OrganizationHackathonsUpdatesController_updatePublishedContent']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/schedule': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update published hackathon schedule + * @description Updates published hackathon timeline and/or participation settings. + */ + patch: operations['OrganizationHackathonsUpdatesController_updatePublishedSchedule']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/financial': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update published hackathon financial settings + * @description Updates published hackathon rewards data with escrow safety checks. + */ + patch: operations['OrganizationHackathonsUpdatesController_updatePublishedFinancial']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/financial/preview': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Preview financial update cost (dry-run) + * @description Calculates the exact USDC cost of a proposed reward update without + * making any changes to escrow state or the wallet. + * + * Returns a per-tier breakdown plus the total additional funding required, + * the current wallet balance, and whether the balance is sufficient. + * + * Call this **before** `PATCH /financial` to power a confirmation step in + * the UI and avoid surprising the organizer with an insufficient-balance error. + */ + post: operations['OrganizationHackathonsUpdatesController_previewPublishedFinancial']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/advanced-settings': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update published hackathon advanced settings + * @description Updates published hackathon advanced settings in metadata for frontend behavior controls. + */ + patch: operations['OrganizationHackathonsUpdatesController_updatePublishedAdvancedSettings']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/export': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Export hackathon data (organizer only) + * @description Export hackathon data as a **CSV** or a **branded PDF**. + * + * **CSV** — A multi-section spreadsheet-compatible file with UTF-8 BOM for + * Excel compatibility. Sections: Overview, Prize Tiers, Participants, Submissions, Winners, Judging. + * + * **PDF** — A professionally branded Boundless report including cover header, + * key-metric stat cards, and data tables. Dark brand palette with mint accent. + * + * Use the `dataset` param to limit which sections are included. + * + * > Only hackathon organizers (organization managers) can use this endpoint. + */ + get: operations['OrganizationHackathonsExportController_exportHackathon']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/invite': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Invite a partner to contribute to the hackathon prize pool */ + post: operations['OrganizationHackathonsPartnersController_invite']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List partner contributions for a hackathon */ + get: operations['OrganizationHackathonsPartnersController_list']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions/{contributionId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Cancel a pending partner invitation */ + delete: operations['OrganizationHackathonsPartnersController_cancel']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions/{contributionId}/allocations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get allocation summary for a contribution + * @description Returns the pledged amount, allocatable (after Trustless Work fee), already allocated, remaining unallocated, and the list of individual allocations. + */ + get: operations['OrganizationHackathonsPartnersController_getAllocations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions/{contributionId}/allocate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Allocate a partner contribution into prize tiers + * @description Distributes the contribution amount into one or more prize tiers — either inflating existing tiers or creating new ones. The sum of allocations cannot exceed the remaining allocatable amount. + */ + post: operations['OrganizationHackathonsPartnersController_allocate']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/allocations/{allocationId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Undo a single allocation + * @description Reverses an allocation, decrementing the prize tier amount and removing the tier if it was created by the allocation and no longer has any remaining amount. + */ + delete: operations['OrganizationHackathonsPartnersController_undoAllocation']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/partners/contribute/{token}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get partner invitation details by token (public, tokenized) */ + get: operations['PartnersContributeController_getByToken']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/partners/contribute/{token}/prepare-fund-tx': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Build an unsigned Trustless Work fund-escrow transaction + * @description Validates the contribution window, calls Trustless Work, and returns an unsigned XDR for the partner wallet to sign locally. The Trustless Work API key never leaves the backend. + */ + post: operations['PartnersContributeController_prepareFundTx']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/partners/contribute/{token}/submit-tx': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit a partner-signed transaction and confirm the contribution + * @description Forwards the signed XDR to Trustless Work, then marks the contribution confirmed using the Stellar transaction hash returned. + */ + post: operations['PartnersContributeController_submitTx']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{idOrSlug}/tracks': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List hackathon tracks + * @description Returns the public list of tracks for a hackathon. Archived tracks are hidden by default; pass includeArchived=true to see them (useful for organizer dashboards). + */ + get: operations['HackathonsTracksController_listTracks']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/tracks': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List tracks (organizer view) + * @description Returns the full set of tracks for this hackathon, including archived ones by default. Use ?includeArchived=false to hide them. + */ + get: operations['OrganizationHackathonsTracksController_list']; + put?: never; + /** Create a track */ + post: operations['OrganizationHackathonsTracksController_create']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/tracks/{trackId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete a track + * @description Hard-deletes the track if no submissions are entered. If submissions have already opted in, archives the track instead (preserves history). + */ + delete: operations['OrganizationHackathonsTracksController_remove']; + options?: never; + head?: never; + /** Update a track */ + patch: operations['OrganizationHackathonsTracksController_update']; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/tracks/{trackId}/bulk-opt-in': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Opt in every existing submission into this track + * @description Retrofit tool for hackathons where tracks were added after submissions exist. Inserts a SubmissionTrackEntry for every non-disqualified submission. Idempotent. Auto-bumps `tracksMaxPerSubmission` if needed so submitters can still edit their submissions afterwards. + */ + post: operations['OrganizationHackathonsTracksController_bulkOptIn']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/funding-otp/request': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Request a funding step-up code + * @description Emails a one-time code the organizer must verify before funding. Reports required=false when step-up is disabled, or alreadyVerified=true when a recent verification still authorizes funding. + */ + post: operations['OrganizationHackathonsEscrowController_requestFundingOtp']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/funding-otp/verify': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Verify a funding step-up code + * @description Verifies the emailed code and authorizes funding for a short window. Wrong or expired codes return 400; attempts are capped. + */ + post: operations['OrganizationHackathonsEscrowController_verifyFundingOtp']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/publish': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Publish a hackathon draft to the events contract + * @description Validates the draft, transitions it to DRAFT_AWAITING_FUNDING, and returns an unsigned XDR transaction for the organizer to sign. After signing, post the result back to /escrow/ops/:opRowId/submit-signed. Requires a verified funding step-up when FUNDING_OTP_ENABLED is on. + */ + post: operations['OrganizationHackathonsEscrowController_publish']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/cancel': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Cancel an active hackathon + * @description Builds a cancel_event contract op. The contract refunds partner contributions first then the owner residual. On settle, the subscriber transitions the hackathon to CANCELLED and stamps the cancel audit columns. + */ + post: operations['OrganizationHackathonsEscrowController_cancel']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/select-winners': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Select winners for a hackathon + * @description Builds a select_winners contract op that pays out per the on-chain winner_distribution and bumps each winner's profile credits / reputation / earnings. On settle, the subscriber moves the hackathon to COMPLETED and sets rank on the winning HackathonSubmission rows. + */ + post: operations['OrganizationHackathonsEscrowController_selectWinners']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/ops/{opRowId}/submit-signed': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit signed XDR for a previously-built escrow op + * @description Accepts the signed XDR returned by the wallet and posts it to Soroban RPC. Returns the op in PENDING_CONFIRM; the reconciliation worker drives the final transition to COMPLETED or FAILED. + */ + post: operations['OrganizationHackathonsEscrowController_submitSigned']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/ops/{opRowId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Read the current state of an escrow op + * @description Polled by the webapp while waiting for the reconciliation worker to mark the op COMPLETED or FAILED. + */ + get: operations['OrganizationHackathonsEscrowController_getOp']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/hackathons/{id}/escrow/reset-to-draft': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Reset a stranded hackathon back to DRAFT + * @description Recovers a hackathon stuck in DRAFT_AWAITING_FUNDING (e.g. a failed managed sign/submit) back to DRAFT so the organizer can fix the cause and republish. Refuses while the publish op may still settle on-chain. + */ + post: operations['OrganizationHackathonsEscrowController_resetToDraft']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/escrow/submissions/{submissionId}/submit': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Anchor a hackathon submission on chain + * @description Builds the contract's submit op for an existing HackathonSubmission row. Hackathon has no prior-apply requirement; the contract simply stores the submission anchor with content_uri + submitted_at. + */ + post: operations['HackathonParticipantEscrowController_submit']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/escrow/submissions/{submissionId}/withdraw': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Withdraw a hackathon submission anchor */ + post: operations['HackathonParticipantEscrowController_withdrawSubmission']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/escrow/contribute': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Contribute funds to a hackathon pool + * @description Builds an add_funds contract op signed by the caller. Contract enforces a 10 USDC minimum. Anyone authenticated can contribute; multiple top-ups from the same wallet are allowed (one row per attempt). + */ + post: operations['HackathonParticipantEscrowController_contribute']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/escrow/ops/{opRowId}/submit-signed': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Submit signed XDR for a participant op */ + post: operations['HackathonParticipantEscrowController_submitSigned']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/hackathons/{id}/escrow/ops/{opRowId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Read the state of a participant op */ + get: operations['HackathonParticipantEscrowController_getOp']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OrganizationsController_getOrganizations']; + put?: never; + post: operations['OrganizationsController_createOrganization']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/my': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OrganizationsController_getMyOrganizations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/profile/{idOrSlug}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get organization profile (public) + * @description Returns public profile for the organization page: name, logo, description, and key stats. Resolve by organization ID or slug. + */ + get: operations['OrganizationsController_getOrganizationProfile']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/search': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Search organizations */ + get: operations['OrganizationsController_searchOrganizations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get organization by ID + * @description Retrieve detailed information about a specific organization + */ + get: operations['OrganizationsController_getOrganization']; + put: operations['OrganizationsController_updateOrganization']; + post?: never; + delete: operations['OrganizationsController_deleteOrganization']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{id}/members': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OrganizationsController_getOrganizationMembers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{id}/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['OrganizationsController_getOrganizationStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/members': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['MembersController_getMembers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/members/{userId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['MembersController_addMember']; + delete: operations['MembersController_removeMember']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/members/{userId}/role': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put: operations['MembersController_updateMemberRole']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/members/me': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['MembersController_getMyMembership']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['InvitationsController_getInvitations']; + put?: never; + post: operations['InvitationsController_inviteMember']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/invitations/{invitationId}/accept': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['InvitationsController_acceptInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/invitations/{invitationId}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['InvitationsController_rejectInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/invitations/{invitationId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete: operations['InvitationsController_cancelInvitation']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/invitations/my': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['InvitationsController_getMyInvitations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/wallets': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List treasury wallets */ + get: operations['OrganizationTreasuryController_listWallets']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/default-wallet': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get (or create) the organization default wallet + * @description Returns the org canonical managed wallet, provisioning one if none exists. Owner/admin only (may create). Use this as the funding + contract-auth identity for organization events. + */ + get: operations['OrganizationTreasuryController_getDefaultWallet']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/wallets/managed': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a Tier 1 managed treasury wallet + * @description Provisions a platform-custodial Stellar account (sponsored activation + USDC trustline) owned by the organization. Owner/admin only. + */ + post: operations['OrganizationTreasuryController_createManagedWallet']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/wallets/connected': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Register a connected (Tier 2/3) wallet + * @description Verifies the external account exists + holds a USDC trustline, snapshots its multisig signer set, and records it. Owner/admin only. + */ + post: operations['OrganizationTreasuryController_registerConnectedWallet']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/wallets/{walletId}/refresh-signers': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Re-fetch a connected wallet signer set from Horizon */ + post: operations['OrganizationTreasuryController_refreshSigners']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/wallets/{walletId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Update a wallet label / default flag */ + patch: operations['OrganizationTreasuryController_updateWallet']; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/wallets/{walletId}/archive': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Archive a treasury wallet */ + post: operations['OrganizationTreasuryController_archiveWallet']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/wallets/{walletId}/balance': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Live USDC + XLM balance for a wallet */ + get: operations['OrganizationTreasuryController_walletBalance']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/policy': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get the treasury spend policy (defaults if unset) */ + get: operations['OrganizationTreasuryController_getPolicy']; + /** Update the treasury spend policy (owner only) */ + put: operations['OrganizationTreasuryController_updatePolicy']; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List spend requests */ + get: operations['OrganizationTreasuryController_listSpend']; + put?: never; + /** Initiate a spend request */ + post: operations['OrganizationTreasuryController_initiateSpend']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend/{requestId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get a spend request */ + get: operations['OrganizationTreasuryController_getSpend']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend/{requestId}/approve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a spend request (owner/admin) */ + post: operations['OrganizationTreasuryController_approveSpend']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend/{requestId}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject a spend request (owner/admin) */ + post: operations['OrganizationTreasuryController_rejectSpend']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend/{requestId}/cancel': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Cancel a spend request (initiator or owner) */ + post: operations['OrganizationTreasuryController_cancelSpend']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend/{requestId}/execute': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Execute an approved spend on-chain (managed wallets) + * @description For a managed source wallet, signs + submits a USDC payment to the destination server-side. Owner/admin only. + */ + post: operations['OrganizationTreasuryController_executeSpend']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend/{requestId}/build-xdr': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Build the unsigned XDR for a connected-wallet spend + * @description For an approved connected (Tier 2/3) spend, returns the unsigned USDC payment XDR to sign in-browser and moves it to awaiting_signatures. + */ + post: operations['OrganizationTreasuryController_buildSpendXdr']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/spend/{requestId}/submit-signed-xdr': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Submit a browser-signed spend XDR (connected wallets) */ + post: operations['OrganizationTreasuryController_submitSpendSignedXdr']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/treasury/audit-log': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Paginated treasury audit log */ + get: operations['OrganizationTreasuryController_auditLog']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/votes': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['VotesController_getVotes']; + put?: never; + post: operations['VotesController_createVote']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/votes/{projectId}/{entityType}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete: operations['VotesController_removeVote']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/votes/count/{projectId}/{entityType}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['VotesController_getVoteCounts']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/votes/my-vote/{projectId}/{entityType}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations['VotesController_getUserVote']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/votes/project/{projectId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get project votes + * @description Get project votes. Use includeVoters=true for comprehensive data including voter list and vote counts. + */ + get: operations['VotesController_getProjectVotes']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/leaderboard': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get community leaderboard entries */ + get: operations['LeaderboardController_getLeaderboard']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/blog-posts': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List all blog posts with pagination and filters */ + get: operations['BlogPostsController_listBlogPosts']; + put?: never; + /** Create a new blog post */ + post: operations['BlogPostsController_createBlogPost']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/blog-posts/id/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get blog post by ID */ + get: operations['BlogPostsController_getBlogPostById']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/blog-posts/slug/{slug}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get blog post by slug */ + get: operations['BlogPostsController_getBlogPostBySlug']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/blog-posts/{id}/related': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get related blog posts */ + get: operations['BlogPostsController_getRelatedPosts']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/blog-posts/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Update a blog post */ + put: operations['BlogPostsController_updateBlogPost']; + post?: never; + /** Delete a blog post */ + delete: operations['BlogPostsController_deleteBlogPost']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ai/generate-excerpt': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Generate excerpt from content */ + post: operations['AiController_generateExcerpt']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ai/generate-reading-time': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Generate reading time estimate from content */ + post: operations['AiController_generateReadingTime']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ai/generate-seo': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Generate SEO settings from content */ + post: operations['AiController_generateSEO']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ai/generate-tags': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Generate tags from content */ + post: operations['AiController_generateTags']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ai/generate-category': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Generate category from content */ + post: operations['AiController_generateCategory']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/overview': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get admin overview data (Admin only) + * @description Retrieves comprehensive overview data including metrics and charts for the admin dashboard + */ + get: operations['AdminController_getOverview']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/users': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get all users (Admin only) + * @description Retrieves a paginated list of all users with optional filtering + */ + get: operations['AdminController_getUsers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/users/export': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Export all users as CSV (Admin only) + * @description Downloads a CSV file containing all platform users and newsletter-only subscribers + */ + get: operations['AdminController_exportUsers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/users/{usernameOrId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user details (Admin only) + * @description Retrieves detailed information about a specific user by username or ID + */ + get: operations['AdminController_getUserDetails']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/users/{usernameOrId}/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user statistics (Admin only) + * @description Retrieves comprehensive statistics for a specific user + */ + get: operations['AdminController_getUserStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/users/{usernameOrId}/activity': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user activity (Admin only) + * @description Retrieves activity history for a specific user + */ + get: operations['AdminController_getUserActivity']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/users/{usernameOrId}/projects': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user projects (Admin only) + * @description Retrieves all projects created by a specific user + */ + get: operations['AdminController_getUserProjects']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/organizations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get all organizations (Admin only) + * @description Retrieves a paginated list of all organizations with member counts + */ + get: operations['AdminController_getOrganizations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/organizations/{orgId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get organization details (Admin only) + * @description Retrieves detailed information about an organization including members and hackathons + */ + get: operations['AdminController_getOrganizationDetails']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/users/{usernameOrId}/organizations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user organizations (Admin only) + * @description Retrieves all organizations a user is a member of + */ + get: operations['AdminController_getUserOrganizations']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List all blog posts including drafts (Admin only) */ + get: operations['AdminBlogsController_listAllBlogPosts']; + put?: never; + /** Create a new blog post (Admin only) */ + post: operations['AdminBlogsController_createBlogPost']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get blog post by ID (Admin only) */ + get: operations['AdminBlogsController_getBlogPostById']; + /** Update a blog post (Admin only) */ + put: operations['AdminBlogsController_updateBlogPost']; + post?: never; + /** + * Soft delete a blog post (Admin only) + * @description Marks the blog post as deleted without removing it from database + */ + delete: operations['AdminBlogsController_deleteBlogPost']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts/{id}/permanent': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Permanently delete a blog post (Admin only) + * @description Permanently removes the blog post from database + */ + delete: operations['AdminBlogsController_permanentlyDeleteBlogPost']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts/{id}/restore': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Restore a soft-deleted blog post (Admin only) */ + post: operations['AdminBlogsController_restoreBlogPost']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts/tags/all': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get all tags with post counts (Admin only) */ + get: operations['AdminBlogsController_getAllTags']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts/tags/{slug}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get tag by slug (Admin only) */ + get: operations['AdminBlogsController_getTagBySlug']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts/tags/unused': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete all unused tags (Admin only) + * @description Removes tags that are not associated with any blog posts + */ + delete: operations['AdminBlogsController_deleteUnusedTags']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/blog-posts/scheduled/publish': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Manually trigger publishing of scheduled posts (Admin only) */ + post: operations['AdminBlogsController_publishScheduledPosts']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List crowdfunding campaigns */ + get: operations['AdminCrowdfundingController_list']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/user/{usernameOrId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List crowdfunding campaigns by user */ + get: operations['AdminCrowdfundingController_listByUser']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/{campaignId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get crowdfunding campaign by ID */ + get: operations['AdminCrowdfundingController_getCampaign']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/pending': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List crowdfunding campaigns pending admin review */ + get: operations['AdminCrowdfundingController_listPending']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/{campaignId}/approve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a crowdfunding campaign */ + post: operations['AdminCrowdfundingController_approve']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/{campaignId}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject a crowdfunding campaign */ + post: operations['AdminCrowdfundingController_reject']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/{campaignId}/request-revision': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Request revisions for a crowdfunding campaign */ + post: operations['AdminCrowdfundingController_requestRevision']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/{campaignId}/review-note': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Add an admin review note for a campaign */ + post: operations['AdminCrowdfundingController_addReviewNote']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/crowdfunding/{campaignId}/assign-reviewer': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Assign a reviewer to a campaign */ + post: operations['AdminCrowdfundingController_assignReviewer']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/milestones': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List all milestones grouped by campaign + * @description Retrieves all milestones organized by their campaigns with pagination + */ + get: operations['AdminMilestonesController_listAllMilestonesByCampaign']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/milestones/pending': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get pending milestone review queue */ + get: operations['AdminMilestonesController_listPendingMilestones']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/milestones/{milestoneId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get milestone detail for review */ + get: operations['AdminMilestonesController_getMilestoneForReview']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/milestones/{milestoneId}/approve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a milestone submission */ + post: operations['AdminMilestonesController_approveMilestone']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/milestones/{milestoneId}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject a milestone submission */ + post: operations['AdminMilestonesController_rejectMilestone']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/milestones/{milestoneId}/request-resubmission': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Request milestone resubmission with changes */ + post: operations['AdminMilestonesController_requestResubmission']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/milestones/{milestoneId}/review-note': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Add a review note to milestone */ + post: operations['AdminMilestonesController_addReviewNote']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/escrow/{campaignId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get escrow information and transaction history for campaign */ + get: operations['AdminEscrowController_getEscrowInfo']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/escrow/{campaignId}/action': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Execute manual escrow action (testnet only) + * @description Manually trigger escrow actions like release, refund, pause, or resume. This is intended for testnet use only. + */ + post: operations['AdminEscrowController_executeEscrowAction']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/disputes': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get dispute dashboard with filtering */ + get: operations['AdminDisputesController_listDisputes']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/disputes/{disputeId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get detailed dispute information */ + get: operations['AdminDisputesController_getDisputeDetail']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/disputes/{disputeId}/assign': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Assign dispute to an admin */ + post: operations['AdminDisputesController_assignDispute']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/disputes/{disputeId}/note': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Add note or message to dispute + * @description Add a communication to the dispute. Can be internal (admin only) or external (visible to parties). + */ + post: operations['AdminDisputesController_addDisputeNote']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/disputes/{disputeId}/resolve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Resolve a dispute with a final decision */ + post: operations['AdminDisputesController_resolveDispute']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/disputes/{disputeId}/escalate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Escalate dispute to arbitration */ + post: operations['AdminDisputesController_escalateDispute']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/manual-projects/pending': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List pending manual project submissions */ + get: operations['AdminManualProjectsController_listPendingManualProjects']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/manual-projects/{projectId}/approve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a pending manual project */ + post: operations['AdminManualProjectsController_approveManualProject']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/manual-projects/{projectId}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject a pending manual project */ + post: operations['AdminManualProjectsController_rejectManualProject']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/manual-projects/{projectId}/request-changes': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Request changes for a pending manual project */ + post: operations['AdminManualProjectsController_requestChanges']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/project-edits/pending': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List pending major project edits */ + get: operations['AdminProjectEditsController_listPendingProjectEdits']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/project-edits/{editId}/approve': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a pending major project edit */ + post: operations['AdminProjectEditsController_approveProjectEdit']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/project-edits/{editId}/reject': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject a pending major project edit */ + post: operations['AdminProjectEditsController_rejectProjectEdit']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get wallet statistics */ + get: operations['AdminWalletsController_getStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List user wallets */ + get: operations['AdminWalletsController_listWallets']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets/user/{userId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get wallets for a specific user */ + get: operations['AdminWalletsController_getByUserId']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get detailed wallet info */ + get: operations['AdminWalletsController_getDetails']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets/{id}/activate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Sponsor-activate a wallet by ID (creates account + configured trustlines, default USDC) + * @description All XLM reserves paid by the platform sponsor account. Idempotent: re-running on an already-activated wallet returns success without submitting. Used by the admin dashboard "Activate" button. + */ + post: operations['AdminWalletsController_activateWallet']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets/users/{userId}/sponsor-activate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Sponsor-activate a single user (account + USDC trustline) + * @description Uses the sponsor account to create the on-chain account and add the configured trustlines (default USDC). User pays no XLM. Idempotent: safe to retry. Use this for hackathon participants who need to receive USDC payouts. + */ + post: operations['AdminWalletsController_sponsorActivateUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets/hackathons/{hackathonId}/sponsor-activate': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Enqueue sponsor activation for every participant of a hackathon + * @description Aggregates all distinct user IDs from HackathonSubmission.participantId and teamMembers[], then enqueues a BullMQ job that activates each wallet (account + USDC trustline). Returns immediately with a job ID. Poll the status URL for progress; idempotent re-runs are safe. + */ + post: operations['AdminWalletsController_sponsorActivateHackathon']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/wallets/jobs/sponsor-activation/{jobId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get status of a sponsor-activation job + * @description Returns BullMQ job state (waiting | active | completed | failed | delayed | paused), progress {processed, total, activated, alreadyActivated, failed}, returnvalue (full summary when complete), and failedReason. + */ + get: operations['AdminWalletsController_getSponsorActivationJobStatus']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/healthz': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Liveness probe + * @description Returns 200 if the process is alive. No downstream checks. Use for orchestrator restart decisions. + */ + get: operations['HealthController_liveness']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/readyz': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Readiness probe + * @description Returns 200 only when Postgres and Redis are reachable. Use for orchestrator traffic-drain decisions, not for restart. + */ + get: operations['HealthController_readiness']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/didit/status': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get current verification state for the authenticated user + * @description Returns a normalized verification state the frontend uses to decide what to render: the verify button is shown only when `canStartNew` is true (states: not_started, declined, abandoned, expired). For `in_review` the response includes a `reviewWindow` with the SLA in business days. + */ + get: operations['DiditController_getStatus']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/didit/callback': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Didit redirect target (post-verification) + * @description Didit redirects the user here after the hosted KYC flow. We resolve authoritative status from the DB (the query string from Didit is not trusted) and 302 to the frontend with `?state=...`. State maps directly to the values returned by GET /didit/status. + */ + get: operations['DiditController_callback']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/didit/create-session': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create verification session + * @description Creates a Didit verification session. Returns session_token and verification_url for the frontend SDK. Authenticated user id is sent as vendor_data unless user_id is provided. + */ + post: operations['DiditController_createSession']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/didit/webhook': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Didit webhook + * @description Receives verification completion events from Didit. Verifies X-Signature-V2 when DIDIT_WEBHOOK_SECRET is set. Updates user verification status and DiditVerificationSession. + */ + post: operations['DiditController_webhook']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/pricing/preview': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Compute the financial preview for a publish wizard */ + get: operations['PricingController_preview']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ops/pause': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AdminOpsController_pause']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ops/unpause': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AdminOpsController_unpause']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/ops/set-fee-bps': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['AdminOpsController_setFeeBps']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/prices': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get USD prices for all supported assets + * @description Returns per-unit USD prices for XLM, USDC, EURC and USDGLO. Resolved from the Reflector on-chain oracle, with CoinGecko and stablecoin-peg fallbacks. Cached for 5 minutes (matches Reflector update cadence). + */ + get: operations['PricesController_getAll']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/prices/debug': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Per-provider price resolution (diagnostic) + * @description Bypasses the cache and pings Reflector + CoinGecko for every supported asset. Returns what each provider returned alongside which one the resolution chain would have picked. Use to verify both price paths are live. + */ + get: operations['PricesController_getDebug']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/prices/{symbol}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get USD price for a single asset + * @description Convenience lookup — internally reads from the same cached map as the list endpoint. + */ + get: operations['PricesController_getOne']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/drafts': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Create a project draft (stepped form) */ + post: operations['ProjectsController_createDraft']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/{id}/draft': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Update a project draft (stepped form autosave) */ + patch: operations['ProjectsController_saveDraft']; + trace?: never; + }; + '/api/projects': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List public projects (PRD products directory) */ + get: operations['ProjectsController_listPublicProjects']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/search': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Search public projects */ + get: operations['ProjectsController_searchPublicProjects']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/featured': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List featured projects */ + get: operations['ProjectsController_listFeaturedProjects']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/{id}/edits': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List edit history for your project */ + get: operations['ProjectsController_listProjectEdits']; + put?: never; + /** Submit a major/minor edit for your project */ + post: operations['ProjectsController_submitProjectEdit']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/{id}/publish': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Publish/submit a project draft (Review & Submit) */ + post: operations['ProjectsController_publishProject']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/me': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List my projects */ + get: operations['ProjectsController_getMyProjects']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/{slug}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get public project by slug */ + get: operations['ProjectsController_getPublicProjectBySlug']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/projects/me/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get my project by ID */ + get: operations['ProjectsController_getProject']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{id}/escrow/publish': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Publish a bounty draft to the events contract + * @description Validates the draft, transitions it to draft_awaiting_funding, and returns an unsigned XDR (EXTERNAL) or the op in PENDING_CONFIRM (MANAGED). Reconciliation transitions the bounty to OPEN on success. + */ + post: operations['OrganizationBountiesEscrowController_publish']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{id}/escrow/cancel': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Cancel an active bounty + * @description Builds a cancel_event contract op. The contract refunds partner contributions first (in full), then the owner residual; or pro-rates partners if escrow is short. On settle, BountyEscrowSubscriber moves the bounty to CANCELLED and stamps the cancel audit columns. + */ + post: operations['OrganizationBountiesEscrowController_cancel']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{id}/escrow/select-winners': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Select winners for a bounty + * @description Builds a select_winners contract op that pays out per the on-chain winner_distribution and bumps each winner's profile credits / reputation / earnings. On settle, BountyEscrowSubscriber moves the bounty to COMPLETED and marks the winning BountySubmission rows accepted with the reward tx hash. + */ + post: operations['OrganizationBountiesEscrowController_selectWinners']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{id}/escrow/ops/{opRowId}/submit-signed': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Submit signed XDR for a previously-built bounty escrow op */ + post: operations['OrganizationBountiesEscrowController_submitSigned']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{id}/escrow/ops/{opRowId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Read the current state of a bounty escrow op */ + get: operations['OrganizationBountiesEscrowController_getOp']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}/escrow/apply': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Apply to a bounty + * @description Builds an apply_to_bounty contract op. EXTERNAL returns unsigned XDR; MANAGED signs and submits. The contract charges the bounty's application_credit_cost via the profile contract on settle. + */ + post: operations['BountyParticipantEscrowController_apply']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}/escrow/withdraw-application': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Withdraw a bounty application + * @description Builds a withdraw_application contract op. Contract refunds half the application_credit_cost via the profile contract on settle. + */ + post: operations['BountyParticipantEscrowController_withdrawApplication']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}/escrow/submit': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit work for a bounty + * @description Builds a submit contract op. Requires the applicant's prior apply_to_bounty to be in active status (contract enforces; the service pre-checks for a cleaner 4xx). + */ + post: operations['BountyParticipantEscrowController_submit']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}/escrow/withdraw-submission': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Withdraw a bounty submission anchor */ + post: operations['BountyParticipantEscrowController_withdrawSubmission']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}/escrow/contribute': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Contribute funds to a bounty pool + * @description Builds an add_funds contract op signed by the caller. Contract enforces a 10 USDC minimum. Anyone with a funded wallet can contribute; this v1 surface requires Boundless auth, so multiple top-ups from the same wallet are allowed (one row per attempt). + */ + post: operations['BountyParticipantEscrowController_contribute']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}/escrow/ops/{opRowId}/submit-signed': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Submit signed XDR for a previously-built participant op */ + post: operations['BountyParticipantEscrowController_submitSigned']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}/escrow/ops/{opRowId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Read the state of a participant op */ + get: operations['BountyParticipantEscrowController_getOp']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{bountyId}/v2/applications': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Submit an application for a LIGHT/HEAVY bounty */ + post: operations['BountyApplicationController_create']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{bountyId}/v2/applications/me': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Read the caller's application for this bounty */ + get: operations['BountyApplicationController_getMine']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{bountyId}/v2/applications/{appId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Withdraw a SUBMITTED application */ + delete: operations['BountyApplicationController_withdraw']; + options?: never; + head?: never; + /** Edit a SUBMITTED application (before shortlist) */ + patch: operations['BountyApplicationController_edit']; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List applications on a bounty */ + get: operations['OrganizationBountyShortlistController_list']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications/select': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Select a single application (Curated Pick / Pitched Pick) */ + post: operations['OrganizationBountyShortlistController_selectForPick']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications/shortlist': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Approve a shortlist (Curated Showdown / Pitched Showdown) */ + post: operations['OrganizationBountyShortlistController_createShortlist']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications/{appId}/decline': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Decline an application with optional reason */ + post: operations['OrganizationBountyShortlistController_decline']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{bountyId}/v2/showdown/join': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Join an Open Showdown bounty */ + post: operations['BountyShowdownJoinController_join']; + /** Leave an Open Showdown before submitting */ + delete: operations['BountyShowdownJoinController_leave']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Public bounty marketplace list */ + get: operations['BountyPublicController_list']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/bounties/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Public bounty detail */ + get: operations['BountyPublicController_findOne']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/grants/{id}/escrow/publish': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Publish a grant draft to the events contract + * @description Validates the draft, transitions to DRAFT_AWAITING_FUNDING, and returns an unsigned XDR (EXTERNAL) or the op in PENDING_CONFIRM (MANAGED). Reconciliation transitions the grant to OPEN on success. + */ + post: operations['OrganizationGrantsEscrowController_publish']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/grants/{id}/escrow/cancel': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Cancel an active grant */ + post: operations['OrganizationGrantsEscrowController_cancel']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/grants/{id}/escrow/select-winners': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Select grant recipients + * @description For Multi release_kind, select_winners records recipients with amount=0 — payouts happen per-milestone via claim_milestone. + */ + post: operations['OrganizationGrantsEscrowController_selectWinners']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/grants/{id}/escrow/claim-milestone': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Pay out a specific milestone for a recipient + * @description Builds a claim_milestone contract op. Contract pays the per-milestone amount to the recipient and bumps profile credits / reputation / earnings. + */ + post: operations['OrganizationGrantsEscrowController_claimMilestone']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/grants/{id}/escrow/ops/{opRowId}/submit-signed': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Submit signed XDR for a grant op */ + post: operations['OrganizationGrantsEscrowController_submitSigned']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/organizations/{organizationId}/grants/{id}/escrow/ops/{opRowId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Read the state of a grant op */ + get: operations['OrganizationGrantsEscrowController_getOp']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/grants/{id}/escrow/contribute': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Contribute funds to a grant pool + * @description Open add_funds op. Contract enforces a 10 USDC minimum. Anyone authenticated can contribute; multiple top-ups from the same wallet are allowed (one row per attempt). + */ + post: operations['GrantContributeEscrowController_contribute']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/grants': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List published grants + * @description Public, page-based list of grant programs. Parallel to /bounties and /hackathons. For a multi-pillar feed (Bounty, Hackathon, Grant, Crowdfunding), use /opportunities instead. + */ + get: operations['GrantsPublicController_list']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/opportunities': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List opportunities across all pillars + * @description Returns a unified, cursor-paginated feed across Bounty, Hackathon, Grant, and Crowdfunding. Pass type= to restrict to one. The cursor is opaque; pass it back as-is to fetch the next page. + */ + get: operations['OpportunitiesController_list']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/subscribe': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Subscribe to the newsletter + * @description Subscribe an email address to the newsletter. Sends a confirmation email (double opt-in). Rate limited to 5 requests per minute. + */ + post: operations['NewsletterController_subscribe']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/confirm/{token}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Confirm newsletter subscription + * @description Confirm a newsletter subscription via the token sent in the confirmation email. Redirects to the frontend on success. + */ + get: operations['NewsletterController_confirmSubscription']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/unsubscribe/{token}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Unsubscribe by token + * @description Unsubscribe from the newsletter using the one-click unsubscribe token from emails. Redirects to the frontend. + */ + get: operations['NewsletterController_unsubscribeByToken']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/unsubscribe': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Unsubscribe by email + * @description Legacy unsubscribe endpoint. Unsubscribe a subscriber by their email address. + */ + post: operations['NewsletterController_unsubscribe']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/preferences': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update subscription preferences + * @description Update topic tag preferences for a subscriber. Valid tags: bounties, hackathons, grants, updates. + */ + patch: operations['NewsletterController_updatePreferences']; + trace?: never; + }; + '/api/newsletter/tracking/open/{campaignId}/{subscriberId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Track email open + * @description Open tracking pixel endpoint. Returns a 1x1 transparent GIF and records the open event. Used in campaign emails. + */ + get: operations['NewsletterController_trackOpen']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/tracking/click/{campaignId}/{subscriberId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Track email link click + * @description Click tracking endpoint. Records the click event and redirects the subscriber to the target URL. + */ + get: operations['NewsletterController_trackClick']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/subscribers': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List newsletter subscribers + * @description Get a paginated list of newsletter subscribers with optional filters by status, source, tags, and search. + */ + get: operations['NewsletterController_getSubscribers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/stats': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get newsletter statistics + * @description Get subscriber counts by status, subscription sources, and campaign statistics (sent, opens, clicks). + */ + get: operations['NewsletterController_getStats']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/export': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Export subscribers as CSV + * @description Download a CSV file of subscribers with optional status and tag filters. + */ + get: operations['NewsletterController_exportSubscribers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/subscribers/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete a subscriber + * @description Permanently delete a newsletter subscriber by ID. + */ + delete: operations['NewsletterController_deleteSubscriber']; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/campaigns': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List newsletter campaigns + * @description Get a paginated list of newsletter campaigns, ordered by most recent first. + */ + get: operations['NewsletterController_getCampaigns']; + put?: never; + /** + * Create a new campaign + * @description Create a new newsletter campaign draft. Use {{name}} placeholder in content for personalization. Target specific subscribers using tags. + */ + post: operations['NewsletterController_createCampaign']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/campaigns/{id}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign details + * @description Get detailed information about a specific campaign, including the most recent 100 send logs. + */ + get: operations['NewsletterController_getCampaign']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/newsletter/campaigns/{id}/send': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Send a campaign + * @description Send a campaign to all matching subscribers. Delivers in batches of 10 with 1-second delays. Cannot re-send an already sent campaign. + */ + post: operations['NewsletterController_sendCampaign']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/queues/dlq/depth': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Current DLQ depth (admin only) */ + get: operations['DlqAdminController_getDepth']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/queues/dlq': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List parked DLQ entries (admin only) */ + get: operations['DlqAdminController_list']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/queues/dlq/{jobId}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Fetch a single parked DLQ entry (admin only) */ + get: operations['DlqAdminController_getOne']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/admin/queues/dlq/{jobId}/replay': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Re-enqueue a parked DLQ entry on its original queue + * @description The DLQ row is removed on success. Replay uses the original queue's normal retry budget, so a job that died after 3 retries gets another 3 retries on replay. + */ + post: operations['DlqAdminController_replay']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/sign-in/social': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign in with a social provider */ + post: operations['socialSignIn']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/get-session': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get the current session */ + get: operations['getSession']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/sign-out': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign out the current user */ + post: operations['signOut']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/sign-up/email': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign up a user using email and password */ + post: operations['signUpWithEmailAndPassword']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/sign-in/email': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign in with email and password */ + post: operations['signInEmail']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/reset-password': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Reset the password for a user */ + post: operations['resetPassword']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/verify-password': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify the current user's password */ + post: operations['verifyPassword']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/verify-email': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Verify the email of the user */ + get: { + parameters: { + query: { + /** @description The token to verify the email */ + token: string; + /** @description The URL to redirect to after email verification */ + callbackURL?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user: components['schemas']['User']; + /** @description Indicates if the email was verified successfully */ + status: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/send-verification-email': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Send a verification email to the user */ + post: operations['sendVerificationEmail']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/change-email': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations['changeEmail']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/change-password': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Change the password of the user */ + post: operations['changePassword']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/update-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Update the current user */ + post: operations['updateUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/delete-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Delete the user */ + post: operations['deleteUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/request-password-reset': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Send a password reset email to the user */ + post: operations['requestPasswordReset']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/reset-password/{token}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Redirects the user to the callback URL with the token */ + get: operations['resetPasswordCallback']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/list-sessions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List all active sessions for the user */ + get: operations['listUserSessions']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/revoke-session': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Revoke a single session */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': { + /** @description The token to revoke */ + token: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if the session was revoked successfully */ + status: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/revoke-sessions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Revoke all sessions for the user */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': Record; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if all sessions were revoked successfully */ + status: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/revoke-other-sessions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Revoke all other sessions for the user except the current one */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': Record; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if all other sessions were revoked successfully */ + status: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/link-social': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Link a social account to the user */ + post: operations['linkSocialAccount']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/list-accounts': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List all accounts linked to the user */ + get: operations['listUserAccounts']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/delete-user/callback': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Callback to complete user deletion with verification token */ + get: { + parameters: { + query?: { + token?: string; + callbackURL?: string | null; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User successfully deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if the deletion was successful */ + success: boolean; + /** + * @description Confirmation message + * @enum {string} + */ + message: 'User deleted'; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/unlink-account': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Unlink an account */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + providerId: string; + accountId?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/refresh-token': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Refresh the access token using a refresh token */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The provider ID for the OAuth provider */ + providerId: string; + /** @description The account ID associated with the refresh token */ + accountId?: string | null; + /** @description The user ID associated with the account */ + userId?: string | null; + }; + }; + }; + responses: { + /** @description Access token refreshed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + tokenType?: string; + idToken?: string; + accessToken?: string; + refreshToken?: string; + /** Format: date-time */ + accessTokenExpiresAt?: string; + /** Format: date-time */ + refreshTokenExpiresAt?: string; + }; + }; + }; + /** @description Invalid refresh token or provider configuration */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/get-access-token': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Get a valid access token, doing a refresh if needed */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The provider ID for the OAuth provider */ + providerId: string; + /** @description The account ID associated with the refresh token */ + accountId?: string | null; + /** @description The user ID associated with the account */ + userId?: string | null; + }; + }; + }; + responses: { + /** @description A Valid access token */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + tokenType?: string; + idToken?: string; + accessToken?: string; + /** Format: date-time */ + accessTokenExpiresAt?: string; + }; + }; + }; + /** @description Invalid refresh token or provider configuration */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/account-info': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get the account info provided by the provider */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user: { + id: string; + name?: string; + email?: string; + image?: string; + emailVerified: boolean; + }; + data: { + [key: string]: unknown; + }; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/ok': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Check if the API is working */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description API is working */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if the API is working */ + ok: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/error': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Displays an error page */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'text/html': string; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/sign-in/username': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign in with username */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The username of the user */ + username: string; + /** @description The password of the user */ + password: string; + /** @description Remember the user session */ + rememberMe?: boolean | null; + /** @description The URL to redirect to after email verification */ + callbackURL?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Session token for the authenticated session */ + token: string; + user: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Unprocessable Entity. Validation error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/is-username-available': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The username to check */ + username: string; + }; + }; + }; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/get-totp-uri': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Use this endpoint to get the TOTP URI */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description User password */ + password: string; + }; + }; + }; + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + totpURI?: string; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/verify-totp': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify two factor TOTP */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The otp code to verify. Eg: "012345" */ + code: string; + /** @description If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true */ + trustDevice?: boolean | null; + }; + }; + }; + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/send-otp': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Send two factor OTP to the user */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/verify-otp': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify two factor OTP */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The otp code to verify. Eg: "012345" */ + code: string; + trustDevice?: boolean | null; + }; + }; + }; + responses: { + /** @description Two-factor OTP verified successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Session token for the authenticated session */ + token: string; + /** @description The authenticated user object */ + user: { + /** @description Unique identifier of the user */ + id: string; + /** + * Format: email + * @description User's email address + */ + email?: string | null; + /** @description Whether the email is verified */ + emailVerified?: boolean | null; + /** @description User's name */ + name?: string | null; + /** + * Format: uri + * @description User's profile image URL + */ + image?: string | null; + /** + * Format: date-time + * @description Timestamp when the user was created + */ + createdAt: string; + /** + * Format: date-time + * @description Timestamp when the user was last updated + */ + updatedAt: string; + }; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/verify-backup-code': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify a backup code for two-factor authentication */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description A backup code to verify. Eg: "123456" */ + code: string; + /** @description If true, the session cookie will not be set. */ + disableSession?: boolean | null; + /** @description If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true */ + trustDevice?: boolean | null; + }; + }; + }; + responses: { + /** @description Backup code verified successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description The authenticated user object with two-factor details */ + user: { + /** @description Unique identifier of the user */ + id: string; + /** + * Format: email + * @description User's email address + */ + email?: string | null; + /** @description Whether the email is verified */ + emailVerified?: boolean | null; + /** @description User's name */ + name?: string | null; + /** + * Format: uri + * @description User's profile image URL + */ + image?: string | null; + /** @description Whether two-factor authentication is enabled for the user */ + twoFactorEnabled: boolean; + /** + * Format: date-time + * @description Timestamp when the user was created + */ + createdAt: string; + /** + * Format: date-time + * @description Timestamp when the user was last updated + */ + updatedAt: string; + }; + /** @description The current session object, included unless disableSession is true */ + session: { + /** @description Session token */ + token: string; + /** @description ID of the user associated with the session */ + userId: string; + /** + * Format: date-time + * @description Timestamp when the session was created + */ + createdAt: string; + /** + * Format: date-time + * @description Timestamp when the session expires + */ + expiresAt: string; + }; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/generate-backup-codes': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Generate new backup codes for two-factor authentication */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The users password. */ + password: string; + }; + }; + }; + responses: { + /** @description Backup codes generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** + * @description Indicates if the backup codes were generated successfully + * @enum {boolean} + */ + status: true; + /** @description Array of generated backup codes in plain text */ + backupCodes: string[]; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/enable': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Use this endpoint to enable two factor authentication. This will generate a TOTP URI and backup codes. Once the user verifies the TOTP URI, the two factor authentication will be enabled. */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description User password */ + password: string; + /** @description Custom issuer for the TOTP URI */ + issuer?: string | null; + }; + }; + }; + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description TOTP URI */ + totpURI?: string; + /** @description Backup codes */ + backupCodes?: string[]; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/two-factor/disable': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Use this endpoint to disable two factor authentication. */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description User password */ + password: string; + }; + }; + }; + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/one-tap/callback': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Use this endpoint to authenticate with Google One Tap */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Google ID token, which the client obtains from the One Tap API */ + idToken: string; + }; + }; + }; + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + session?: components['schemas']['Session']; + user?: components['schemas']['User']; + }; + }; + }; + /** @description Invalid token */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/email-otp/send-verification-otp': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Send a verification OTP to an email */ + post: operations['sendEmailVerificationOTP']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/email-otp/check-verification-otp': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify an email with an OTP */ + post: operations['verifyEmailWithOTP']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/email-otp/verify-email': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify email with OTP */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address to verify */ + email: string; + /** @description OTP to verify */ + otp: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** + * @description Indicates if the verification was successful + * @enum {boolean} + */ + status: true; + /** @description Session token if autoSignInAfterVerification is enabled, otherwise null */ + token: string | null; + user: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/sign-in/email-otp': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign in with email and OTP */ + post: operations['signInWithEmailOTP']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/email-otp/request-password-reset': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Request password reset with email and OTP */ + post: operations['requestPasswordResetWithEmailOTP']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/forget-password/email-otp': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Deprecated: Use /email-otp/request-password-reset instead. */ + post: operations['forgetPasswordWithEmailOTP']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/email-otp/reset-password': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Reset password with email and OTP */ + post: operations['resetPasswordWithEmailOTP']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/create': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Create an organization */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The name of the organization */ + name: string; + /** @description The slug of the organization */ + slug: string; + /** @description The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: "user-id" */ + userId?: string | null; + /** @description The logo of the organization */ + logo?: string | null; + /** @description The metadata of the organization */ + metadata?: string | null; + /** @description Whether to keep the current active organization active after creating a new one. Eg: true */ + keepCurrentActiveOrganization?: boolean | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Organization']; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/update': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Update an organization */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + data: { + /** @description The name of the organization */ + name?: string | null; + /** @description The slug of the organization */ + slug?: string | null; + /** @description The logo of the organization */ + logo?: string | null; + /** @description The metadata of the organization */ + metadata?: string | null; + }; + /** @description The organization ID. Eg: "org-id" */ + organizationId?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Organization']; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/delete': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Delete an organization */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The organization id to delete */ + organizationId: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': string; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/set-active': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Set the active organization */ + post: operations['setActiveOrganization']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/get-full-organization': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get the full organization */ + get: operations['getOrganization']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/list': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List all organizations */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Organization'][]; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/invite-member': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Create an invitation to an organization */ + post: operations['createOrganizationInvitation']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/cancel-invitation': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The ID of the invitation to cancel */ + invitationId: string; + }; + }; + }; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/accept-invitation': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Accept an invitation to an organization */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The ID of the invitation to accept */ + invitationId: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + invitation?: Record; + member?: Record; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/get-invitation': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get an invitation by ID */ + get: { + parameters: { + query?: { + id?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + id: string; + email: string; + role: string; + organizationId: string; + inviterId: string; + status: string; + expiresAt: string; + organizationName: string; + organizationSlug: string; + inviterEmail: string; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/reject-invitation': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Reject an invitation to an organization */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The ID of the invitation to reject */ + invitationId: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + invitation?: Record; + member?: Record | null; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/list-invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/get-active-member': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get the member details of the active organization */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + id: string; + userId: string; + organizationId: string; + role: string; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/check-slug': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The organization slug to check. Eg: "my-org" */ + slug: string; + }; + }; + }; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/remove-member': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Remove a member from an organization */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The ID or email of the member to remove */ + memberIdOrEmail: string; + /** @description The ID of the organization to remove the member from. If not provided, the active organization will be used. Eg: "org-id" */ + organizationId?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + member: { + id: string; + userId: string; + organizationId: string; + role: string; + }; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/update-member-role': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Update the role of a member in an organization */ + post: operations['updateOrganizationMemberRole']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/leave': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The organization Id for the member to leave. Eg: "organization-id" */ + organizationId: string; + }; + }; + }; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/list-user-invitations': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List all invitations a user has received */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + id: string; + email: string; + role: string; + organizationId: string; + organizationName: string; + /** @description The ID of the user who created the invitation */ + inviterId: string; + /** @description The ID of the team associated with the invitation */ + teamId?: string | null; + status: string; + expiresAt: string; + createdAt: string; + }[]; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/list-members': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/get-active-member-role': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/organization/has-permission': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Check if the user has permission */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': { + /** + * @deprecated + * @description The permission to check + */ + permission?: Record; + /** @description The permission to check */ + permissions: Record; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + error?: string; + success: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/set-role': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Set the role of a user */ + post: operations['setUserRole']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/get-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get an existing user */ + get: operations['getUser']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/create-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Create a new user */ + post: operations['createUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/update-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Update a user's details */ + post: operations['updateUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/list-users': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List users */ + get: operations['listUsers']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/list-user-sessions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description List user sessions */ + post: operations['listUserSessions']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/unban-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Unban a user */ + post: operations['unbanUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/ban-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Ban a user */ + post: operations['banUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/impersonate-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Impersonate a user */ + post: operations['impersonateUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/stop-impersonating': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/revoke-user-session': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Revoke a user session */ + post: operations['revokeUserSession']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/revoke-user-sessions': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Revoke all user sessions */ + post: operations['revokeUserSessions']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/remove-user': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Delete a user and all their sessions and accounts. Cannot be undone. */ + post: operations['removeUser']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/set-user-password': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Set a user's password */ + post: operations['setUserPassword']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/admin/has-permission': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Check if the user has permission */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': { + /** + * @deprecated + * @description The permission to check + */ + permission?: Record; + /** @description The permission to check */ + permissions: Record; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + error?: string; + success: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/passkey/generate-register-options': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Generate registration options for a new passkey */ + get: operations['generatePasskeyRegistrationOptions']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/passkey/generate-authenticate-options': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Generate authentication options for a passkey */ + get: operations['passkeyGenerateAuthenticateOptions']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/passkey/verify-registration': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify registration of a new passkey */ + post: operations['passkeyVerifyRegistration']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/passkey/verify-authentication': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify authentication of a passkey */ + post: operations['passkeyVerifyAuthentication']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/passkey/list-user-passkeys': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List all passkeys for the authenticated user */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Passkeys retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Passkey'][]; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/passkey/delete-passkey': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Delete a specific passkey */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The ID of the passkey to delete. Eg: "some-passkey-id" */ + id: string; + }; + }; + }; + responses: { + /** @description Passkey deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates whether the deletion was successful */ + status: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/passkey/update-passkey': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Update a specific passkey's name */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The ID of the passkey which will be updated. Eg: "passkey-id" */ + id: string; + /** @description The new name which the passkey will be updated to. Eg: "my-new-passkey-name" */ + name: string; + }; + }; + }; + responses: { + /** @description Passkey updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + passkey: components['schemas']['Passkey']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/sign-in/magic-link': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign in with magic link */ + post: operations['signInWithMagicLink']; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/api/auth/magic-link/verify': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Verify magic link */ + get: operations['verifyMagicLink']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + NotificationPreferencesDto: Record; + UpdatePrivacySettingsDto: { + /** + * @description Public profile + * @example true + */ + publicProfile: boolean; + /** + * @description Email visibility + * @example true + */ + emailVisibility: boolean; + /** + * @description Location visibility + * @example true + */ + locationVisibility: boolean; + /** + * @description Company visibility + * @example true + */ + companyVisibility: boolean; + /** + * @description Website visibility + * @example true + */ + websiteVisibility: boolean; + /** + * @description Social links visibility + * @example true + */ + socialLinksVisibility: boolean; + }; + UpdateAppearanceSettingsDto: { + /** + * @description Theme + * @example light + * @enum {string} + */ + theme: 'light' | 'dark' | 'auto'; + }; + PublicEarningsSummaryDto: { + /** + * @description All-time total earned (normalized, e.g. USDC 7 decimals) + * @example 50000 + */ + totalEarned: number; + }; + EarningsBreakdownDto: { + /** + * @description Total from hackathons + * @example 20000 + */ + hackathons: number; + /** + * @description Total from grants + * @example 10000 + */ + grants: number; + /** + * @description Total from crowdfunding + * @example 15000 + */ + crowdfunding: number; + /** + * @description Total from bounties + * @example 5000 + */ + bounties: number; + }; + PublicEarningActivityDto: { + /** @description Unique activity id */ + id: string; + /** + * @description Earnings source category + * @enum {string} + */ + source: 'hackathons' | 'grants' | 'crowdfunding' | 'bounties'; + /** + * @description Human-readable title + * @example Winner of Stellar Hackathon Q1 + */ + title: string; + /** + * @description Amount (normalized) + * @example 5000 + */ + amount: number; + /** + * @description Currency code + * @example USDC + */ + currency: string; + /** + * @description When the earning occurred (ISO date string) + * @example 2024-01-19T14:30:00Z + */ + occurredAt: string; + }; + PublicEarningsResponseDto: { + summary: components['schemas']['PublicEarningsSummaryDto']; + breakdown: components['schemas']['EarningsBreakdownDto']; + /** @description Verified activity history (completed only) */ + activities: components['schemas']['PublicEarningActivityDto'][]; + }; + EarningsSummaryDto: { + /** + * @description All-time total earned (normalized, e.g. USDC 7 decimals) + * @example 50000 + */ + totalEarned: number; + /** + * @description Amount currently claimable / pending withdrawal + * @example 10000 + */ + pendingWithdrawal: number; + /** + * @description Amount already paid out (completed withdrawals) + * @example 40000 + */ + completedWithdrawal: number; + }; + EarningActivityDto: { + /** @description Unique activity id (e.g. submissionId or milestoneId) */ + id: string; + /** + * @description Earnings source category + * @enum {string} + */ + source: 'hackathons' | 'grants' | 'crowdfunding' | 'bounties'; + /** + * @description Human-readable title + * @example Winner of Stellar Hackathon Q1 + */ + title: string; + /** + * @description Amount (normalized) + * @example 5000 + */ + amount: number; + /** + * @description Currency code + * @example USDC + */ + currency: string; + /** + * @description Activity status + * @enum {string} + */ + status: 'pending' | 'claimable' | 'completed'; + /** + * @description When the earning occurred (ISO date string) + * @example 2024-01-19T14:30:00Z + */ + occurredAt: string; + /** @description Entity id for claim (e.g. submissionId, milestoneId) */ + entityId?: string; + }; + EarningsResponseDto: { + summary: components['schemas']['EarningsSummaryDto']; + breakdown: components['schemas']['EarningsBreakdownDto']; + /** @description Activity feed */ + activities: components['schemas']['EarningActivityDto'][]; + }; + WithdrawItemDto: { + /** + * @description Source of the claimable (crowdfunding or grants; user claims release to wallet) + * @enum {string} + */ + source: 'crowdfunding' | 'grants'; + /** @description Entity id (e.g. milestoneId for crowdfunding or grants) */ + entityId: string; + }; + WithdrawRequestDto: { + /** @description Items to claim (source + entityId). Only crowdfunding supported (grants not yet). Payout goes to user's linked wallet. */ + items?: components['schemas']['WithdrawItemDto'][]; + }; + ConfirmReleaseDto: { + /** @description Signed XDR from creator/grantee wallet (release milestone transaction from real wallet) */ + signedXdr: string; + /** @description Entity id (e.g. crowdfunding milestone id) */ + entityId: string; + /** + * @description Source of the claimable (only crowdfunding supported for confirm-release) + * @example crowdfunding + * @enum {string} + */ + source: 'crowdfunding'; + }; + ConfirmReleaseResponseDto: { + /** + * @description Whether the release was submitted successfully + * @example true + */ + success: boolean; + /** @description Transaction hash once the release is executed on-chain */ + transactionHash?: string; + /** + * @description Human-readable message + * @example Release submitted successfully + */ + message?: string; + }; + DashboardUserStatsDto: { + followers: number; + following: number; + }; + DashboardUserDto: { + id: string; + name: string | null; + email: string; + username: string | null; + displayUsername: string | null; + image: string | null; + role: string; + /** Format: date-time */ + createdAt: string; + stats?: components['schemas']['DashboardUserStatsDto']; + }; + UserStatsDto: { + projectsCreated: number; + projectsFunded: number; + totalContributed: number; + commentsPosted: number; + votes: number; + grants: number; + hackathons: number; + followers: number; + following: number; + reputation: number; + communityScore: number; + }; + ChartDataPointDto: { + /** @description Date in YYYY-MM-DD format */ + date: string; + /** @description Count for that date */ + count: number; + }; + ChartDto: { + data: components['schemas']['ChartDataPointDto'][]; + }; + ActivitiesGraphDto: { + data: components['schemas']['ChartDataPointDto'][]; + }; + ActivityProjectDto: { + id: string; + title: string; + banner?: string | null; + logo?: string | null; + }; + ActivityOrganizationDto: { + id: string; + name: string; + }; + RecentActivityDto: { + id: string; + type: string; + userId: string; + projectId?: string | null; + organizationId?: string | null; + /** Format: date-time */ + createdAt: string; + project?: components['schemas']['ActivityProjectDto']; + organization?: components['schemas']['ActivityOrganizationDto']; + }; + DashboardDto: { + /** @description User profile data */ + user: components['schemas']['DashboardUserDto']; + stats: components['schemas']['UserStatsDto']; + chart: components['schemas']['ChartDto']; + activitiesGraph: components['schemas']['ActivitiesGraphDto']; + /** @description Recent activities */ + recentActivities: components['schemas']['RecentActivityDto'][]; + }; + UpdateProfileDto: Record; + UpdateUserDto: Record; + UploadResponseDto: Record; + MultipleUploadResponseDto: Record; + FileInfoResponseDto: Record; + SearchFilesResponseDto: Record; + OptimizedUrlResponseDto: Record; + ResponsiveUrlsResponseDto: Record; + UsageStatsResponseDto: Record; + RegisterDto: Record; + LoginDto: Record; + RefreshTokenDto: Record; + VerifySignatureDto: Record; + CreateConversationDto: { + /** @description User ID of the other participant */ + otherUserId: string; + }; + CreateMessageDto: { + /** @description Message text */ + body: string; + }; + ContactDto: Record; + CreateCampaignDto: { + /** + * @description Title of the campaign + * @example Web3 Campaign + */ + title: string; + /** + * @description Logo of the campaign + * @example https://example.com/logo.png + */ + logo: string; + /** + * @description Vision of the campaign + * @example Web3 Campaign + */ + vision: string; + /** + * @description Banner image URL of the campaign + * @example https://example.com/banner.png + */ + banner: string; + /** + * @description Category of the campaign + * @example web3 + */ + category: string; + /** + * @description Details of the campaign + * @example Web3 Campaign + */ + details: string; + /** + * @description Funding amount of the campaign + * @example 1000 + */ + fundingAmount: number; + /** + * @description Github URL of the campaign + * @example https://github.com/example/project + */ + githubUrl: string; + /** + * @description Gitlab URL of the campaign + * @example https://gitlab.com/example/project + */ + gitlabUrl: string; + /** + * @description Bitbucket URL of the campaign + * @example https://bitbucket.com/example/project + */ + bitbucketUrl: string; + /** + * @description Project website of the campaign + * @example https://example.com/project + */ + projectWebsite: string; + /** + * @description Demo video of the campaign + * @example https://example.com/demo.mp4 + */ + demoVideo: string; + /** + * @description Milestones of the campaign + * @example [ + * { + * "name": "Milestone 1", + * "description": "Milestone 1 description", + * "startDate": "2025-01-01", + * "endDate": "2025-01-02", + * "amount": 1000 + * } + * ] + */ + milestones: string[]; + /** + * @description Team of the campaign + * @example [ + * { + * "name": "John Doe", + * "role": "Developer", + * "email": "john.doe@example.com", + * "linkedin": "https://linkedin.com/in/john-doe", + * "twitter": "https://twitter.com/john-doe" + * } + * ] + */ + team: string[]; + /** + * @description Contact of the campaign + * @example { + * "primary": "john.doe", + * "backup": "john.doe@example.com" + * } + */ + contact: components['schemas']['ContactDto']; + /** + * @description Social links of the campaign + * @example [ + * { + * "platform": "twitter", + * "url": "https://twitter.com/john-doe" + * } + * ] + */ + socialLinks: string[]; + /** + * @description Escrow contract ID for the campaign + * @example CCAJPWPKSR6FY5Q5RYT5E3EIZQNDMDFYVVKJ656C5SUOIXQOQ4JQVWGV + */ + escrowId?: string; + /** + * @description Transaction hash of the deployed escrow contract + * @example a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 + */ + transactionHash?: string; + }; + UpdateCampaignDto: { + /** + * @description Title of the campaign + * @example Web3 Campaign + */ + title?: string; + /** + * @description Logo of the campaign + * @example https://example.com/logo.png + */ + logo?: string; + /** + * @description Vision of the campaign + * @example Web3 Campaign + */ + vision?: string; + /** + * @description Banner image URL of the campaign + * @example https://example.com/banner.png + */ + banner?: string; + /** + * @description Category of the campaign + * @example web3 + */ + category?: string; + /** + * @description Details of the campaign + * @example Web3 Campaign + */ + details?: string; + /** + * @description Funding amount of the campaign + * @example 1000 + */ + fundingAmount?: number; + /** + * @description Github URL of the campaign + * @example https://github.com/example/project + */ + githubUrl?: string; + /** + * @description Gitlab URL of the campaign + * @example https://gitlab.com/example/project + */ + gitlabUrl?: string; + /** + * @description Bitbucket URL of the campaign + * @example https://bitbucket.com/example/project + */ + bitbucketUrl?: string; + /** + * @description Project website of the campaign + * @example https://example.com/project + */ + projectWebsite?: string; + /** + * @description Demo video of the campaign + * @example https://example.com/demo.mp4 + */ + demoVideo?: string; + /** + * @description Milestones of the campaign + * @example [ + * { + * "name": "Milestone 1", + * "description": "Milestone 1 description", + * "startDate": "2025-01-01", + * "endDate": "2025-01-02", + * "amount": 1000 + * } + * ] + */ + milestones?: string[]; + /** + * @description Team of the campaign + * @example [ + * { + * "name": "John Doe", + * "role": "Developer", + * "email": "john.doe@example.com", + * "linkedin": "https://linkedin.com/in/john-doe", + * "twitter": "https://twitter.com/john-doe" + * } + * ] + */ + team?: string[]; + /** + * @description Contact of the campaign + * @example { + * "primary": "john.doe", + * "backup": "john.doe@example.com" + * } + */ + contact?: components['schemas']['ContactDto']; + /** + * @description Social links of the campaign + * @example [ + * { + * "platform": "twitter", + * "url": "https://twitter.com/john-doe" + * } + * ] + */ + socialLinks?: string[]; + /** + * @description Escrow contract ID for the campaign + * @example CCAJPWPKSR6FY5Q5RYT5E3EIZQNDMDFYVVKJ656C5SUOIXQOQ4JQVWGV + */ + escrowId?: string; + /** + * @description Transaction hash of the deployed escrow contract + * @example a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 + */ + transactionHash?: string; + }; + UpdateEscrowDto: { + /** + * @description Transaction hash of the deployed escrow contract + * @example a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 + */ + transactionHash?: string; + /** + * @description Escrow contract address + * @example CCAJPWPKSR6FY5Q5RYT5E3EIZQNDMDFYVVKJ656C5SUOIXQOQ4JQVWGV + */ + escrowAddress?: string; + /** + * @description Trustless Work status + * @example deployed + * @enum {string} + */ + trustlessWorkStatus?: 'pending' | 'deployed' | 'funded' | 'failed'; + /** + * @description Escrow type + * @example multi-release + * @enum {string} + */ + escrowType?: 'single-release' | 'multi-release'; + }; + InviteTeamMemberDto: { + /** + * @description The email address of the team member to invite + * @example user@example.com + */ + email: string; + /** + * @description The role of the team member in the campaign + * @example Developer + */ + role: string; + }; + ContributeCampaignDto: { + /** + * @description Amount of the contribution + * @example 100 + */ + amount: number; + /** + * @description Optional message from the contributor + * @example I love this campaign! + */ + message?: string; + /** + * @description Whether to make this contribution anonymous + * @default false + * @example false + */ + anonymous: boolean; + }; + ValidateMilestoneSubmissionDto: { + /** + * @description Array of proof of work file URLs (documents, images, reports, etc.) - must be valid URLs with http, https, or ipfs protocol + * @example [ + * "https://example.com/report.pdf", + * "https://example.com/screenshot.png" + * ] + */ + proofOfWorkFiles: string[]; + /** + * @description Array of proof of work links (GitHub PRs, demos, deployed sites, etc.) - must be valid URLs + * @example [ + * "https://github.com/user/repo/pull/123", + * "https://demo.example.com" + * ] + */ + proofOfWorkLinks: string[]; + /** + * @description Additional notes about the submission - optional but must be at least 10 characters if provided + * @example Successfully deployed the MVP with all core features implemented and tested. + */ + submissionNotes?: string; + }; + UpdateMilestoneDto: { + /** @description Array of proof of work file URLs (documents, images, etc.) */ + proofOfWorkFiles: string[]; + /** @description Array of proof of work links (GitHub PRs, demos, etc.) */ + proofOfWorkLinks: string[]; + /** @description Additional notes about the submission */ + submissionNotes?: string; + }; + PublishCrowdfundingEscrowDto: { + /** + * @description Stellar G-address that signs create_event. Strictly the builder's Boundless abstracted wallet (D9). MANAGED funding is the only path. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + builderAddress: string; + /** + * @description Whitelisted SAC token contract (USDC by default). + * @example CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA + */ + tokenAddress: string; + /** + * @description Funding goal in token-native units (e.g. 5000 = 5000 USDC). Informational on chain; backers determine the actual raised total. + * @example 5000 + */ + fundingGoal: string; + /** + * @description Number of milestones for ReleaseKind::Multi(n). + * @example 3 + */ + nMilestones: number; + /** + * @description Funding deadline as Unix seconds. + * @example 1735689600 + */ + fundingDeadline: number; + /** @description Override content URI. */ + contentUri?: string; + }; + CancelCrowdfundingEscrowDto: { + /** @description Builder G-address. */ + builderAddress: string; + }; + ClaimCrowdfundingMilestoneDto: { + /** @description Builder G-address (must match campaign). */ + builderAddress: string; + /** @description Crowdfunding milestone id. */ + crowdfundingMilestoneId: string; + }; + ContributeCrowdfundingDto: { + /** + * @description G-address that signs add_funds. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + contributorAddress: string; + /** + * @description Wallet origin: BOUNDLESS uses the managed signer; EXTERNAL returns an unsigned XDR for the connected wallet (D9). + * @example BOUNDLESS + * @enum {string} + */ + walletOrigin: 'BOUNDLESS' | 'EXTERNAL'; + /** + * @description Amount in token-native units (10 USDC minimum). + * @example 25 + */ + amount: string; + /** @description Optional message attached. */ + message?: string; + /** + * @description Hide displayName / usernameSnapshot if true. + * @default false + */ + anonymous: boolean; + }; + CastCrowdfundingVoteDto: { + /** + * @description UP supports the campaign, DOWN opposes it. + * @example UP + * @enum {string} + */ + choice: 'UP' | 'DOWN'; + }; + ApproveCrowdfundingCampaignDto: { + /** + * @description The user delegated to validate this campaign's milestones. D6=A: exactly one reviewer per campaign, assigned at approval time. + * @example user_1234567890 + */ + delegatedReviewerId: string; + }; + RejectCrowdfundingCampaignDto: { + /** @description Reason for rejection; surfaced to the builder. */ + reason?: string; + }; + PauseCrowdfundingCampaignDto: { + /** @description Reason for the pause. */ + reason?: string; + }; + ReclaimDormantDto: { + /** + * @description Minimum days a wallet must have been idle to be eligible. Default 90. + * @example 90 + */ + minIdleDays?: number; + /** + * @description Maximum number of wallets to reclaim in this call. Hard-capped at 100. + * @example 25 + */ + maxToProcess?: number; + /** + * @description When true (default), report what would be reclaimed without submitting transactions. Set false to actually merge accounts. + * @example true + */ + dryRun?: boolean; + }; + AddTrustlineDto: { + /** + * @description Asset code to add a trustline for (e.g. USDC, EURC) + * @example USDC + */ + assetCode: string; + }; + UserSendDto: { + /** + * @description Stellar destination public key (G...) + * @example GABCD... + */ + destinationPublicKey: string; + /** + * @description Amount to send (positive number) + * @example 100.5 + */ + amount: number; + /** + * @description Asset code (XLM, USDC, EURC, etc.) + * @example USDC + */ + currency: string; + /** @description Memo (required by some exchanges). Max 28 bytes UTF-8. */ + memo?: string; + /** @description If true, request fails when memo is missing (e.g. exchange requires it) */ + memoRequired?: boolean; + /** @description Idempotency key to prevent duplicate sends */ + idempotencyKey?: string; + }; + SendPayoutDto: { + /** + * @description Stellar destination public key (G...) + * @example GABCD... + */ + destinationPublicKey: string; + /** + * @description Amount to send (positive number) + * @example 100.5 + */ + amount: number; + /** + * @description Asset code (XLM, USDC, EURC, etc. – must be supported on network) + * @example USDC + */ + currency: string; + /** @description Memo (required by some exchanges). Max 28 bytes UTF-8. */ + memo?: string; + /** + * @description Memo type + * @enum {string} + */ + memoType?: 'text' | 'id'; + /** @description If true, request fails when memo is missing (e.g. exchange requires it) */ + memoRequired?: boolean; + /** @description Idempotency key to prevent duplicate payouts */ + idempotencyKey?: string; + /** @description Reference for audit (e.g. earnings-payout-123) */ + reference?: string; + }; + CreateCommentDto: { + /** + * @description Comment content + * @example This is a great project! + */ + content: string; + /** + * @description Entity type for the comment + * @example PROJECT + * @enum {string} + */ + entityType: + | 'PROJECT' + | 'BOUNTY' + | 'CROWDFUNDING_CAMPAIGN' + | 'GRANT' + | 'GRANT_APPLICATION' + | 'HACKATHON' + | 'HACKATHON_SUBMISSION' + | 'BLOG_POST'; + /** + * @description Entity ID for the comment + * @example cm12345abcde + */ + entityId: string; + /** + * @description Parent comment ID for threaded replies + * @example cm12345abcde + */ + parentId?: string; + }; + UpdateCommentDto: Record; + AddReactionDto: { + /** + * @description Type of reaction + * @example LIKE + * @enum {string} + */ + reactionType: + | 'LIKE' + | 'DISLIKE' + | 'LOVE' + | 'LAUGH' + | 'THUMBS_UP' + | 'THUMBS_DOWN' + | 'FIRE' + | 'ROCKET'; + }; + ReportCommentDto: { + /** + * @description Reason for reporting the comment + * @example SPAM + * @enum {string} + */ + reason: + | 'SPAM' + | 'HARASSMENT' + | 'HATE_SPEECH' + | 'INAPPROPRIATE_CONTENT' + | 'COPYRIGHT_VIOLATION' + | 'OTHER'; + /** + * @description Additional details about the report + * @example This comment contains unsolicited advertising + */ + description?: string; + }; + ResolveReportDto: { + /** + * @description Resolution status for the report + * @example RESOLVED + * @enum {string} + */ + status: 'PENDING' | 'REVIEWED' | 'RESOLVED' | 'DISMISSED'; + /** + * @description Moderator notes about the resolution + * @example Comment was reviewed and found to violate community guidelines + */ + resolution?: string; + }; + HackathonsListResponseDto: Record; + FeeEstimateResponseDto: { + /** + * @description Total prize pool (USDC) + * @example 5000 + */ + totalPool: number; + /** + * @description Fee rate as decimal + * @example 0.023 + */ + feeRate: number; + /** + * @description Fee rate as percentage + * @example 2.3 + */ + feeRatePercent: number; + /** + * @description Fee amount (USDC) + * @example 115 + */ + feeAmount: number; + /** + * @description Total to pay (prize pool + fee) + * @example 5115 + */ + totalFunds: number; + /** + * @description Display label for the fee + * @example Platform Fee (2.3%) + */ + feeLabel: string; + }; + ParticipantDto: { + /** @description Username of the participant */ + username: string; + /** @description Avatar URL of the participant */ + avatar?: Record; + }; + HackathonWinnerDto: { + /** @description Rank of the winner (1, 2, 3, etc.) */ + rank: number; + /** @description Name of the project */ + projectName: string; + /** @description Name of the team */ + teamName?: Record; + /** @description Logo of the project */ + logo?: Record; + /** @description List of participants */ + participants: components['schemas']['ParticipantDto'][]; + /** @description Prize information */ + prize: string; + /** @description Submission ID */ + submissionId: string; + }; + HackathonWinnersResponseDto: { + /** @description Hackathon ID */ + hackathonId: string; + /** @description List of winners */ + winners: components['schemas']['HackathonWinnerDto'][]; + }; + PublicAggregatedJudgingResultDto: { + submissionId: string; + projectName: string; + teamId?: Record; + participantId: string; + status: string; + /** Format: date-time */ + submittedAt: string; + averageScore: number; + totalScore: number; + judgeCount: number; + expectedJudgeCount: number; + judgingProgress: string; + rank?: Record; + isComplete: boolean; + isPending: boolean; + hasDisagreement: boolean; + }; + JudgingResultsMetadataDto: { + sortedBy: string; + includesVariance: boolean; + includesIndividualScores: boolean; + includesProgressTracking: boolean; + onlyWinners?: boolean; + }; + PublicJudgingResultsResponseDto: { + hackathonId: string; + totalSubmissions: number; + submissionsScoredCount: number; + submissionsPendingCount: number; + averageScoreAcrossAll: number; + resultsPublished: boolean; + judgesAssigned: number; + results: components['schemas']['PublicAggregatedJudgingResultDto'][]; + /** Format: date-time */ + generatedAt: string; + /** @description Manual winner assignments override (submissionId -> rank) */ + winnerOverrides?: { + [key: string]: number; + }; + metadata: components['schemas']['JudgingResultsMetadataDto']; + }; + CreatorRelationDto: { + id: string; + name: string; + username?: string; + image?: string; + }; + OrganizationRelationDto: { + id: string; + name: string; + logo?: string; + slug?: string; + }; + HackathonResponseDto: { + createdBy: components['schemas']['CreatorRelationDto']; + organization?: components['schemas']['OrganizationRelationDto']; + }; + ParticipationResponseDto: Record; + ParticipantResponseDto: Record; + HackathonParticipantsResponseDto: { + participants: components['schemas']['ParticipantResponseDto'][]; + }; + TeamMemberDto: { + /** + * @description User ID of the team member + * @example user_1234567890 + */ + userId: string; + /** + * @description Name of the team member + * @example John Doe + */ + name: string; + /** + * @description Username of the team member + * @example johndoe + */ + username?: string; + /** + * @description Role of the team member in the project + * @example Full Stack Developer + */ + role: string; + /** + * @description Avatar URL of the team member + * @example https://example.com/avatar.png + */ + avatar?: string; + }; + SubmissionLinkDto: { + /** + * @description Type of link. Each fixed type (github, demo, video, document, presentation) can be used at most once per submission. Use "other" for additional links, up to a maximum of 5. + * @example github + * @enum {string} + */ + type: 'github' | 'demo' | 'video' | 'document' | 'presentation' | 'other'; + /** + * @description URL of the link + * @example https://github.com/username/project + */ + url: string; + /** + * @description Optional description of the link + * @example Main repository with source code + */ + description?: string; + }; + SocialLinksDto: { + /** + * @description GitHub profile or repository + * @example https://github.com/username + */ + github?: string; + /** + * @description Telegram username or group + * @example https://t.me/username + */ + telegram?: string; + /** + * @description Twitter/X handle + * @example https://twitter.com/username + */ + twitter?: string; + /** + * @description Email address + * @example contact@example.com + */ + email?: string; + }; + SubmissionResponseDto: { + id: string; + hackathonId: string; + projectId: string; + participantId: string; + organizationId: string; + /** @enum {string} */ + participationType: 'INDIVIDUAL' | 'TEAM'; + teamId?: string; + teamName?: string; + teamMembers?: components['schemas']['TeamMemberDto'][]; + projectName: string; + category: string; + description: string; + logo?: string; + banner?: string; + videoUrl?: string; + introduction?: string; + links: components['schemas']['SubmissionLinkDto'][]; + socialLinks?: components['schemas']['SocialLinksDto']; + status: string; + rank?: number; + /** @description Track entries this submission has opted into. Each entry carries the track slug/name and a wonRank stamped when the submission won that track (null until results are published). */ + trackEntries?: unknown[][]; + tagline?: string; + builtWith?: string[]; + screenshots?: string[]; + license?: string; + /** Format: date-time */ + codeAttestedAt?: string; + /** Format: date-time */ + registeredAt: string; + /** Format: date-time */ + submittedAt?: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + CreateSubmissionDto: { + /** + * @description Organization ID + * @example org_1234567890 + */ + organizationId: string; + /** + * @description Project ID (must be owned by the user or organization). If not provided, a base project will be created automatically. + * @example proj_1234567890 + */ + projectId?: string; + /** + * @description Type of participation + * @example INDIVIDUAL + * @enum {string} + */ + participationType: 'INDIVIDUAL' | 'TEAM'; + /** + * @deprecated + * @description [Ignored by backend.] Team ID is snapshotted from the user's authoritative team record at submission time. Field accepted for backwards compatibility only. + * @example team_1234567890 + */ + teamId?: string; + /** + * @deprecated + * @description [Ignored by backend.] Team name is snapshotted from the user's authoritative team record at submission time. + * @example Awesome Hackers + */ + teamName?: string; + /** + * @deprecated + * @description [Ignored by backend.] Team members are snapshotted from the user's authoritative team record at submission time. Sending this field has no effect. + */ + teamMembers?: components['schemas']['TeamMemberDto'][]; + /** + * @description Project name for the submission + * @example DeFi Lending Platform + */ + projectName: string; + /** + * @description Category of the project + * @example DeFi + */ + category: string; + /** + * @description Detailed description of the project + * @example A decentralized lending platform built on Stellar... + */ + description: string; + /** + * @description Project logo URL + * @example https://example.com/logo.png + */ + logo?: string; + /** + * @description Project banner image URL (wide hero image) + * @example https://example.com/banner.png + */ + banner?: string; + /** + * @description Video demonstration URL + * @example https://youtube.com/watch?v=xyz + */ + videoUrl?: string; + /** + * @description Brief introduction to the project + * @example We built a platform that allows users to... + */ + introduction?: string; + /** @description Links to project resources. Each fixed link type (github, demo, video, document, presentation) can appear at most once. Use "other" for additional links, up to a maximum of 5. */ + links: components['schemas']['SubmissionLinkDto'][]; + /** @description Social links for the project */ + socialLinks?: components['schemas']['SocialLinksDto']; + /** + * @description Optional list of track ids to enter. Only allowed when the hackathon has prizeStructure != OVERALL_ONLY. Capped at Hackathon.tracksMaxPerSubmission. + * @example [ + * "trk_abc", + * "trk_def" + * ] + */ + trackIds?: string[]; + /** + * @description Per-track answers. Keyed by trackId; each value is { promptAnswer?, customAnswers?, artifacts? }. Phase B. + * @example { + * "trk_abc": { + * "promptAnswer": "We focused on a one-tap escrow flow.", + * "customAnswers": { + * "q_audience": "Freelancers" + * }, + * "artifacts": { + * "figma": "https://figma.com/file/..." + * } + * } + * } + */ + trackAnswers?: Record; + /** + * @description Short elevator pitch shown on cards / sidebars / judge queue. Max ~160 chars. + * @example Trustless escrow for one-time freelance gigs on Stellar. + */ + tagline?: string; + /** + * @description Free-form tech-stack tags. Max 20 entries, 40 chars each. + * @example [ + * "Soroban", + * "Stellar SDK", + * "Next.js", + * "TrustlessWork SDK" + * ] + */ + builtWith?: string[]; + /** @description Up to 5 screenshot URLs for the project gallery. */ + screenshots?: string[]; + /** + * @description License the submission ships under. + * @enum {string} + */ + license?: + | 'MIT' + | 'Apache-2.0' + | 'GPL-3.0' + | 'BSD-3' + | 'PROPRIETARY' + | 'OTHER'; + /** @description Submitter attests the code is original or properly attributed. Required to mark a submission SUBMITTED (vs DRAFT). */ + codeAttested?: boolean; + }; + UpdateSubmissionDto: { + /** + * @description Project name for the submission + * @example DeFi Lending Platform + */ + projectName?: string; + /** + * @description Category of the project + * @example DeFi + */ + category?: string; + /** + * @description Detailed description of the project + * @example A decentralized lending platform built on Stellar... + */ + description?: string; + /** + * @description Project logo URL + * @example https://example.com/logo.png + */ + logo?: string; + /** + * @description Project banner image URL (wide hero image) + * @example https://example.com/banner.png + */ + banner?: string; + /** + * @description Video demonstration URL + * @example https://youtube.com/watch?v=xyz + */ + videoUrl?: string; + /** + * @description Brief introduction to the project + * @example We built a platform that allows users to... + */ + introduction?: string; + /** @description Links to project resources. Each fixed link type (github, demo, video, document, presentation) can appear at most once. Use "other" for additional links, up to a maximum of 5. */ + links?: components['schemas']['SubmissionLinkDto'][]; + /** @description Social links for the project */ + socialLinks?: components['schemas']['SocialLinksDto']; + /** @description Team members (for team submissions) */ + teamMembers?: components['schemas']['TeamMemberDto'][]; + /** @description Replace the submission's track picks. Omit to leave existing entries untouched; pass an empty array to clear all picks. */ + trackIds?: string[]; + /** @description Per-track answers, same shape as on create. Phase B. */ + trackAnswers?: Record; + tagline?: string; + builtWith?: string[]; + screenshots?: string[]; + /** @enum {string} */ + license?: + | 'MIT' + | 'Apache-2.0' + | 'GPL-3.0' + | 'BSD-3' + | 'PROPRIETARY' + | 'OTHER'; + codeAttested?: boolean; + }; + TeamMemberResponseDto: { + /** @description User ID */ + userId: string; + /** @description Username */ + username: string; + /** @description Display name */ + name: string; + /** @description Role in team (e.g. leader, member) */ + role: string; + /** @description Profile image URL */ + image?: string; + /** @description When the member joined the team (ISO string) */ + joinedAt: string; + }; + LookingForRoleDto: { + /** + * @description Role title (e.g. "Frontend Developer", "UI Designer") + * @example Frontend Developer + */ + role: string; + /** + * @description Optional free-form skills associated with this role + * @example [ + * "React", + * "TypeScript" + * ] + */ + skills?: unknown[][]; + }; + TeamRoleResponseDto: { + /** @description Skill/role name */ + skill: string; + /** @description Whether this role has been filled */ + hired: boolean; + }; + TeamResponseDto: { + /** + * @description Team ID + * @example team_1234567890 + */ + id: string; + /** + * @description Team name + * @example Stellar Innovators + */ + teamName: string; + /** @description Team description */ + description: string; + /** @description Hackathon ID */ + hackathonId: string; + /** @description Team leader information */ + leader: Record; + /** @description Team members */ + members: components['schemas']['TeamMemberResponseDto'][]; + /** + * @description Current number of members + * @example 3 + */ + memberCount: number; + /** + * @description Maximum team size allowed + * @example 5 + */ + maxSize: number; + /** @description Roles the team is looking for, with optional free-form skills */ + lookingFor?: components['schemas']['LookingForRoleDto'][]; + /** @description Hired status per role (when using lookingFor) */ + rolesStatus?: components['schemas']['TeamRoleResponseDto'][]; + /** @description Contact information (e.g. telegram, discord, email) */ + contactInfo?: Record; + /** + * @description Whether team is accepting new members + * @example true + */ + isOpen: boolean; + /** @description Team creation date */ + createdAt: string; + /** @description Last update date */ + updatedAt: string; + }; + TeamListResponseDto: { + /** @description List of teams */ + teams: components['schemas']['TeamResponseDto'][]; + /** @description Pagination metadata */ + pagination: Record; + }; + CreateTeamDto: { + /** + * @description Team name + * @example Stellar Innovators + */ + teamName: string; + /** + * @description Team description + * @example We are building the next generation DeFi platform + */ + description: string; + /** @description Roles the team is looking for. Each entry is a role title with optional free-form skills. Team will be CLOSED unless at least one role is specified. The number of roles is bounded by the hackathon's teamMin/teamMax (excluding the leader). */ + lookingFor?: components['schemas']['LookingForRoleDto'][]; + /** + * @description Contact information for interested members + * @example { + * "telegram": "@teamlead", + * "discord": "lead#1234" + * } + */ + contactInfo?: Record; + }; + UpdateTeamDto: { + /** + * @description Updated team name + * @example Stellar Innovators Pro + */ + teamName?: string; + /** @description Updated team description */ + description?: string; + /** @description Roles the team is looking for. Set to empty array to close the team. Each entry is a role title with optional free-form skills. */ + lookingFor?: components['schemas']['LookingForRoleDto'][]; + /** @description Updated contact information */ + contactInfo?: Record; + /** @description Explicitly set team open/closed status. Can only be true if lookingFor is not empty. */ + isOpen?: boolean; + }; + InviteToTeamDto: { + /** + * @description User ID or username of the person to invite + * @example user_1234567890 + */ + inviteeIdentifier: string; + /** + * @description Optional message to include with the invitation + * @example We would love to have you on our team! + */ + message?: string; + }; + TeamInvitationResponseDto: { + /** + * @description Invitation ID + * @example inv_1234567890 + */ + id: string; + /** + * @description Team ID + * @example team_1234567890 + */ + teamId: string; + /** @description Hackathon information */ + hackathon: Record; + /** @description Invitee information */ + invitee: Record; + /** @description Inviter information */ + inviter: Record; + /** + * @description Invitation status + * @example pending + * @enum {string} + */ + status: 'pending' | 'accepted' | 'rejected' | 'expired'; + /** + * @description Optional message from inviter + * @example We would love to have you on our team! + */ + message?: Record; + /** + * @description Role in the team + * @example member + */ + role: Record; + /** + * Format: date-time + * @description Invitation expiration date + * @example 2026-01-30T12:00:00.000Z + */ + expiresAt: string; + /** + * Format: date-time + * @description Invitation creation date + * @example 2026-01-23T12:00:00.000Z + */ + createdAt: string; + /** + * @description Date when invitation was responded to + * @example 2026-01-24T12:00:00.000Z + */ + respondedAt?: Record; + }; + TeamInvitationListResponseDto: { + /** @description List of invitations */ + invitations: components['schemas']['TeamInvitationResponseDto'][]; + /** + * @description Total count + * @example 5 + */ + total: number; + }; + InvitationActionResponseDto: { + /** + * @description Success message + * @example Successfully accepted team invitation + */ + message: string; + /** + * @description Team ID that was joined (only for accept) + * @example team_1234567890 + */ + teamId: string; + /** @description Updated invitation */ + invitation: components['schemas']['TeamInvitationResponseDto']; + }; + ToggleRoleHiredDto: { + /** + * @description Skill/role name to toggle hired status + * @example Rust Developer + */ + skill: string; + }; + TransferLeadershipDto: { + /** + * @description User ID of the new team leader (must be an existing member) + * @example user_1234567890 + */ + newLeaderId: string; + /** + * @description Optional reason for the leadership transfer + * @example Stepping down to focus on development tasks + */ + reason?: string; + }; + LeadershipTransferResponseDto: { + /** + * @description Success message + * @example Leadership successfully transferred + */ + message: string; + /** @description Updated team with new leader */ + team: components['schemas']['TeamResponseDto']; + /** + * @description Previous leader ID + * @example user_1234567890 + */ + previousLeaderId: string; + /** + * @description New leader ID + * @example user_0987654321 + */ + newLeaderId: string; + /** + * Format: date-time + * @description Timestamp of the transfer + * @example 2026-02-16T10:30:00.000Z + */ + transferredAt: string; + }; + InfoFormData: { + /** @description Hackathon title */ + name: string; + /** + * Format: uri + * @description Banner image URL + */ + banner: string; + /** @description Hackathon description */ + description: string; + /** @description One or more hackathon categories */ + categories: ( + | 'DeFi' + | 'NFTs' + | 'DAOs' + | 'Layer 2' + | 'Cross-chain' + | 'Web3 Gaming' + | 'Social Tokens' + | 'Infrastructure' + | 'Privacy' + | 'Sustainability' + | 'Real World Assets' + | 'Other' + )[]; + /** + * @description Venue type + * @enum {string} + */ + venueType: 'virtual' | 'physical'; + /** @description Short tagline */ + tagline: string; + country?: string; + state?: string; + city?: string; + venueName?: string; + venueAddress?: string; + /** @description Read-only URL slug (server-assigned) */ + slug?: string; + }; + PhaseDto: { + /** @description Phase name */ + name: string; + /** Format: date-time */ + startDate: string; + /** Format: date-time */ + endDate: string; + description?: string; + }; + TimelineFormData: { + /** Format: date-time */ + startDate: string; + /** Format: date-time */ + submissionDeadline: string; + /** @description IANA timezone */ + timezone: string; + /** Format: date-time */ + registrationDeadline?: string; + /** Format: date-time */ + judgingDeadline?: string; + phases?: components['schemas']['PhaseDto'][]; + /** + * Format: date-time + * @description Read-only: original submission deadline before any extension + */ + submissionDeadlineOriginal?: string; + /** + * Format: date-time + * @description Read-only: timestamp the submission deadline was last extended + */ + submissionDeadlineExtendedAt?: string; + }; + ParticipantFormData: { + /** @enum {string} */ + participantType: 'individual' | 'team' | 'team_or_individual'; + teamMin?: number; + teamMax?: number; + /** @description Participant cap; omit for unlimited */ + maxParticipants?: number; + require_github?: boolean; + require_demo_video?: boolean; + require_other_links?: boolean; + detailsTab?: boolean; + participantsTab?: boolean; + resourcesTab?: boolean; + submissionTab?: boolean; + announcementsTab?: boolean; + discussionTab?: boolean; + winnersTab?: boolean; + sponsorsTab?: boolean; + joinATeamTab?: boolean; + rulesTab?: boolean; + /** @enum {string} */ + submissionVisibility?: 'PUBLIC' | 'PARTICIPANTS_ONLY'; + /** @enum {string} */ + submissionStatusVisibility?: + | 'ALL' + | 'ACCEPTED_SHORTLISTED' + | 'HIDDEN_UNTIL_RESULTS'; + }; + PrizeTierDto: { + /** @description Client-generated tier id */ + id: string; + /** @description Placement label, e.g. "1st Place" */ + place: string; + /** @description Prize amount as a decimal string */ + prizeAmount: string; + description?: string; + currency?: string; + passMark: number; + /** @enum {string} */ + kind?: 'OVERALL' | 'TRACK'; + trackId?: string; + }; + WinnerOverrideDto: { + /** @description Submission id the override targets */ + submissionId: string; + rank?: number; + prizeAmount?: string; + currency?: string; + }; + RewardsFormData: { + prizeTiers: components['schemas']['PrizeTierDto'][]; + winnerOverrides?: components['schemas']['WinnerOverrideDto'][]; + /** @enum {string} */ + prizeStructure?: 'OVERALL_ONLY' | 'OVERALL_AND_TRACKS' | 'TRACKS_ONLY'; + tracksMaxPerSubmission?: number; + }; + ResourceItemDto: { + /** @description Client-generated resource id */ + id: string; + link?: string; + description?: string; + /** @description Uploaded file metadata */ + file?: { + url?: string; + name?: string; + }; + }; + ResourcesFormData: { + resources: components['schemas']['ResourceItemDto'][]; + }; + CriterionDto: { + /** @description Client-generated criterion id */ + id: string; + /** @description Criterion name */ + name: string; + weight: number; + description?: string; + }; + JudgingFormData: { + criteria: components['schemas']['CriterionDto'][]; + }; + SponsorPartnerDto: { + /** @description Client-generated sponsor/partner id */ + id: string; + name?: string; + logo?: string; + link?: string; + }; + CollaborationFormData: { + /** @description Organizer contact email */ + contactEmail: string; + telegram?: string; + discord?: string; + socialLinks?: string[]; + sponsorsPartners?: components['schemas']['SponsorPartnerDto'][]; + }; + HackathonDraftDataDto: { + information?: components['schemas']['InfoFormData']; + timeline?: components['schemas']['TimelineFormData']; + participation?: components['schemas']['ParticipantFormData']; + rewards?: components['schemas']['RewardsFormData']; + resources?: components['schemas']['ResourcesFormData']; + judging?: components['schemas']['JudgingFormData']; + collaboration?: components['schemas']['CollaborationFormData']; + }; + HackathonDraftResponseDto: { + id: string; + /** @enum {string} */ + status: + | 'DRAFT' + | 'DRAFT_AWAITING_FUNDING' + | 'PUBLISHED' + | 'ARCHIVED' + | 'CANCELLED'; + /** @description First incomplete step (1-based) */ + currentStep: number; + completedSteps: string[]; + data: components['schemas']['HackathonDraftDataDto']; + isValidForPublish: boolean; + /** @description Per-section validation messages, keyed by step */ + validationErrors: { + [key: string]: string[]; + }; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + UpdateHackathonDraftDto: { + information?: components['schemas']['InfoFormData']; + timeline?: components['schemas']['TimelineFormData']; + participation?: components['schemas']['ParticipantFormData']; + rewards?: components['schemas']['RewardsFormData']; + resources?: components['schemas']['ResourcesFormData']; + judging?: components['schemas']['JudgingFormData']; + collaboration?: components['schemas']['CollaborationFormData']; + /** @description Hint that this is an autosave (no completion side effects). */ + autoSave?: boolean; + }; + UpdateVisibilitySettingsDto: { + /** + * @description Who can view hackathon submissions + * @example PUBLIC + * @enum {string} + */ + submissionVisibility?: 'PUBLIC' | 'PARTICIPANTS_ONLY'; + /** + * @description Which submission statuses are visible to others. ALL exposes SUBMITTED and SHORTLISTED. ACCEPTED_SHORTLISTED exposes only SHORTLISTED. HIDDEN_UNTIL_RESULTS hides every submission from non-owners and non-organizers until the hackathon results are published, then exposes only SHORTLISTED. DISQUALIFIED is never visible to anyone other than the owner or an organizer. + * @example ACCEPTED_SHORTLISTED + * @enum {string} + */ + submissionStatusVisibility?: + | 'ALL' + | 'ACCEPTED_SHORTLISTED' + | 'HIDDEN_UNTIL_RESULTS'; + }; + ReviewSubmissionDto: { + /** + * @description ID of the assigned judge performing the review + * @example user_1234567890 + */ + judgeId: string; + /** + * @description Review action + * @example SHORTLISTED + * @enum {string} + */ + status: 'SHORTLISTED' | 'SUBMITTED'; + /** + * @description Reviewer notes or feedback + * @example Great project with innovative approach + */ + notes?: string; + /** + * @description Rank/position for the submission + * @example 1 + */ + rank?: number; + /** + * @description Whether this is an organizational override (bypasses COI and assignment checks) + * @default false + */ + isOrganizerOverride: boolean; + }; + OrganizationHackathonParticipantsResponseDto: Record; + DisqualifySubmissionDto: { + /** + * @description Reason for disqualification + * @example Submission does not meet hackathon requirements + */ + disqualificationReason: string; + }; + BulkSubmissionActionDto: { + /** + * @description Array of submission IDs + * @example [ + * "sub_1234567890", + * "sub_0987654321" + * ] + */ + submissionIds: string[]; + /** + * @description Action to perform + * @example SHORTLISTED + * @enum {string} + */ + action: 'SHORTLISTED' | 'SUBMITTED' | 'DISQUALIFIED'; + /** + * @description Reason (required for DISQUALIFIED action) + * @example Does not meet requirements + */ + reason?: string; + }; + SummaryMetricsDto: { + /** @example 120 */ + participantsCount: number; + /** @example 45 */ + submissionsCount: number; + /** @example 6 */ + activeJudges: number; + /** @example 3 */ + completedMilestones: number; + }; + TrendPointDto: { + /** @example 2026-02-01 */ + date: string; + /** @example 5 */ + count: number; + }; + TrendsDto: { + submissionsOverTime: components['schemas']['TrendPointDto'][]; + participantSignupsOverTime: components['schemas']['TrendPointDto'][]; + }; + TimelinePhaseDto: { + /** @example Registration */ + phase: string; + /** @example Individuals and teams are signing up to participate in the hackathon. */ + description: string; + /** @example 2026-01-20 */ + date: string; + /** @enum {string} */ + status: 'upcoming' | 'ongoing' | 'completed'; + }; + HackathonAnalyticsResponseDto: { + /** @example hack_1234567890 */ + hackathonId: string; + summary: components['schemas']['SummaryMetricsDto']; + trends: components['schemas']['TrendsDto']; + timeline: components['schemas']['TimelinePhaseDto'][]; + }; + AnnouncementAuthorDto: { + id: string; + name: string; + image?: string; + username?: string; + }; + AnnouncementResponseDto: { + id: string; + hackathonId: string; + title: string; + content: string; + isDraft: boolean; + isPinned: boolean; + /** Format: date-time */ + publishedAt?: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + author: components['schemas']['AnnouncementAuthorDto']; + }; + CreateAnnouncementDto: { + /** + * @description Title of the announcement + * @example Hackathon Starts Now! + */ + title: string; + /** + * @description Content of the announcement in Markdown + * @example # Welcome + * + * We are excited to start... + */ + content: string; + /** + * @description Whether the announcement is a draft + * @default true + */ + isDraft: boolean; + /** + * @description Whether the announcement should be pinned + * @default false + */ + isPinned: boolean; + }; + UpdateAnnouncementDto: { + /** + * @description Title of the announcement + * @example Hackathon Starts Now! + */ + title?: string; + /** + * @description Content of the announcement in Markdown + * @example # Welcome + * + * We are excited to start... + */ + content?: string; + /** @description Whether the announcement is a draft */ + isDraft?: boolean; + /** @description Whether the announcement should be pinned */ + isPinned?: boolean; + }; + CriterionScoreDto: { + /** + * @description Criterion ID or name + * @example Technical Complexity + */ + criterionId: string; + /** + * @description Score for this criterion (0-10) + * @example 8.5 + */ + score: number; + /** + * @description Optional comment for this criterion + * @example Great technical implementation + */ + comment?: string; + }; + ScoreSubmissionDto: { + /** + * @description Submission ID being judged + * @example sub_1234567890 + */ + submissionId: string; + /** @description Scores for each individual criterion */ + criteriaScores: components['schemas']['CriterionScoreDto'][]; + /** + * @description Optional ID of the judge to attribute this score to (defaults to calling user) + * @example user_123 + */ + judgeId?: string; + /** + * @description Optional admin notes + * @example Score adjusted per appeal + */ + notes?: string; + /** + * @description Whether this is an organizational override (bypasses COI and assignment checks) + * @default false + */ + isOrganizerOverride: boolean; + }; + UserDetailsDto: { + id: string; + email: string; + name: string; + username: string; + image?: string; + }; + JudgingSubmissionParticipantDto: { + id: string; + userId: string; + user: components['schemas']['UserDetailsDto']; + participationType: string; + teamId?: string; + teamName?: string; + teamMembers?: Record[]; + }; + JudgingSubmissionDataDto: { + id: string; + projectName: string; + category: string; + description: string; + logo?: string; + videoUrl?: string; + introduction?: string; + links?: Record[]; + socialLinks?: { + [key: string]: unknown; + }; + submissionDate: string; + status: string; + rank?: number; + }; + IndividualJudgingResultDto: { + judgeId: string; + judgeName: string; + criteriaScores: components['schemas']['CriterionScoreDto'][]; + totalScore: number; + /** Format: date-time */ + submittedAt: string; + }; + JudgingSubmissionDto: { + participant: components['schemas']['JudgingSubmissionParticipantDto']; + submission: components['schemas']['JudgingSubmissionDataDto']; + myScore?: components['schemas']['IndividualJudgingResultDto']; + averageScore: Record | null; + judgeCount: number; + }; + JudgingPaginationDto: { + page: number; + limit: number; + total: number; + totalPages: number; + }; + JudgingSubmissionsResponseDto: { + submissions: components['schemas']['JudgingSubmissionDto'][]; + criteria: components['schemas']['CriterionDto'][]; + pagination: components['schemas']['JudgingPaginationDto']; + /** @description Number of submissions in this hackathon that the calling judge has already scored. Independent of pagination so the progress strip is accurate even when the user is on page 2. */ + scoredCount?: number; + }; + AddJudgeDto: { + /** + * @description Email address of the user to be assigned as a judge + * @example judge@example.com + */ + email: string; + }; + JudgeResponseDto: { + id: string; + userId: string; + name: string; + image?: Record; + }; + IndividualScoreDto: { + judgeId: string; + judgeName: string; + score: number; + }; + ScoreRangeDto: { + min: number; + max: number; + }; + CriteriaBreakdownDto: { + criterionId: string; + averageScore: number; + min: number; + max: number; + variance: number; + }; + AggregatedJudgingResultDto: { + submissionId: string; + projectName: string; + teamId?: Record; + participantId: string; + status: string; + /** Format: date-time */ + submittedAt: string; + averageScore: number; + totalScore: number; + judgeCount: number; + expectedJudgeCount: number; + judgingProgress: string; + individualScores: components['schemas']['IndividualScoreDto'][]; + scoreVariance: number; + scoreRange: components['schemas']['ScoreRangeDto']; + criteriaBreakdown: components['schemas']['CriteriaBreakdownDto'][]; + rank?: Record; + computedRank?: number; + prize?: string; + isComplete: boolean; + isPending: boolean; + hasDisagreement: boolean; + trackIds?: string[]; + }; + JudgingResultsResponseDto: { + hackathonId: string; + totalSubmissions: number; + submissionsScoredCount: number; + submissionsPendingCount: number; + averageScoreAcrossAll: number; + resultsPublished: boolean; + judgesAssigned: number; + results: components['schemas']['AggregatedJudgingResultDto'][]; + /** Format: date-time */ + generatedAt: string; + /** @description Manual winner assignments override (submissionId -> rank) */ + winnerOverrides?: { + [key: string]: number; + }; + metadata: components['schemas']['JudgingResultsMetadataDto']; + }; + InviteJudgeDto: { + /** @example judge@example.com */ + email: string; + /** @description Optional public display name for the judge */ + displayName?: string; + /** @description Personal message included in the invitation email */ + message?: string; + /** @description Override expiry in days (default 14). Maximum 60 to prevent indefinite invitations. */ + expiresInDays?: number; + }; + AcceptJudgeInvitationDto: { + /** @description Optional display name override. If omitted, the inviter-provided displayName (or the user’s account name) is used. */ + displayName?: string; + }; + PublishedInfoFormDataDto: { + /** @example Web3 Innovation Hackathon */ + name: string; + /** @example https://example.com/banner.png */ + banner: string; + /** @example Build products for the decentralized future. */ + description: string; + categories: ( + | 'DeFi' + | 'NFTs' + | 'DAOs' + | 'Layer 2' + | 'Cross-chain' + | 'Web3 Gaming' + | 'Social Tokens' + | 'Infrastructure' + | 'Privacy' + | 'Sustainability' + | 'Real World Assets' + | 'Other' + )[]; + /** + * @example virtual + * @enum {string} + */ + venueType: 'virtual' | 'physical'; + /** @example Build the future of Web3 */ + tagline: string; + /** @example Nigeria */ + country?: string; + /** @example Lagos */ + state?: string; + /** @example Ikeja */ + city?: string; + /** @example Eko Convention Center */ + venueName?: string; + /** @example Plot 1415 Adetokunbo Ademola St */ + venueAddress?: string; + /** @example web3-innovation-hackathon */ + slug?: string; + }; + PublishedSponsorPartnerDto: { + /** @example sp-1 */ + id: string; + /** @example Stellar Foundation */ + name?: string; + /** @example https://example.com/logo.png */ + logo?: string; + /** @example https://stellar.org */ + link?: string; + }; + PublishedCollaborationFormDataDto: { + /** @example organizer@boundless.dev */ + contactEmail: string; + /** @example @boundless */ + telegram?: string; + /** @example boundless-hackathon */ + discord?: string; + /** + * @example [ + * "https://x.com/boundless" + * ] + */ + socialLinks: string[]; + sponsorsPartners: components['schemas']['PublishedSponsorPartnerDto'][]; + }; + UpdatePublishedHackathonContentDto: { + information?: components['schemas']['PublishedInfoFormDataDto']; + collaboration?: components['schemas']['PublishedCollaborationFormDataDto']; + }; + PublishedPhaseDto: { + /** @example Building Phase */ + name: string; + /** @example 2026-04-01T00:00:00.000Z */ + startDate: string; + /** @example 2026-04-10T00:00:00.000Z */ + endDate: string; + /** @example Core build phase for teams */ + description?: string; + }; + PublishedTimelineFormDataDto: { + /** @example 2026-04-01T00:00:00.000Z */ + startDate?: string; + /** @example 2026-04-15T00:00:00.000Z */ + submissionDeadline?: string; + /** @example Africa/Lagos */ + timezone?: string; + /** + * @description Optional. When null, registration stays open until submission deadline. + * @example 2026-04-02T00:00:00.000Z + */ + registrationDeadline?: string; + /** + * @description Optional judging deadline. When null, no judging phase is rendered on the timeline. + * @example 2026-04-18T00:00:00.000Z + */ + judgingDeadline?: string; + phases?: components['schemas']['PublishedPhaseDto'][]; + }; + PublishedParticipantFormDataDto: { + /** @enum {string} */ + participantType: 'individual' | 'team' | 'team_or_individual'; + /** @example 2 */ + teamMin?: number; + /** @example 5 */ + teamMax?: number; + /** + * @description Optional cap on total participants. null = unlimited. Can be updated after publishing. + * @example 200 + */ + maxParticipants?: number; + /** @example true */ + require_github?: boolean; + /** @example false */ + require_demo_video?: boolean; + /** @example true */ + require_other_links?: boolean; + detailsTab?: boolean; + participantsTab?: boolean; + resourcesTab?: boolean; + submissionTab?: boolean; + announcementsTab?: boolean; + discussionTab?: boolean; + winnersTab?: boolean; + sponsorsTab?: boolean; + joinATeamTab?: boolean; + rulesTab?: boolean; + }; + UpdatePublishedHackathonScheduleDto: { + timeline?: components['schemas']['PublishedTimelineFormDataDto']; + participation?: components['schemas']['PublishedParticipantFormDataDto']; + }; + PublishedPrizeTierDto: { + /** @example tier-1 */ + id: string; + /** @example 1st Place */ + place: string; + /** @example 5000 */ + prizeAmount: string; + /** @example USDC */ + currency?: string; + /** @example Top overall project */ + description?: string; + /** + * @description Display rank / ordering of the tier (1 = highest) + * @example 1 + */ + rank?: number; + /** @example 70 */ + passMark: number; + /** @enum {string} */ + kind?: 'OVERALL' | 'TRACK'; + /** @description Required when kind=TRACK. References a HackathonTrack id. */ + trackId?: string; + }; + PublishedRewardsFormDataDto: { + prizeTiers: components['schemas']['PublishedPrizeTierDto'][]; + /** + * @description Manual winner assignments override (submissionId -> rank) + * @example { + * "sub-1": 1, + * "sub-2": 2 + * } + */ + winnerOverrides?: { + [key: string]: number; + }; + /** @enum {string} */ + prizeStructure?: 'OVERALL_ONLY' | 'OVERALL_AND_TRACKS' | 'TRACKS_ONLY'; + tracksMaxPerSubmission?: number; + }; + UpdatePublishedHackathonFinancialDto: { + rewards: components['schemas']['PublishedRewardsFormDataDto']; + }; + AdvancedSettingsFormDataDto: { + /** @example true */ + isPublic: boolean; + /** @example false */ + allowLateRegistration: boolean; + /** @example true */ + requireApproval: boolean; + /** @example 500 */ + maxParticipants?: number; + /** @example hackathons.boundless.dev */ + customDomain?: string; + /** @example true */ + enableDiscord: boolean; + /** @example https://discord.gg/boundless */ + discordInviteLink?: string; + /** @example true */ + enableTelegram: boolean; + /** @example https://t.me/boundless */ + telegramInviteLink?: string; + }; + UpdatePublishedHackathonAdvancedSettingsDto: { + advancedSettings: components['schemas']['AdvancedSettingsFormDataDto']; + }; + InvitePartnerDto: { + /** @example sponsor@partner.io */ + partnerEmail: string; + /** @example Acme Corp */ + partnerName: string; + /** @example https://cdn.example.com/logo.png */ + partnerLogo?: string; + /** @example https://acme.io */ + partnerLink?: string; + /** + * @description Pledged amount in USDC + * @example 1000 + */ + pledgedAmount: number; + /** + * @default USDC + * @example USDC + */ + currency: string; + /** @description Optional message included in the invite */ + message?: string; + /** + * @description Whether the partner is shown publicly on the hackathon page + * @default true + */ + showPublicly: boolean; + }; + AllocationTargetDto: { + /** @description Existing prize tier id to inflate. Either tierId or newTier must be set. */ + tierId?: string; + /** + * @description Create a new prize tier with this label. Either tierId or newTier must be set. + * @example Best AI Project + */ + newTierLabel?: string; + /** @description Optional description for the new tier */ + newTierDescription?: string; + /** @description Net amount (USDC) to add to the tier */ + amount: number; + }; + AllocateContributionDto: { + /** @description One or more tiers to allocate this contribution into */ + targets: components['schemas']['AllocationTargetDto'][]; + }; + PrepareFundTransactionDto: { + /** @description Stellar address of the partner wallet that will sign the transaction */ + signerAddress: string; + }; + SubmitSignedTransactionDto: { + /** @description Signed transaction XDR returned by the partner wallet */ + signedXdr: string; + }; + TrackCustomQuestionDto: { + /** @description Stable id, unique within the track. */ + id: string; + /** @description Question label shown on the submission form. */ + label: string; + /** + * @description Input type. 'short' = single-line, 'long' = textarea, 'url' = URL field. + * @enum {string} + */ + type: 'short' | 'long' | 'url'; + /** @description Optional maxLength override (defaults: short=200, long=1000). */ + maxLength?: number; + /** @description Whether an answer is required. */ + required?: boolean; + }; + TrackRequiredArtifactDto: { + /** @description Stable id, unique within the track. */ + id: string; + /** @description Artifact label (e.g. "Figma file URL"). */ + label: string; + /** + * @description Artifact type — drives the placeholder + light hint UI. + * @enum {string} + */ + type: 'figma' | 'github' | 'video' | 'pdf' | 'url'; + /** @description Whether submitting this artifact is required. */ + required?: boolean; + }; + TrackResponseDto: { + id: string; + hackathonId: string; + slug: string; + name: string; + description?: string; + type?: string; + /** @enum {string} */ + eligibility: 'OPT_IN' | 'OPEN'; + displayOrder: number; + isArchived: boolean; + /** @description Count of submissions that have opted into this track. Useful for organizer dashboards. */ + entryCount: number; + /** @description Per-track customization (Phase B). */ + prompt?: string; + customQuestions?: components['schemas']['TrackCustomQuestionDto'][]; + requiredArtifacts?: components['schemas']['TrackRequiredArtifactDto'][]; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + CreateTrackDto: { + /** + * @description Human-readable track name shown on the hackathon page. + * @example Best UI/UX + */ + name: string; + /** + * @description URL-safe handle, unique within the hackathon. Auto-generated from name if omitted. + * @example best-ui-ux + */ + slug?: string; + /** + * @description Short blurb shown in the track picker and on results. + * @example Best end-to-end user experience and visual polish. + */ + description?: string; + /** + * @description Free-form classifier for badge styling. Common values: skill, technology, theme, special. + * @example skill + */ + type?: string; + /** + * @description OPT_IN (default): submitters explicitly enter. OPEN: every submission auto-eligible. + * @default OPT_IN + * @enum {string} + */ + eligibility: 'OPT_IN' | 'OPEN'; + /** + * @description Sort order. Lower numbers render first. Defaults to 0. + * @example 10 + */ + displayOrder?: number; + /** + * @description Single open-ended prompt shown on the submission form. When set, the submitter must answer to opt in. + * @example Why does this project fit Best UI/UX? + */ + prompt?: string; + customQuestions?: components['schemas']['TrackCustomQuestionDto'][]; + requiredArtifacts?: components['schemas']['TrackRequiredArtifactDto'][]; + }; + UpdateTrackDto: { + name?: string; + slug?: string; + description?: string; + type?: string; + /** @enum {string} */ + eligibility?: 'OPT_IN' | 'OPEN'; + displayOrder?: number; + /** @description Soft-archive instead of delete when entries already exist. Cannot be unset via this endpoint; recreate the track if needed. */ + isArchived?: boolean; + /** @description Single open-ended prompt. */ + prompt?: string; + customQuestions?: components['schemas']['TrackCustomQuestionDto'][]; + requiredArtifacts?: components['schemas']['TrackRequiredArtifactDto'][]; + }; + RequestFundingOtpResponseDto: { + /** @description Whether funding step-up is enforced for this action */ + required: boolean; + /** @description True when a recent verification is still valid; the client can fund without entering a new code */ + alreadyVerified: boolean; + /** @description True when a fresh code was just emailed */ + sent: boolean; + /** @description Seconds until the emailed code expires (0 when none sent) */ + expiresInSeconds: number; + }; + VerifyFundingOtpDto: { + /** + * @description The 6-digit code emailed to the organizer + * @example 123456 + */ + code: string; + }; + VerifyFundingOtpResponseDto: { + /** @description True when the code was accepted */ + verified: boolean; + /** @description Seconds the funding authorization remains valid */ + expiresInSeconds: number; + }; + WinnerDistributionEntryDto: { + /** + * @description Winner position (1-indexed; 1 = top winner). + * @example 1 + */ + position: number; + /** + * @description Percentage of the total budget allocated to this position. All entries must sum to exactly 100. + * @example 100 + */ + percent: number; + }; + PublishHackathonEscrowDto: { + /** + * @description Stellar G-address that will own and sign the on-chain create_event transaction. For managed wallets, this is the platform-derived address tied to the organizer's account; for connected/multisig, it's the org treasury's G-address. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + ownerAddress: string; + /** + * @description Stellar Asset Contract (SAC) address the prize pool is denominated in. Must be whitelisted on the events contract (see admin runbook). + * @example CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA + */ + tokenAddress: string; + /** + * @description Total prize budget in token-native units (e.g. 1000 = 1000 USDC, NOT stroops). Use a string when the value exceeds JavaScript's safe integer range. The backend converts to stroops via *10^7. + * @example 1000 + */ + budget: string; + /** @description Optional override for the winner distribution. Each entry maps a position to a percent of total_budget. Percents must sum to exactly 100. Defaults to a single winner at position 1 taking 100%. */ + winnerDistribution?: components['schemas']['WinnerDistributionEntryDto'][]; + /** + * @description Override for the public content_uri the contract stores against the event. Defaults to https://api.boundless.fi/hackathons//content. + * @example https://api.boundless.fi/hackathons/abc/content + */ + contentUri?: string; + /** + * @description Signing path. Defaults to EXTERNAL (return unsigned XDR for the caller to sign). Set to MANAGED to have the backend sign + submit using the caller user's managed wallet; the response carries the op in PENDING_CONFIRM with a txHash. + * @default EXTERNAL + * @example MANAGED + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + /** @description For MANAGED funding, the organization treasury wallet to fund from. When set, the backend signs with that treasury (managed) wallet instead of the caller's personal wallet; ownerAddress must match the treasury wallet address. Omit to fund from the personal managed wallet. */ + sourceWalletId?: string; + }; + HackathonEscrowOpResponseDto: { + /** + * @description Internal cuid for the EscrowOp row. Use this for follow-up calls. + * @example cmpwiox7u0000yy4404ojbk9t + */ + id: string; + /** + * @description Hex-encoded 32-byte op_id derived deterministically from the operation parameters. Used by the on-chain idempotency check. + * @example 3cc257d743b1b44423dc8dbd417aedfe6e47ad489b5d301a2fbec5284d36de1c + */ + opId: string; + /** + * @description Contract operation kind. + * @example CREATE_EVENT + * @enum {string} + */ + kind: + | 'CREATE_EVENT' + | 'CANCEL_EVENT' + | 'ADD_FUNDS' + | 'APPLY_TO_BOUNTY' + | 'WITHDRAW_APPLICATION' + | 'SUBMIT' + | 'WITHDRAW_SUBMISSION' + | 'SELECT_WINNERS' + | 'CLAIM_MILESTONE'; + /** + * @description Status of the EscrowOp in its lifecycle. + * @example PENDING_SIGN + * @enum {string} + */ + status: + | 'PENDING_BUILD' + | 'PENDING_SIGN' + | 'PENDING_SUBMIT' + | 'PENDING_CONFIRM' + | 'COMPLETED' + | 'FAILED' + | 'CANCELLED'; + /** + * @description Entity kind the op operates on. Matches the application-level row (hackathon, bounty, grant, etc.). + * @example HACKATHON + */ + entityKind: string; + /** + * @description Application-level row id this op acts on. + * @example cmpwihilf0000fd44iln3dzbg + */ + entityId: string; + /** + * @description Unsigned XDR transaction the wallet must sign. Present after the build phase completes (PENDING_SIGN onwards). + * @example AAAAAgAAAACdiamX7q...truncated... + */ + unsignedXdr?: string | null; + /** + * @description Stellar G-address expected to sign this op. The wallet routing layer on the webapp uses this to pick the right signer. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + signerHint?: string | null; + /** + * @description Soroban tx hash assigned at submit time. Set once the op reaches PENDING_CONFIRM or beyond. + * @example daafec9027da007b54eec34c54a5919edd7a8682bc96ccf7c7072982305cfa3b + */ + txHash?: string | null; + /** + * @description Contract error code when the op transitions to FAILED. Mirrors the on-chain error name (e.g. "InsufficientEscrow", "OpAlreadySeen", "txBadAuth"). + * @example txBadAuth + */ + errorCode?: string | null; + /** + * Format: date-time + * @description Row creation time. + * @example 2026-06-02T11:45:36.927Z + */ + createdAt: string; + /** + * Format: date-time + * @description Row last-updated time. + * @example 2026-06-02T11:45:44.310Z + */ + updatedAt: string; + }; + CancelHackathonEscrowDto: { + /** + * @description Organizer's Stellar G-address. Must match the on-chain hackathon owner. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + ownerAddress: string; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side with the caller's platform-held wallet. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + /** @description For MANAGED, the organization treasury wallet to sign with (the event contract-auth identity). ownerAddress must match it. Omit to use the caller's personal managed wallet. */ + sourceWalletId?: string; + }; + HackathonWinnerSelectionDto: { + /** + * @description ID of the winning submission. The payout recipient is resolved server-side = the submitter's (team leader's) Boundless managed wallet; no on-chain submission anchor is required. + * @example cmq7sgwst0001abcd1234efgh + */ + submissionId: string; + /** + * @description Winner position, 1-indexed. Must exist in the hackathon's on-chain winner_distribution. + * @example 1 + */ + position: number; + /** + * @description Override the platform default credit_earn for this position. Defaults to 20/10/5 for positions 1/2/3 and 3 for the rest. Capped at 100 by the contract. + * @example 20 + */ + creditEarn?: number; + /** + * @description Override the platform default reputation_bump for this position. Defaults to 50/25/10 for positions 1/2/3 and 5 for the rest. + * @example 50 + */ + reputationBump?: number; + }; + SelectHackathonWinnersDto: { + /** + * @description Organizer's Stellar G-address — a hint only. select_winners is authorized by the event manager resolved on-chain (the org treasury for new events), which the backend signs with server-side; this value is used only as a fallback when that on-chain read is unavailable (legacy/pre-upgrade events). Omit for the MANAGED flow. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + ownerAddress?: string; + /** @description Winners to declare, each by winning submissionId + position. The payout recipient is resolved server-side = the submitter's (team leader's) Boundless managed wallet; no on-chain submission anchor is required. Positions and submissionIds must be unique within the array. */ + selections: components['schemas']['HackathonWinnerSelectionDto'][]; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + /** @description For MANAGED, the organization treasury wallet to sign with (the event contract-auth identity). ownerAddress must match it. Omit to use the caller's personal managed wallet. */ + sourceWalletId?: string; + }; + HackathonSubmitSignedXdrDto: { + /** + * @description The fully-signed XDR returned by the wallet (Freighter, Albedo, platform-managed signer, or a multisig coordinator). Backend submits this verbatim to Soroban RPC. + * @example AAAAAgAAAACdiamX7q...truncated... + */ + signedXdr: string; + }; + SubmitHackathonDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR. MANAGED signs server-side with the caller's platform-held wallet. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + /** + * @description On-chain content URI for the submission. Stored verbatim in the contract's submission anchor; off-chain content lives wherever the URI points (IPFS, S3, GitHub PR, etc.). + * @example ipfs://Qm.../project.json + */ + contentUri: string; + }; + WithdrawHackathonSubmissionDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR. MANAGED signs server-side with the caller's platform-held wallet. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + ContributeHackathonDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR. MANAGED signs server-side with the caller's platform-held wallet. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + /** + * @description Amount in token-native units (e.g. 30 = 30 USDC, NOT stroops). Must be >= 10 USDC (contract minimum). + * @example 30 + */ + amount: string; + }; + CreateOrganizationDto: Record; + OrganizationProfileStatsDto: { + /** + * @description Number of projects under this organization + * @example 12 + */ + projectsCount: number; + /** + * @description Total hackathons run by this organization + * @example 5 + */ + totalHackathons: number; + /** + * @description Total bounties offered by this organization + * @example 8 + */ + totalBounties: number; + /** + * @description Total grants (projects with grants) under this organization + * @example 3 + */ + totalGrants: number; + }; + OrganizationProfileDto: { + /** + * @description Organization ID + * @example org_1234567890 + */ + id: string; + /** + * @description Organization name + * @example Tech Innovators + */ + name: string; + /** + * @description Organization slug + * @example tech-innovators + */ + slug: string; + /** + * @description Logo URL + * @example https://example.com/logo.png + */ + logoUrl: string; + /** + * @description Organization description (from about or tagline) + * @example We are a community of developers building the future. + */ + description: string; + /** @description Key stats for the organization profile */ + stats: components['schemas']['OrganizationProfileStatsDto']; + }; + UpdateOrganizationDto: Record; + UpdateMemberRoleDto: Record; + InviteMemberDto: Record; + TreasuryWalletResponseDto: { + id: string; + organizationId: string; + /** @enum {string} */ + kind: 'MANAGED' | 'CONNECTED'; + publicKey: string; + label: string; + isDefault: boolean; + /** @enum {string} */ + status: 'ACTIVE' | 'ARCHIVED' | 'NEEDS_REVIEW'; + isMultisig: boolean; + multisigThreshold: number | null; + connectionMethod: string | null; + lastVerifiedAt: string | null; + createdAt: string; + updatedAt: string; + }; + CreateManagedWalletDto: { + /** + * @description Display label for the wallet + * @example Main treasury + */ + label: string; + }; + RegisterConnectedWalletDto: { + /** @description G-address of the external wallet */ + publicKey: string; + /** + * @description Display label + * @example Company multisig + */ + label: string; + /** @enum {string} */ + connectionMethod: + | 'freighter' + | 'lobstr' + | 'albedo' + | 'xbull' + | 'hana' + | 'rabet' + | 'walletkit_generic'; + }; + UpdateTreasuryWalletDto: { + /** @description New display label */ + label?: string; + /** @description Make this the organization default */ + isDefault?: boolean; + }; + WalletBalanceResponseDto: { + publicKey: string; + /** @description USDC balance */ + usdc: string; + /** @description XLM balance (fee float) */ + xlm: string; + }; + TreasuryPolicyRuleDto: { + /** @example 0 */ + min_usdc: number; + /** @example 1000 */ + max_usdc?: Record | null; + /** @example 1 */ + required_approvals: number; + /** + * @example [ + * "owner", + * "admin" + * ] + */ + approver_roles: string[]; + }; + TreasuryPolicyResponseDto: { + organizationId: string; + defaultWalletId: string | null; + rules: components['schemas']['TreasuryPolicyRuleDto'][]; + /** @description True when no policy is saved yet (defaults returned) */ + isDefault: boolean; + updatedAt: string | null; + }; + UpdateTreasuryPolicyDto: { + rules: components['schemas']['TreasuryPolicyRuleDto'][]; + /** @description Default source wallet id */ + defaultWalletId?: string; + }; + InitiateSpendDto: { + /** @description Treasury wallet to spend from */ + sourceWalletId: string; + /** @description Destination G-address or escrow contract id */ + destination: string; + /** + * @description Amount in USDC + * @example 2500.00 + */ + amount: string; + /** + * @description What the spend funds + * @example fund_hackathon_escrow + */ + purpose: string; + /** @enum {string} */ + referenceType?: 'hackathon' | 'bounty' | 'grant'; + referenceId?: string; + }; + SpendRequestResponseDto: { + id: string; + organizationId: string; + sourceWalletId: string; + destination: string; + amount: string; + currency: string; + purpose: string; + referenceType: string | null; + referenceId: string | null; + initiatorUserId: string; + requiredApprovals: number; + approvals: Record[]; + status: string; + onChainTxHash: string | null; + createdAt: string; + approvedAt: string | null; + }; + SpendDecisionDto: { + /** @description Optional note for the decision */ + note?: string; + }; + BuildSpendXdrResponseDto: { + /** @description Unsigned transaction XDR to sign in-browser */ + unsignedXdr: string; + request: components['schemas']['SpendRequestResponseDto']; + }; + SubmitSpendSignedXdrDto: { + /** @description The browser-signed transaction XDR */ + signedXdr: string; + }; + TreasuryAuditEntryDto: { + id: string; + action: string; + actorUserId: string | null; + actorKind: string; + walletId: string | null; + spendRequestId: string | null; + details: { + [key: string]: unknown; + } | null; + createdAt: string; + }; + TreasuryAuditLogResponseDto: { + data: components['schemas']['TreasuryAuditEntryDto'][]; + total: number; + page: number; + limit: number; + }; + CreateVoteDto: { + /** @description ID of the project being voted on */ + projectId: string; + /** + * @description Type of entity being voted on + * @enum {string} + */ + entityType: + | 'PROJECT' + | 'CROWDFUNDING_CAMPAIGN' + | 'HACKATHON_SUBMISSION' + | 'GRANT'; + /** + * @description Type of vote (UPVOTE or DOWNVOTE) + * @default UPVOTE + * @enum {string} + */ + voteType: 'UPVOTE' | 'DOWNVOTE'; + /** + * @description Weight of the vote + * @default 1 + */ + weight: number; + }; + CreateBlogPostDto: { + /** + * @description Blog post title + * @example Getting Started with Stellar Smart Contracts + */ + title: string; + /** + * @description Blog post content in markdown format + * @example # Introduction + * + * This tutorial will teach you... + */ + content: string; + /** + * @description Short excerpt or summary + * @example Learn how to build your first smart contract on Stellar + */ + excerpt?: string; + /** + * @description Cover image URL + * @example https://res.cloudinary.com/demo/image/upload/v1234567890/post-cover.jpg + */ + coverImage?: string; + /** + * @description Post status + * @default DRAFT + * @example DRAFT + * @enum {string} + */ + status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED' | 'SCHEDULED'; + /** + * @description Post tags + * @example [ + * "smart-contracts", + * "soroban", + * "tutorial" + * ] + */ + tags?: string[]; + /** + * @description Post categories + * @example [ + * "tutorials" + * ] + */ + categories?: string[]; + /** + * @description Mark as featured post + * @default false + * @example false + */ + isFeatured: boolean; + /** + * @description Pin post to top + * @default false + * @example false + */ + isPinned: boolean; + /** + * @description Reading time in minutes (auto-calculated if not provided) + * @example 5 + */ + readingTime?: number; + /** @description SEO title (overrides post title) */ + seoTitle?: string; + /** @description SEO meta description */ + seoDescription?: string; + /** + * @description SEO keywords + * @example [ + * "stellar", + * "blockchain", + * "smart contracts" + * ] + */ + seoKeywords?: string[]; + /** + * @description Schedule publication date (for SCHEDULED status) + * @example 2025-12-31T10:00:00Z + */ + scheduledFor?: string; + /** + * @description Generate AI content (excerpt, reading time, SEO, tags, category) if not provided + * @default false + * @example true + */ + generateAI: boolean; + }; + UpdateBlogPostDto: Record; + MetricDataDto: { + /** + * @description The metric value + * @example 1250 + */ + value: number; + /** + * @description Percentage change + * @example 12.5 + */ + change: number; + /** + * @description Type of change + * @example positive + * @enum {string} + */ + changeType: 'positive' | 'negative' | 'neutral'; + /** + * @description Metric label + * @example Total Users + */ + label: string; + /** + * @description Additional description + * @example Active users in the platform + */ + description?: string; + }; + HackathonMetricDataDto: { + /** + * @description The metric value + * @example 1250 + */ + value: number; + /** + * @description Percentage change + * @example 12.5 + */ + change: number; + /** + * @description Type of change + * @example positive + * @enum {string} + */ + changeType: 'positive' | 'negative' | 'neutral'; + /** + * @description Metric label + * @example Total Users + */ + label: string; + /** + * @description Additional description + * @example Active users in the platform + */ + description?: string; + /** + * @description Additional hackathon info + * @example 3 active, 7 upcoming + */ + additionalInfo?: string; + }; + OverviewMetricsDto: { + totalUsers: components['schemas']['MetricDataDto']; + organizations: components['schemas']['MetricDataDto']; + projects: components['schemas']['MetricDataDto']; + hackathons: components['schemas']['HackathonMetricDataDto']; + }; + OverviewChartDataDto: { + data: components['schemas']['ChartDataPointDto'][]; + /** + * @description Time range for the chart + * @example 7d + * @enum {string} + */ + timeRange: '7d' | '30d' | '90d'; + }; + AdminOverviewResponseDto: { + metrics: components['schemas']['OverviewMetricsDto']; + chart: components['schemas']['OverviewChartDataDto']; + /** + * @description Last updated timestamp + * @example 2025-12-26T10:30:00Z + */ + lastUpdated: string; + }; + AdminCrowdfundingRejectDto: { + /** + * @description Reason for rejection + * @example Campaign does not meet requirements + */ + reason?: string; + }; + AdminCrowdfundingRequestRevisionDto: { + /** + * @description Message for the creator explaining requested revisions + * @example Please update the project description to be more detailed + */ + message: string; + /** + * @description Optional structured reasons + * @example [ + * "incomplete_description", + * "missing_team_info" + * ] + */ + reasons?: string[]; + }; + AdminCrowdfundingNoteDto: { + /** + * @description Short admin note or comment + * @example Reviewed initial submission + */ + note: string; + }; + AdminCrowdfundingAssignDto: { + /** + * @description Reviewer (user) id to assign + * @example 550e8400-e29b-41d4-a716-446655440000 + */ + reviewerId: string; + }; + ApproveMilestoneDto: { + /** + * @description Optional approval notes + * @example Milestone completed successfully + */ + notes?: string; + }; + RejectMilestoneDto: { + /** + * @description Rejection reason + * @example Incomplete deliverables + */ + reason: string; + /** + * @description Detailed feedback for rejection + * @example The submitted work does not meet the project requirements. Please revise and resubmit. + */ + feedback: string; + /** + * @description Deadline for resubmission + * @example 2025-02-01 + */ + resubmissionDeadline?: string; + }; + RequestMilestoneResubmissionDto: { + /** + * @description Feedback explaining what needs to change + * @example Please improve the documentation and add more test cases + */ + feedback: string; + /** + * @description Deadline for resubmission + * @example 2025-02-15 + */ + resubmissionDeadline: string; + }; + AddMilestoneReviewNoteDto: { + /** + * @description Review note content + * @example Reviewed the code quality and found it satisfactory + */ + note: string; + }; + ManualEscrowActionDto: { + /** + * @description Type of escrow action to execute + * @example RELEASE + * @enum {string} + */ + action: 'RELEASE' | 'REFUND' | 'PAUSE' | 'RESUME'; + /** + * @description Amount to transfer (for RELEASE/REFUND) + * @example 1000 + */ + amount?: number; + /** + * @description Optional notes for this action + * @example Releasing funds for completed milestone + */ + notes?: string; + /** + * @description Recipient address (for RELEASE/REFUND) + * @example GAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + */ + recipientAddress?: string; + }; + AssignDisputeDto: { + /** + * @description Admin user ID to assign dispute to + * @example 550e8400-e29b-41d4-a716-446655440000 + */ + adminId: string; + }; + AddDisputeNoteDto: { + /** + * @description Message content + * @example Contacted the project creator for more information + */ + message: string; + /** + * @description Whether this is an internal note (not visible to parties) + * @example false + */ + isInternal?: boolean; + }; + ResolveDisputeDto: { + /** + * @description Resolution type + * @example APPROVED_WITH_CONDITIONS + * @enum {string} + */ + resolution: + | 'APPROVED_WITH_CONDITIONS' + | 'REQUIRE_RESUBMISSION' + | 'PARTIAL_REFUND' + | 'FULL_REFUND' + | 'DISMISSED' + | 'ARBITRATION'; + /** + * @description Detailed notes explaining the resolution + * @example Approved with condition that milestone is completed by next week + */ + resolutionNotes: string; + }; + EscalateDisputeDto: { + /** + * @description Reason for escalation to arbitration + * @example Parties cannot agree on resolution terms + */ + reason: string; + }; + RejectManualProjectDto: Record; + RequestManualProjectChangesDto: Record; + RejectProjectEditDto: Record; + AdminWalletStatsDto: { + totalWallets: components['schemas']['MetricDataDto']; + activatedWallets: components['schemas']['MetricDataDto']; + inactiveWallets: components['schemas']['MetricDataDto']; + }; + AdminWalletUserDto: { + id: string; + name: string; + email: string; + username?: string; + image?: string; + }; + AdminWalletListItemDto: { + id: string; + publicKey: string; + isActivated: boolean; + /** Format: date-time */ + createdAt: string; + users: components['schemas']['AdminWalletUserDto'][]; + }; + AdminWalletListResponseDto: { + wallets: components['schemas']['AdminWalletListItemDto'][]; + total: number; + page: number; + limit: number; + totalPages: number; + }; + AdminWalletBalanceDto: { + balance: string; + assetCode: string; + assetIssuer?: string; + assetType: string; + }; + AdminWalletDetailsDto: { + id: string; + publicKey: string; + isActivated: boolean; + /** Format: date-time */ + createdAt: string; + balances: components['schemas']['AdminWalletBalanceDto'][]; + users: components['schemas']['AdminWalletUserDto'][]; + }; + ReviewWindowDto: { + /** @example 1 */ + minBusinessDays: number; + /** @example 3 */ + maxBusinessDays: number; + /** @description ISO timestamp by which the review is expected to complete. */ + estimatedCompletionAt: string; + }; + DeclineDetailsDto: { + /** @description Human-readable reason from Didit, if available. */ + reason?: string; + /** + * @description Whether the user is allowed to start a new verification. + * @example true + */ + canRetry: boolean; + }; + VerificationStatusDto: { + /** + * @description Normalized verification state. Frontend should hide the verify button unless this is one of: not_started, declined, abandoned, expired. + * @enum {string} + */ + state: + | 'not_started' + | 'in_progress' + | 'in_review' + | 'approved' + | 'declined' + | 'abandoned' + | 'expired'; + /** @description Whether the user can start a new verification session. */ + canStartNew: boolean; + /** @description Polite, render-ready copy summarising the current state. */ + message: string; + /** @description ISO timestamp when the user became verified. */ + verifiedAt?: string; + /** @description ISO timestamp of the last status transition. */ + reviewedAt?: string; + /** @description Estimated review window. Present only when state === "in_review". */ + reviewWindow?: components['schemas']['ReviewWindowDto']; + /** @description Decline details. Present only when state === "declined". */ + decline?: components['schemas']['DeclineDetailsDto']; + }; + CreateDiditSessionDto: Record; + PricingPreviewResponseDto: { + /** @description Effective rate applied to this preview. */ + feeBps: number; + /** @description Fee in stroops. String to preserve i128 precision. */ + feeStroops: string; + /** @description Pool released to winners; equals the requested budget. */ + poolStroops: string; + /** @description budgetStroops + feeStroops; what the organizer signs for. */ + totalDepositStroops: string; + /** @description Audit label for the rate choice: default | foundation-tier | sales-override:* | waiver:*. */ + reason: string; + }; + Function: Record; + BountyWinnerDistributionEntryDto: { + /** + * @description 1-indexed winner position. + * @example 1 + */ + position: number; + /** + * @description Percent of total_budget for this position. All entries sum to 100. + * @example 100 + */ + percent: number; + }; + PublishBountyEscrowDto: { + /** + * @description Stellar G-address that will own and sign the create_event transaction. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + ownerAddress: string; + /** + * @description Whitelisted Stellar Asset Contract address the prize is in. + * @example CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA + */ + tokenAddress: string; + /** + * @description Total prize in token-native units (e.g. 500 = 500 USDC, NOT stroops). String is required when the value exceeds the JS safe-integer range. + * @example 500 + */ + budget: string; + /** + * @description Submission deadline as a Unix timestamp in seconds. Required for bounties that close at a specific time. Pass null only for always-open bounties (rare). + * @example 1804383600 + */ + submissionDeadline: number | null; + /** + * @description Credits required to apply. Defaults to 1; raise on high-value bounties to deter spam. Max 100 (enforced by the contract). + * @default 1 + * @example 1 + */ + applicationCreditCost: number; + /** @description Override for the winner distribution. Defaults to 100% to position 1. */ + winnerDistribution?: components['schemas']['BountyWinnerDistributionEntryDto'][]; + /** @description Override for the content URI stored on chain. Defaults to https://api.boundless.fi/bounties//content. */ + contentUri?: string; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR for the wallet or multisig coordinator to sign. MANAGED has the backend sign and submit using the caller's platform-held wallet; the response is PENDING_CONFIRM with a txHash. + * @default EXTERNAL + * @example MANAGED + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + BountyEscrowOpResponseDto: { + /** @description Internal EscrowOp cuid. */ + id: string; + /** @description Hex-encoded 32-byte contract op_id. */ + opId: string; + /** @description Contract operation kind. */ + kind: string; + /** @description EscrowOp status. */ + status: string; + /** @description EntityKind (BOUNTY for this surface). */ + entityKind: string; + /** @description Bounty id. */ + entityId: string; + /** @description Unsigned XDR for the wallet to sign (PENDING_SIGN onward). */ + unsignedXdr?: string | null; + /** @description Stellar G-address expected to sign this op. */ + signerHint?: string | null; + /** @description Soroban tx hash (set once the op reaches PENDING_CONFIRM). */ + txHash?: string | null; + /** @description On-chain or platform-side error code when the op transitions to FAILED. */ + errorCode?: string | null; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + CancelBountyEscrowDto: { + /** + * @description Organizer's Stellar G-address that signs cancel_event. Must match the bounty's on-chain owner. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + ownerAddress: string; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side with the caller's platform-held wallet and submits. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + BountyWinnerSelectionDto: { + /** + * @description Stellar G-address of the applicant being declared winner. Must have an active submission anchor for this bounty. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description Winner position, 1-indexed. Must exist in the bounty's on-chain winner_distribution (the contract rejects unknown positions). + * @example 1 + */ + position: number; + /** + * @description Override the platform default credit_earn for this position. Defaults to 20/10/5 for positions 1/2/3 and 3 for the rest. Capped at 100 by the contract. + * @example 20 + */ + creditEarn?: number; + /** + * @description Override the platform default reputation_bump for this position. Defaults to 50/25/10 for positions 1/2/3 and 5 for the rest. + * @example 50 + */ + reputationBump?: number; + }; + SelectBountyWinnersDto: { + /** + * @description Organizer's Stellar G-address that signs select_winners. Must match the bounty's on-chain owner. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + ownerAddress: string; + /** @description Winners to declare. Each entry must reference an applicant with an active submission. Positions must be unique within the array. */ + selections: components['schemas']['BountyWinnerSelectionDto'][]; + /** + * @description Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side with the caller's platform-held wallet and submits. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + BountySubmitSignedXdrDto: { + /** @description Fully-signed XDR returned by the wallet or coordinator. */ + signedXdr: string; + }; + ApplyBountyDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + WithdrawApplicationDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + SubmitBountyDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + /** + * @description URI of the participant's submission content. Stored on chain in the contract's submission anchor; off-chain content lives wherever the URI points (S3, IPFS, GitHub PR, etc.). + * @example https://github.com/me/boundless-fix/pull/1 + */ + contentUri: string; + }; + WithdrawSubmissionDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + ContributeBountyDto: { + /** + * @description Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** + * @description EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + /** + * @description Amount in token-native units (e.g. 30 = 30 USDC, NOT stroops). Pass a string when the value exceeds the JS safe-integer range. Must be >= 10 USDC (contract minimum). + * @example 30 + */ + amount: string; + }; + CreateBountyApplicationDto: { + /** + * @description G-address that will receive payout if selected. + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + /** @description Light proposal text (LIGHT vetting): 100 to 300 words. Required for LIGHT mode. */ + proposalShort?: string; + /** @description Full proposal text (HEAVY vetting): 500 to 2000 words. Required for HEAVY mode. */ + proposalFull?: string; + /** @description Portfolio links. LIGHT: up to 3. HEAVY: up to 6. */ + portfolioLinks?: string[]; + /** @description Estimated days to complete (LIGHT). Required for LIGHT mode. */ + estimatedDays?: number; + /** @description Qualifications text (HEAVY). Required for HEAVY mode. */ + qualifications?: string; + /** @description Optional video intro URL (HEAVY). */ + videoIntroUrl?: string; + }; + EditBountyApplicationDto: { + /** @description Light proposal text. */ + proposalShort?: string; + /** @description Full proposal text. */ + proposalFull?: string; + portfolioLinks?: string[]; + estimatedDays?: number; + qualifications?: string; + videoIntroUrl?: string; + }; + SelectForPickDto: { + /** @description Application id to select as the single winner. */ + applicationId: string; + }; + CreateShortlistDto: { + /** @description Application ids to include in the shortlist. */ + applicationIds: string[]; + }; + DeclineApplicationDto: { + /** @description Reason for decline (surfaced to builder). */ + reason?: string; + }; + JoinShowdownDto: { + /** + * @description G-address that will receive payout if winning + * @example GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS + */ + applicantAddress: string; + }; + BountyPrizeTierPublicDto: { + position: number; + /** @description Tier amount in token-native units. */ + amount: string; + /** @description Optional minimum quality bar. */ + passMark?: number | null; + }; + BountyOrganizationPublicDto: { + id: string; + name: string; + slug?: string | null; + logo?: string | null; + }; + BountyPublicDto: { + id: string; + title: string; + description: string; + /** @description Pillar lifecycle state (lowercase). */ + status: string; + type: string; + rewardAmount: number; + rewardCurrency: string; + /** @enum {string} */ + vettingLevel?: 'NONE' | 'LIGHT' | 'HEAVY'; + /** @enum {string} */ + selectionMode?: 'PICK' | 'SHOWDOWN'; + /** @enum {string} */ + submissionVisibility: 'ORGANIZER_ONLY' | 'HIDDEN_UNTIL_DEADLINE'; + /** Format: date-time */ + applicationWindowCloseAt?: string | null; + maxApplicants?: number | null; + shortlistSize?: number | null; + reputationMinimum?: number | null; + prizeTiers: components['schemas']['BountyPrizeTierPublicDto'][]; + organization: components['schemas']['BountyOrganizationPublicDto']; + /** @description On-chain event id once published; null while in draft. */ + escrowEventId?: string | null; + escrowTxHash?: string | null; + /** Format: date-time */ + createdAt: string; + }; + BountyPublicListDto: { + bounties: components['schemas']['BountyPublicDto'][]; + total: number; + page: number; + limit: number; + }; + GrantWinnerDistributionEntryDto: { + /** + * @description 1-indexed winner position + * @example 1 + */ + position: number; + /** + * @description Percent of total_budget for this position. All sum to 100. + * @example 100 + */ + percent: number; + }; + PublishGrantEscrowDto: { + /** + * @description Organizer's Stellar G-address that signs the create_event transaction. + * @example GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ + */ + ownerAddress: string; + /** + * @description Whitelisted Stellar Asset Contract address. + * @example CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA + */ + tokenAddress: string; + /** + * @description Total budget in token-native units (NOT stroops). + * @example 500 + */ + budget: string; + /** + * @description Number of milestones (n) for the ReleaseKind::Multi(n) release_kind. Per-recipient amount is total_budget * winner_share% / 100 / n_milestones. + * @example 2 + */ + nMilestones: number; + /** + * @description Optional submission deadline (Unix seconds). + * @example 1804383600 + */ + submissionDeadline?: number; + /** @description Override the winner distribution. Defaults to 100% to position 1. */ + winnerDistribution?: components['schemas']['GrantWinnerDistributionEntryDto'][]; + /** @description Override the public content_uri. Defaults to /grants//content. */ + contentUri?: string; + /** + * @description Signing path. EXTERNAL (default) or MANAGED. + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + GrantEscrowOpResponseDto: { + id: string; + opId: string; + kind: string; + status: string; + entityKind: string; + entityId: string; + unsignedXdr?: string | null; + signerHint?: string | null; + txHash?: string | null; + errorCode?: string | null; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + CancelGrantEscrowDto: { + /** @description Organizer's Stellar G-address. */ + ownerAddress: string; + /** + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + GrantWinnerSelectionDto: { + /** @description GrantApplication.id to declare as a winner. The application must already have applicantAddress set (the Stellar G-address receiving the grant). */ + grantApplicationId: string; + /** + * @description Winner position, 1-indexed. + * @example 1 + */ + position: number; + /** @example 20 */ + creditEarn?: number; + /** @example 50 */ + reputationBump?: number; + }; + SelectGrantWinnersDto: { + ownerAddress: string; + selections: components['schemas']['GrantWinnerSelectionDto'][]; + /** + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + ClaimGrantMilestoneDto: { + ownerAddress: string; + /** @description GrantMilestone.id to claim payment for. */ + grantMilestoneId: string; + /** + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + GrantSubmitSignedXdrDto: { + signedXdr: string; + }; + ContributeGrantDto: { + /** @description Contributor's Stellar G-address. Must match caller's wallet. */ + applicantAddress: string; + /** + * @description Amount in token-native units. Must be >= 10 USDC. + * @example 30 + */ + amount: string; + /** + * @default EXTERNAL + * @enum {string} + */ + fundingMode: 'EXTERNAL' | 'MANAGED'; + }; + GrantPublicListItemDto: { + /** + * @description Grant id. + * @example grant_123 + */ + id: string; + /** + * @description Underlying project title used as the card title. + * @example On-chain governance research + */ + title: string; + /** + * @description Short tagline/summary. Empty string when none is available. + * @example Funding research into delegated voting models. + */ + summary: string; + /** + * @description Banner or thumbnail image URL. + * @example https://cdn.boundless.dev/grants/abc.png + */ + coverImageUrl: string | null; + /** + * @description Lowercased grant status. + * @example open + */ + status: string; + /** + * @description Total program budget in USDC, stringified. + * @example 50000 + */ + totalBudgetUsdc: string | null; + /** + * @description Owning organization id, if any. + * @example org_123 + */ + organizationId: string | null; + /** + * @description Owning organization display name. + * @example Boundless Labs + */ + organizationName: string | null; + /** + * @description Owning organization logo URL. + * @example https://cdn.boundless.dev/orgs/boundless.png + */ + organizationLogoUrl: string | null; + /** + * @description Underlying project category, if any. + * @example governance + */ + category: string | null; + /** + * @description Total submitted applications count. + * @example 12 + */ + applicationCount: number; + /** + * @description When the grant was created. + * @example 2026-05-01T12:00:00.000Z + */ + createdAt: string; + }; + GrantPublicListResponseDto: { + items: components['schemas']['GrantPublicListItemDto'][]; + /** + * @description Total count of grants matching the filters. + * @example 84 + */ + total: number; + /** + * @description Current page (1-indexed). + * @example 1 + */ + page: number; + /** + * @description Items per page. + * @example 20 + */ + limit: number; + }; + /** + * @description The pillar this opportunity belongs to. + * @enum {string} + */ + OpportunityType: 'BOUNTY' | 'HACKATHON' | 'GRANT' | 'CROWDFUNDING'; + OpportunityListItemDto: { + /** + * @description The pillar this opportunity belongs to. + * @example BOUNTY + */ + type: components['schemas']['OpportunityType']; + /** + * @description Pillar-local primary key. Globally unique within a type. + * @example ckxyz123 + */ + id: string; + /** + * @description Optional URL slug. Hackathons and crowdfunding campaigns expose one; bounties and grants do not. + * @example open-defi-hack + */ + slug: string | null; + /** + * @description Display title for the card. + * @example Build a DAO governance dashboard + */ + title: string; + /** + * @description Short blurb shown under the title. Empty string when the underlying pillar has no summary; never null. + * @example Ship a React dashboard that visualizes on-chain governance votes. + */ + summary: string; + /** + * @description Banner or hero image URL for the card. + * @example https://cdn.boundless.dev/banners/abc.png + */ + coverImageUrl: string | null; + /** + * @description Owning organization id. Null on crowdfunding or grants that lack an organization. + * @example org_123 + */ + organizationId: string | null; + /** + * @description Owning organization display name. + * @example Boundless Labs + */ + organizationName: string | null; + /** + * @description Owning organization logo URL. + * @example https://cdn.boundless.dev/orgs/boundless.png + */ + organizationLogoUrl: string | null; + /** + * @description Lowercased pillar-specific status (e.g. "open", "upcoming", "active"). + * @example open + */ + status: string; + /** + * @description Total advertised reward in USDC, stringified. Null when not applicable to the pillar. + * @example 5000.00 + */ + totalRewardUsdc: string | null; + /** + * @description Funded amount so far in USDC, crowdfunding only. Null elsewhere. + * @example 1234.56 + */ + fundedAmountUsdc: string | null; + /** + * @description When this opportunity went live. Falls back to createdAt when the pillar lacks publishedAt. + * @example 2026-05-01T12:00:00.000Z + */ + publishedAt: string; + /** + * @description When the opportunity window opens. + * @example 2026-05-15T00:00:00.000Z + */ + startsAt: string | null; + /** + * @description Application or submission deadline. Null for open-ended pillars (notably grants). + * @example 2026-06-30T23:59:59.000Z + */ + endsAt: string | null; + /** + * @description Approximate participant count. Null when the pillar has no relation to count from. + * @example 42 + */ + participantCount: number | null; + /** + * @description Pillar-defined tags. Empty array for pillars without a tag field; never null. + * @example [ + * "stellar", + * "defi" + * ] + */ + tags: string[]; + /** + * @description Path to the detail page on the frontend. + * @example /bounties/ckxyz123 + */ + detailUrl: string; + /** + * @description True when this opportunity is currently featured. Drives the page-1 boost in the marketplace. + * @example false + */ + isFeatured: boolean; + }; + OpportunityListResponseDto: { + /** @description Cards in the current page, post-merge. */ + items: components['schemas']['OpportunityListItemDto'][]; + /** + * @description Opaque cursor for the next page. Null when no more results are available. + * @example eyJzb3J0IjoibmV3ZXN0IiwicHJpbWFyeSI6IjIwMjYtMDUtMTVUMDA6MDA6MDAuMDAwWiIsImlkIjoiY2t4eXoxMjMifQ + */ + nextCursor: string | null; + /** + * @description Total rows matching the current filter combo (type, status, search, tags), summed across pillar adapters. Cursor-blind, so stable across paginated requests with the same filters. + * @example 137 + */ + total: number; + }; + SubscribeDto: { + /** + * @description Email address to subscribe + * @example user@example.com + */ + email: string; + /** + * @description Subscriber name + * @example John Doe + */ + name?: string; + /** + * @description Subscription source + * @example website + */ + source?: string; + /** + * @description Topic tags for subscription preferences + * @example [ + * "updates", + * "hackathons" + * ] + */ + tags?: string[]; + }; + UnsubscribeDto: { + /** + * @description Email address to unsubscribe + * @example user@example.com + */ + email: string; + }; + UpdatePreferencesDto: { + /** + * @description Subscriber email address + * @example user@example.com + */ + email: string; + /** + * @description Topic tags to subscribe to. Valid: bounties, hackathons, grants, updates + * @example [ + * "updates", + * "hackathons" + * ] + */ + tags: string[]; + }; + CreateNewsletterCampaignDto: { + /** + * @description Campaign email subject line + * @example Boundless Weekly: New Hackathon Announced! + */ + subject: string; + /** + * @description Campaign HTML content. Supports {{name}} placeholder. + * @example

Hello {{name}}

Check out our latest hackathon!

+ */ + content: string; + /** + * @description Preview text shown in email clients + * @example New hackathon with $10k in prizes + */ + previewText?: string; + /** + * @description Target subscriber tags — only subscribers with matching tags receive the campaign + * @example [ + * "hackathons", + * "updates" + * ] + */ + tags?: string[]; + }; + User: { + id?: string; + name: string; + email: string; + /** @default false */ + readonly emailVerified: boolean; + image?: string; + /** + * Format: date-time + * @default Generated at runtime + */ + createdAt: string; + /** + * Format: date-time + * @default Generated at runtime + */ + updatedAt: string; + username?: string; + displayUsername?: string; + /** @default false */ + readonly twoFactorEnabled: boolean; + readonly lastLoginMethod?: string; + readonly role?: string; + /** @default false */ + readonly banned: boolean; + readonly banReason?: string; + /** Format: date-time */ + readonly banExpires?: string; + }; + Session: { + id?: string; + /** Format: date-time */ + expiresAt: string; + token: string; + /** + * Format: date-time + * @default Generated at runtime + */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + ipAddress?: string; + userAgent?: string; + userId: string; + activeOrganizationId?: string; + impersonatedBy?: string; + }; + Account: { + id?: string; + accountId: string; + providerId: string; + userId: string; + accessToken?: string; + refreshToken?: string; + idToken?: string; + /** Format: date-time */ + accessTokenExpiresAt?: string; + /** Format: date-time */ + refreshTokenExpiresAt?: string; + scope?: string; + password?: string; + /** + * Format: date-time + * @default Generated at runtime + */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + Verification: { + id?: string; + identifier: string; + value: string; + /** Format: date-time */ + expiresAt: string; + /** + * Format: date-time + * @default Generated at runtime + */ + createdAt: string; + /** + * Format: date-time + * @default Generated at runtime + */ + updatedAt: string; + }; + TwoFactor: { + id?: string; + secret: string; + backupCodes: string; + userId: string; + }; + Organization: { + id?: string; + name: string; + slug: string; + logo?: string; + /** Format: date-time */ + createdAt: string; + metadata?: string; + }; + Member: { + id?: string; + organizationId: string; + userId: string; + /** @default member */ + role: string; + /** Format: date-time */ + createdAt: string; + }; + Invitation: { + id?: string; + organizationId: string; + email: string; + role?: string; + /** @default pending */ + status: string; + /** Format: date-time */ + expiresAt: string; + /** + * Format: date-time + * @default Generated at runtime + */ + createdAt: string; + inviterId: string; + }; + Passkey: { + id?: string; + name?: string; + publicKey: string; + userId: string; + credentialID: string; + counter: number; + deviceType: string; + backedUp: boolean; + transports?: string; + /** Format: date-time */ + createdAt?: string; + aaguid?: string; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + AppController_getHello: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_getNotifications: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_getUnreadCount: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_markAsRead: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_markAllAsRead: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_deleteNotification: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_getPreferences: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_updatePreferences: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['NotificationPreferencesDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_sendTestNotification: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NotificationsController_triggerMarketingCron: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SettingsController_getSettings: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Settings retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SettingsController_updateNotificationSettings: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Notification settings object */ + requestBody: { + content: { + 'application/json': string; + }; + }; + responses: { + /** @description Notification settings updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SettingsController_updatePrivacySettings: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdatePrivacySettingsDto']; + }; + }; + responses: { + /** @description Privacy settings updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SettingsController_updateAppearanceSettings: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateAppearanceSettingsDto']; + }; + }; + responses: { + /** @description Appearance settings updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EarningsController_getEarningsPublic: { + parameters: { + query: { + /** @description Max activities to return (default 100) */ + limit?: number; + /** @description Offset for activity pagination */ + offset?: number; + /** @description Username of the profile to fetch earnings for */ + username: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Public earnings retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['PublicEarningsResponseDto']; + }; + }; + /** @description Missing or invalid username */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EarningsController_getEarnings: { + parameters: { + query?: { + /** @description Max activities to return (default 100) */ + limit?: number; + /** @description Offset for activity pagination */ + offset?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Earnings data retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['EarningsResponseDto']; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EarningsController_withdraw: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['WithdrawRequestDto']; + }; + }; + responses: { + /** @description Withdrawal submitted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + withdrawalId?: string; + transactionHash?: string; + message?: string; + }; + }; + }; + /** @description Invalid request or not claimable */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Identity verification required. Complete KYC to withdraw funds. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EarningsController_confirmRelease: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ConfirmReleaseDto']; + }; + }; + responses: { + /** @description Release submitted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ConfirmReleaseResponseDto']; + }; + }; + /** @description Invalid request or submit failed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Identity verification required. Complete KYC to release funds. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UserController_getProfile: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User dashboard with profile, stats, chart data, activities graph, and recent activities retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['DashboardDto']; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UserController_getPublic: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Public route accessed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UserController_getOptional: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Optional auth route accessed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UserController_getUserByUsername: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Username of the user to retrieve */ + username: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User profile retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UserController_getUserFollowers: { + parameters: { + query?: { + /** @description Pagination offset */ + offset?: number; + /** @description Number of followers to return */ + limit?: number; + }; + header?: never; + path: { + /** @description Username of the user */ + username: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Followers retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UserController_getUserFollowing: { + parameters: { + query?: { + /** @description Filter by entity type */ + entityType?: + | 'USER' + | 'PROJECT' + | 'ORGANIZATION' + | 'CROWDFUNDING_CAMPAIGN' + | 'BOUNTY' + | 'GRANT' + | 'HACKATHON'; + /** @description Pagination offset */ + offset?: number; + /** @description Number of following to return */ + limit?: number; + }; + header?: never; + path: { + /** @description Username of the user */ + username: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Following list retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProfileController_getProfile: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Profile retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProfileController_updateProfile: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateProfileDto']; + }; + }; + responses: { + /** @description Profile updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProfileController_getProfileStats: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Profile stats retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProfileController_getActivity: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Activity retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProfileController_uploadAvatar: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'multipart/form-data': { + /** + * Format: binary + * @description Avatar image file + */ + avatar?: string; + }; + }; + }; + responses: { + /** @description Avatar uploaded successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PreferencesController_getPreferences: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Preferences retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PreferencesController_updateLanguage: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @example en */ + language?: string; + }; + }; + }; + responses: { + /** @description Language preference updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PreferencesController_updateTimezone: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @example America/New_York */ + timezone?: string; + }; + }; + }; + responses: { + /** @description Timezone preference updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PreferencesController_updateCategoryPreferences: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** + * @example [ + * "tech", + * "design" + * ] + */ + categories?: string[]; + }; + }; + }; + responses: { + /** @description Category preferences updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PreferencesController_updateSkillPreferences: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** + * @example [ + * "javascript", + * "react" + * ] + */ + skills?: string[]; + }; + }; + }; + responses: { + /** @description Skill preferences updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UsersController_getUsers: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Users retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UsersController_getUser: { + parameters: { + query?: never; + header?: never; + path: { + /** @description User ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid user ID */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UsersController_updateUser: { + parameters: { + query?: never; + header?: never; + path: { + /** @description User ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateUserDto']; + }; + }; + responses: { + /** @description User updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UsersController_deleteUser: { + parameters: { + query?: never; + header?: never; + path: { + /** @description User ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UsersController_getUserProfile: { + parameters: { + query?: never; + header?: never; + path: { + /** @description User ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User profile retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_uploadSingle: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description File upload data */ + requestBody: { + content: { + 'multipart/form-data': { + /** + * Format: binary + * @description File to upload + */ + file?: string; + /** + * @description Folder to upload to + * @example boundless/projects/project123 + */ + folder?: string; + /** + * @description Tags for the file + * @example [ + * "project", + * "logo" + * ] + */ + tags?: string[]; + /** @description Image transformation options */ + transformation?: { + /** @example 400 */ + width?: number; + /** @example 400 */ + height?: number; + /** @example fit */ + crop?: string; + /** @example auto */ + quality?: string; + /** @example auto */ + format?: string; + }; + }; + }; + }; + responses: { + /** @description File uploaded successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['UploadResponseDto']; + }; + }; + /** @description Invalid file or upload failed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_uploadMultiple: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Multiple files upload data */ + requestBody: { + content: { + 'multipart/form-data': { + /** @description Files to upload */ + files?: string[]; + /** + * @description Folder to upload to + * @example boundless/projects/project123/gallery + */ + folder?: string; + /** + * @description Tags for the files + * @example [ + * "project", + * "gallery" + * ] + */ + tags?: string[]; + }; + }; + }; + responses: { + /** @description Files uploaded successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['MultipleUploadResponseDto']; + }; + }; + /** @description Invalid files or upload failed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_deleteFile: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Public ID of the file to delete */ + publicId: string; + /** @description Type of resource */ + resourceType: 'image' | 'video' | 'raw'; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description File deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example true */ + success?: boolean; + /** @example File deleted successfully */ + message?: string; + }; + }; + }; + /** @description File not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_getFileInfo: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Public ID of the file */ + publicId: string; + /** @description Type of resource */ + resourceType: 'image' | 'video' | 'raw'; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description File information retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['FileInfoResponseDto']; + }; + }; + /** @description File not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_searchFiles: { + parameters: { + query?: { + /** @description Maximum number of results */ + maxResults?: number; + /** @description Resource type to filter by */ + resourceType?: 'image' | 'video' | 'raw'; + /** @description Folder to search in */ + folder?: unknown; + /** @description Tags to filter by */ + tags?: string[]; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Files found successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SearchFilesResponseDto']; + }; + }; + /** @description Search failed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_generateOptimizedUrl: { + parameters: { + query?: { + /** @description Output format */ + format?: unknown; + /** @description Quality setting */ + quality?: unknown; + /** @description Crop mode */ + crop?: unknown; + /** @description Desired height */ + height?: number; + /** @description Desired width */ + width?: number; + }; + header?: never; + path: { + /** @description Public ID of the file */ + publicId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Optimized URL generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['OptimizedUrlResponseDto']; + }; + }; + /** @description Failed to generate URL */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_generateResponsiveUrls: { + parameters: { + query?: { + /** @description Output format */ + format?: unknown; + /** @description Quality setting */ + quality?: unknown; + /** @description Crop mode */ + crop?: unknown; + /** @description Base height for responsive breakpoints */ + height?: number; + /** @description Base width for responsive breakpoints */ + width?: number; + }; + header?: never; + path: { + /** @description Public ID of the file */ + publicId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Responsive URLs generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ResponsiveUrlsResponseDto']; + }; + }; + /** @description Failed to generate responsive URLs */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_generateAvatarUrl: { + parameters: { + query?: { + /** @description Avatar size (square) */ + size?: number; + }; + header?: never; + path: { + /** @description Public ID of the image file */ + publicId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Avatar URL generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['OptimizedUrlResponseDto']; + }; + }; + /** @description Failed to generate avatar URL */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_generateLogoUrl: { + parameters: { + query?: { + /** @description Logo height */ + height?: number; + /** @description Logo width */ + width?: number; + }; + header?: never; + path: { + /** @description Public ID of the image file */ + publicId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Logo URL generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['OptimizedUrlResponseDto']; + }; + }; + /** @description Failed to generate logo URL */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_generateBannerUrl: { + parameters: { + query?: { + /** @description Banner height */ + height?: number; + /** @description Banner width */ + width?: number; + }; + header?: never; + path: { + /** @description Public ID of the image file */ + publicId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Banner URL generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['OptimizedUrlResponseDto']; + }; + }; + /** @description Failed to generate banner URL */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadController_getUsageStats: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Usage statistics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['UsageStatsResponseDto']; + }; + }; + /** @description Failed to get usage stats */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuthController_register: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RegisterDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuthController_login: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['LoginDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuthController_refreshToken: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RefreshTokenDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuthController_logout: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuthController_getProfile: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuthController_verifyStellarSignature: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['VerifySignatureDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OAuthController_googleAuth: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OAuthController_googleAuthCallback: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OAuthController_githubAuth: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OAuthController_githubAuthCallback: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OAuthController_twitterAuth: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OAuthController_twitterAuthCallback: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + FollowsController_followEntity: { + parameters: { + query?: never; + header?: never; + path: { + entityType: string; + entityId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + FollowsController_unfollowEntity: { + parameters: { + query?: never; + header?: never; + path: { + entityType: string; + entityId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + FollowsController_getUserFollowing: { + parameters: { + query: { + entityType: string; + }; + header?: never; + path: { + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + FollowsController_getEntityFollowers: { + parameters: { + query?: never; + header?: never; + path: { + entityType: string; + entityId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + FollowsController_getFollowStats: { + parameters: { + query?: never; + header?: never; + path: { + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + FollowsController_isFollowing: { + parameters: { + query?: never; + header?: never; + path: { + entityType: string; + entityId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ChatController_getMessages: { + parameters: { + query: { + roomId: string; + roomType: string; + cursor?: string; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns list of messages. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MessagesController_listConversations: { + parameters: { + query?: { + limit?: number; + offset?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of conversations */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MessagesController_startOrGetConversation: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateConversationDto']; + }; + }; + responses: { + /** @description Conversation (created or existing) */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MessagesController_getConversation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Conversation ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Conversation details */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MessagesController_listMessages: { + parameters: { + query?: { + limit?: number; + /** @description Cursor for older messages */ + before?: string; + }; + header?: never; + path: { + /** @description Conversation ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated messages */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MessagesController_sendMessage: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Conversation ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateMessageDto']; + }; + }; + responses: { + /** @description Message created */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MessagesController_markConversationRead: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Conversation ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Marked as read */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_validateCampaign: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateCampaignDto']; + }; + }; + responses: { + /** @description Campaign data is valid */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid campaign data */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getCampaigns: { + parameters: { + query: { + /** @description Category of the campaign */ + category?: string; + /** @description Status of the campaign */ + status?: 'active' | 'funded' | 'completed'; + minFundingGoal?: number; + /** @description Minimum funding goal of the campaign */ + maxFundingGoal?: number; + /** @description Maximum funding goal of the campaign */ + page?: number; + /** @description Limit of the campaign */ + limit?: number; + /** @description Sort by of the campaign */ + sortBy: string; + /** @description Sort order of the campaign */ + sortOrder: string; + /** @description Search of the campaign */ + search?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaigns retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_createCampaign: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateCampaignDto']; + }; + }; + responses: { + /** @description Campaign and project created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid campaign data */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_triggerCron: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Cron job triggered successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getMyCampaigns: { + parameters: { + query: { + /** @description Category of the campaign */ + category: string; + /** @description Status of the campaign */ + status: string; + minFundingGoal: number; + /** @description Minimum funding goal of the campaign */ + maxFundingGoal: number; + /** @description Maximum funding goal of the campaign */ + page?: number; + /** @description Limit of the campaign */ + limit?: number; + /** @description Sort by of the campaign */ + sortBy?: string; + /** @description Sort order of the campaign */ + sortOrder?: string; + /** @description Search of the campaign */ + search: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User campaigns retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getCampaignBySlug: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign URL slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getCampaign: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_updateCampaign: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateCampaignDto']; + }; + }; + responses: { + /** @description Campaign updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User does not own the campaign */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_deleteCampaign: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Cannot delete campaign with contributions, campaigns in funding phase, funded campaigns, completed campaigns, or user does not own the campaign */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getCampaignStatistics: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign statistics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_updateEscrowDetails: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateEscrowDto']; + }; + }; + responses: { + /** @description Escrow details updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User does not own the campaign */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getInvitations: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_inviteTeamMember: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['InviteTeamMemberDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_acceptInvitation: { + parameters: { + query: { + token: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ContributionsController_contributeToCampaign: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ContributeCampaignDto']; + }; + }; + responses: { + /** @description Contribution added successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign has ended or is fully funded */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ContributionsController_getCampaignContributions: { + parameters: { + query?: { + page?: number; + limit?: number; + }; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Contributions retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ContributionsController_getContributionStats: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Contribution statistics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MilestonesController_getCampaignMilestones: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Milestones retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MilestonesController_getMilestone: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + /** @description Milestone ID */ + milestoneId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Milestone details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Milestone not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MilestonesController_updateMilestone: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + /** @description Milestone ID */ + milestoneId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateMilestoneDto']; + }; + }; + responses: { + /** @description Milestone submitted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Validation failed - invalid proof of work data */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User does not own the campaign */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MilestonesController_validateMilestoneSubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + /** @description Milestone ID */ + milestoneId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ValidateMilestoneSubmissionDto']; + }; + }; + responses: { + /** @description Validation successful */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example true */ + validated?: boolean; + data?: { + /** @example submitted */ + status?: string; + /** @example Milestone completed - all deliverables ready for review. */ + evidence?: string; + /** + * @example [ + * "https://example.com/report.pdf" + * ] + */ + documents?: string[]; + }; + }; + }; + }; + /** @description Validation failed */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example false */ + validated?: boolean; + /** @example Evidence must be at least 10 characters of meaningful content */ + error?: string; + }; + }; + }; + }; + }; + MilestonesController_getMilestoneStats: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Milestone statistics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BuilderCrowdfundingV2Controller_submitForReview: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BuilderCrowdfundingV2Controller_withdrawSubmission: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BuilderCrowdfundingV2Controller_reviseAndResubmit: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BuilderCrowdfundingV2Controller_publish: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PublishCrowdfundingEscrowDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BuilderCrowdfundingV2Controller_cancel: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CancelCrowdfundingEscrowDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BuilderCrowdfundingV2Controller_claimMilestone: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ClaimCrowdfundingMilestoneDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BackerCrowdfundingV2Controller_contribute: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ContributeCrowdfundingDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommunityCrowdfundingV2Controller_getTally: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommunityCrowdfundingV2Controller_castVote: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CastCrowdfundingVoteDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommunityCrowdfundingV2Controller_getMyVote: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingV2Controller_approve: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ApproveCrowdfundingCampaignDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingV2Controller_reject: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RejectCrowdfundingCampaignDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingV2Controller_pause: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PauseCrowdfundingCampaignDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingV2Controller_unpause: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_getWallet: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_getWalletDetails: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_getAddressBalance: { + parameters: { + query?: never; + header?: never; + path: { + address: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_syncWallet: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_createWallet: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_activate: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Wallet activated. Returns tx hash and added trustlines. */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Sponsorship not configured, or unexpected submit error. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Sponsor account is out of available XLM. Operators have been alerted; retry later. */ + 503: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_reclaimDormant: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ReclaimDormantDto']; + }; + }; + responses: { + /** @description Reclaim summary: scanned, eligible, revoked, freedXlm, walletIds, errors */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_getSupportedTrustlines: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of supported trustline assets */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_addTrustline: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AddTrustlineDto']; + }; + }; + responses: { + /** @description Trustline added or already exists */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Wallet not activated, insufficient XLM for fees, or unsupported asset */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletController_validateSendDestination: { + parameters: { + query: { + /** @description Stellar public key (G...) */ + destinationPublicKey: string; + /** @description Asset code (e.g. USDC, XLM) */ + currency: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Validation result (valid, isActivated, hasTrustlineForAsset, memoRequired) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + valid?: boolean; + isValidPublicKey?: boolean; + isActivated?: boolean; + hasTrustlineForAsset?: boolean; + /** @description True if this destination requires a memo (e.g. exchange shared address) */ + memoRequired?: boolean; + message?: string | null; + }; + }; + }; + }; + }; + WalletController_send: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UserSendDto']; + }; + }; + responses: { + /** @description Send submitted successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Validation or business rule error (e.g. destination not activated, no trustline, memo required, insufficient balance) */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Identity verification required. Complete KYC to send funds. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + WalletPayoutController_sendPayout: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SendPayoutDto']; + }; + }; + responses: { + /** @description Payout submitted successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Validation or business rule error (e.g. destination not activated, no trustline, memo required) */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden – admin only */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_listComments: { + parameters: { + query?: { + /** @description Entity type to filter comments */ + entityType?: + | 'PROJECT' + | 'BOUNTY' + | 'CROWDFUNDING_CAMPAIGN' + | 'GRANT' + | 'GRANT_APPLICATION' + | 'HACKATHON' + | 'HACKATHON_SUBMISSION' + | 'BLOG_POST'; + /** @description Entity ID to filter comments */ + entityId?: string; + /** @description Author ID to filter comments */ + authorId?: string; + /** @description Parent comment ID to filter replies */ + parentId?: string; + /** @description Comment status to filter */ + status?: 'ACTIVE' | 'HIDDEN' | 'DELETED' | 'PENDING_MODERATION'; + /** @description Include reaction data in response */ + includeReactions?: boolean; + /** @description Include report data in response (moderators only) */ + includeReports?: boolean; + /** @description Page number */ + page?: number; + /** @description Number of items per page */ + limit?: number; + /** @description Field to sort by */ + sortBy?: string; + /** @description Sort order */ + sortOrder?: 'asc' | 'desc'; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comments retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_createComment: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateCommentDto']; + }; + }; + responses: { + /** @description Comment created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_getComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comment retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Comment not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_updateComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateCommentDto']; + }; + }; + responses: { + /** @description Comment updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Comment not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_deleteComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comment deleted successfully */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Comment not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_getCommentsByEntity: { + parameters: { + query: { + includeNested: string; + }; + header?: never; + path: { + /** @description Entity type */ + entityType: string; + /** @description Entity ID */ + entityId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comments retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_getReactions: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Reactions retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_addReaction: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AddReactionDto']; + }; + }; + responses: { + /** @description Reaction added successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_removeReaction: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + /** @description Reaction type */ + reactionType: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Reaction removed successfully */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentsController_reportComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ReportCommentDto']; + }; + }; + responses: { + /** @description Comment reported successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_getModerationQueue: { + parameters: { + query?: { + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Moderation queue retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_getReports: { + parameters: { + query?: { + status?: 'PENDING' | 'REVIEWED' | 'RESOLVED' | 'DISMISSED'; + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Reports retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_resolveReport: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Report ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ResolveReportDto']; + }; + }; + responses: { + /** @description Report resolved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Report not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_approveComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comment approved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Comment not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_rejectComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comment rejected successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Comment not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_hideComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comment hidden successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Comment not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_restoreComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comment restored successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Comment not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CommentModerationController_getModerationStats: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Moderation stats retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_getHackathons: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Hackathons retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonsListResponseDto']; + }; + }; + }; + }; + HackathonsController_getFeeEstimate: { + parameters: { + query: { + totalPool: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Fee estimate */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['FeeEstimateResponseDto']; + }; + }; + /** @description totalPool is missing, invalid, or below minimum (5 USDC) */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_getWinners: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Winners retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonWinnersResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_getPublicResults: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Results retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['PublicJudgingResultsResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_getHackathon: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Hackathon retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_getPublicContributors: { + parameters: { + query?: never; + header?: never; + path: { + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Contributors retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_followHackathon: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Follow status updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example true */ + following?: boolean; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_joinHackathon: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully joined hackathon */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ParticipationResponseDto']; + }; + }; + /** @description Registration closed or already participating */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_leaveHackathon: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully left hackathon */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ParticipationResponseDto']; + }; + }; + /** @description Not a participant or submission deadline passed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsController_getHackathonParticipants: { + parameters: { + query: { + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + status: string; + skill: string; + type: string; + search: string; + }; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Participants retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonParticipantsResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsSubmissionsController_getHackathonSubmissions: { + parameters: { + query: { + /** @description Filter by submission status */ + status?: 'SUBMITTED' | 'SHORTLISTED' | 'DISQUALIFIED'; + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + search: string; + type: string; + }; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Submissions retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SubmissionResponseDto'][]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsSubmissionsController_createSubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateSubmissionDto']; + }; + }; + responses: { + /** @description Submission created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SubmissionResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsSubmissionsController_exploreHackathonSubmissions: { + parameters: { + query: { + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + search: string; + type: string; + }; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Submissions retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SubmissionResponseDto'][]; + }; + }; + /** @description Hackathon not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsSubmissionsController_getMySubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Submission retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SubmissionResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsSubmissionsController_getSubmissionById: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Submission ID */ + submissionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Submission retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SubmissionResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsSubmissionsController_deleteSubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Submission ID */ + submissionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Submission withdrawn successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example Submission withdrawn successfully */ + message?: string; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsSubmissionsController_updateSubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Submission ID */ + submissionId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateSubmissionDto']; + }; + }; + responses: { + /** @description Submission updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SubmissionResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsDiscussionsController_getHackathonDiscussions: { + parameters: { + query?: { + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + /** @description Sort by field */ + sortBy?: 'createdAt' | 'updatedAt'; + /** @description Sort order */ + sortOrder?: 'asc' | 'desc'; + }; + header?: never; + path: { + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Discussions retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsDiscussionsController_createHackathonComment: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** + * @description Comment content + * @example This hackathon looks amazing! When does registration open? + */ + content: string; + /** + * @description Parent comment ID for replies + * @example comment_1234567890 + */ + parentId?: string; + }; + }; + }; + responses: { + /** @description Comment posted successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsDiscussionsController_deleteHackathonComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + commentId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Comment deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example Comment deleted successfully */ + message?: string; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsDiscussionsController_updateHackathonComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + commentId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** + * @description Updated comment content + * @example Updated: This hackathon looks amazing! + */ + content: string; + }; + }; + }; + responses: { + /** @description Comment updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsDiscussionsController_reactToComment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Comment ID */ + commentId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** + * @description Type of reaction + * @example LIKE + * @enum {string} + */ + reactionType: 'LIKE' | 'LOVE' | 'CELEBRATE' | 'INSIGHTFUL'; + }; + }; + }; + responses: { + /** @description Reaction updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsDiscussionsController_getCommentReplies: { + parameters: { + query?: { + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + }; + header?: never; + path: { + /** @description Comment ID */ + commentId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Replies retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_getHackathonTeams: { + parameters: { + query?: { + /** @description Search query */ + search?: string; + /** @description Filter by open teams only */ + openOnly?: boolean; + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + }; + header?: never; + path: { + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Teams retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TeamListResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_createTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateTeamDto']; + }; + }; + responses: { + /** @description Team created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TeamResponseDto']; + }; + }; + /** @description Not a participant, already in a team, or hackathon does not allow teams */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_getTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Team found */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TeamResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_disbandTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Team disbanded */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Team has an existing submission and cannot be disbanded */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Only the team leader can disband the team */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_updateTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateTeamDto']; + }; + }; + responses: { + /** @description Team updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not team leader or invalid update */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_joinTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** + * @description Optional message to team leader + * @example I have 5 years of Rust development experience + */ + message?: string; + }; + }; + }; + responses: { + /** @description Successfully joined team */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Team is closed, full, or user already in a team */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_removeTeamMember: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + userId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Member removed from team */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Target user is not a member, or leader tried to remove themselves */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Only the team leader can remove members */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_leaveTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully left team */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not a member or leader cannot leave with members */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_getMyTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Team found or null if not in a team */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TeamResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_inviteToTeam: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['InviteToTeamDto']; + }; + }; + responses: { + /** @description Invitation sent successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TeamInvitationResponseDto']; + }; + }; + /** @description User already in team, team full, or pending invitation exists */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_getMyInvitations: { + parameters: { + query?: { + /** @description Filter by invitation status */ + status?: 'pending' | 'accepted' | 'rejected' | 'expired'; + }; + header?: never; + path: { + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of invitations */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TeamInvitationListResponseDto']; + }; + }; + }; + }; + HackathonsTeamsController_acceptInvitation: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Invitation ID */ + inviteId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully accepted invitation and joined team */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['InvitationActionResponseDto']; + }; + }; + /** @description Invitation expired, already processed, or team full */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_rejectInvitation: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Invitation ID */ + inviteId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully rejected invitation */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['InvitationActionResponseDto']; + }; + }; + /** @description Invitation already processed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_cancelInvitation: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Invitation ID */ + inviteId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully cancelled invitation */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not team leader or invitation already processed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_getTeamInvitations: { + parameters: { + query?: { + /** @description Filter by invitation status */ + status?: 'pending' | 'accepted' | 'rejected' | 'expired'; + }; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of team invitations */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TeamInvitationListResponseDto']; + }; + }; + /** @description Only team leader can view */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_toggleRoleHiredStatus: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ToggleRoleHiredDto']; + }; + }; + responses: { + /** @description Role status toggled successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not team leader or invalid role */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTeamsController_transferLeadership: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + /** @description Team ID */ + teamId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['TransferLeadershipDto']; + }; + }; + responses: { + /** @description Leadership successfully transferred */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['LeadershipTransferResponseDto']; + }; + }; + /** @description Not current leader, new leader not a member, or invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Only current team leader can transfer leadership */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsDraftsController_getDraft: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon draft ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Draft retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonDraftResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsDraftsController_deleteDraft: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon draft ID to delete */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Draft deleted successfully */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Draft not found or user not authorized */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsDraftsController_updateDraft: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon draft ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateHackathonDraftDto']; + }; + }; + responses: { + /** @description Draft updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonDraftResponseDto']; + }; + }; + /** @description Validation failed for one or more sections */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsDraftsController_getOrganizationHackathons: { + parameters: { + query: { + page: number; + limit: number; + /** @description Filter by hackathon status */ + status?: 'upcoming' | 'active' | 'ended'; + }; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Hackathons retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonsListResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsDraftsController_createDraft: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Draft created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonDraftResponseDto']; + }; + }; + /** @description User is not a member of the organization */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsDraftsController_getOrganizationDrafts: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Drafts retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonDraftResponseDto'][]; + }; + }; + }; + }; + OrganizationHackathonsDraftsController_previewAnnouncementAudience: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon (or draft) ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Audience size preview */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsSubmissionsController_updateVisibilitySettings: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateVisibilitySettingsDto']; + }; + }; + responses: { + /** @description Visibility settings updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonDraftResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsSubmissionsController_reviewSubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + hackathonId: string; + /** @description Submission ID */ + submissionId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ReviewSubmissionDto']; + }; + }; + responses: { + /** @description Submission reviewed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example Submission reviewed successfully */ + message?: string; + submission?: Record; + }; + }; + }; + /** @description Invalid status or submission does not belong to hackathon */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsSubmissionsController_getOrganizationHackathonParticipants: { + parameters: { + query: { + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + search: string; + status: string; + type: string; + }; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Participants retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['OrganizationHackathonParticipantsResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsSubmissionsController_scoreSubmissionOverride: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + hackathonId: string; + /** @description Submission ID */ + submissionId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** + * @description Judge ID to credit with these scores (optional, defaults to organizer) + * @example user_1234567890 + */ + judgeId?: string; + /** @description Scores for each criterion */ + criteriaScores: unknown[]; + }; + }; + }; + responses: { + /** @description Submission score override applied successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example Submission scored successfully (organizer override) */ + message?: string; + judgingScore?: Record; + complianceChecks?: { + rubricValid?: boolean; + isOrganizerOverride?: boolean; + }; + }; + }; + }; + /** @description Invalid criteria scores or rubric validation failed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsSubmissionsController_disqualifySubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + hackathonId: string; + /** @description Submission ID */ + submissionId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['DisqualifySubmissionDto']; + }; + }; + responses: { + /** @description Submission disqualified successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example Submission disqualified successfully */ + message?: string; + submission?: Record; + }; + }; + }; + /** @description Submission does not belong to hackathon */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsSubmissionsController_bulkSubmissionAction: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + hackathonId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['BulkSubmissionActionDto']; + }; + }; + responses: { + /** @description Bulk action completed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example Successfully updated 5 submission(s) */ + message?: string; + /** @example 5 */ + count?: number; + /** @example SHORTLISTED */ + action?: string; + }; + }; + }; + /** @description Invalid action or missing required fields */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsSubmissionsController_setSubmissionRank: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + hackathonId: string; + /** @description Submission ID */ + submissionId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @example 1 */ + rank: number; + }; + }; + }; + responses: { + /** @description Submission rank updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example Submission rank updated successfully */ + message?: string; + submission?: Record; + }; + }; + }; + /** @description Invalid rank or submission does not belong to hackathon */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsSubmissionsController_getAnalytics: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + hackathonId: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Analytics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonAnalyticsResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - only organizers can access */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsAnnouncementsController_getAnnouncements: { + parameters: { + query?: { + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + }; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Announcements retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AnnouncementResponseDto'][]; + }; + }; + }; + }; + HackathonsAnnouncementsController_getAnnouncement: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Announcement ID */ + announcementId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Announcement retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AnnouncementResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsAnnouncementsController_createAnnouncement: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateAnnouncementDto']; + }; + }; + responses: { + /** @description Announcement created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AnnouncementResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsAnnouncementsController_deleteAnnouncement: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + /** @description Announcement ID */ + announcementId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Announcement deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsAnnouncementsController_updateAnnouncement: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + /** @description Announcement ID */ + announcementId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateAnnouncementDto']; + }; + }; + responses: { + /** @description Announcement updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AnnouncementResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsAnnouncementsController_publishAnnouncement: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + /** @description Announcement ID */ + announcementId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Announcement published successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AnnouncementResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsJudgingController_getCriteria: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or Slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Criteria retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['CriterionDto'][]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsJudgingController_submitScore: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ScoreSubmissionDto']; + }; + }; + responses: { + /** @description Score submitted successfully with compliance verification */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + judgingScore?: { + id?: string; + totalScore?: number; + criteriaScores?: unknown[]; + }; + complianceChecks?: { + judgeAssigned?: boolean; + noConflictOfInterest?: boolean; + rubricValid?: boolean; + }; + }; + }; + }; + /** @description Judge not assigned, conflict of interest detected, or invalid scores */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsJudgingController_getJudgingSubmissions: { + parameters: { + query?: { + /** @description Page number (1-indexed) */ + page?: number; + /** @description Number of items per page */ + limit?: number; + /** @description Search term for project name, description, participant name or username */ + search?: string; + /** @description Sort field */ + sortBy?: 'date' | 'name' | 'score' | 'rank'; + /** @description Sort order */ + order?: 'asc' | 'desc'; + }; + header?: never; + path: { + /** @description Hackathon ID or Slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['JudgingSubmissionsResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_getJudges: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Judges retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['JudgeResponseDto'][]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_addJudge: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AddJudgeDto']; + }; + }; + responses: { + /** @description Judge added successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['JudgeResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_removeJudge: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + /** @description User ID of the judge */ + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Judge removed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_getResults: { + parameters: { + query?: { + /** @description Page number (1-indexed) */ + page?: number; + /** @description Number of items per page */ + limit?: number; + /** @description Search term for project name, participant name or username */ + search?: string; + /** @description Sort field */ + sortBy?: 'score' | 'name' | 'rank' | 'date'; + /** @description Sort order */ + order?: 'asc' | 'desc'; + /** @description If true, only returns submissions that have been assigned a rank */ + onlyWinners?: boolean; + }; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Results retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['JudgingResultsResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_getIndividualScores: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + /** @description ID of the submission */ + submissionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['IndividualJudgingResultDto'][]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_getWinnerRanking: { + parameters: { + query?: { + /** @description Page number (1-indexed) */ + page?: number; + /** @description Number of items per page */ + limit?: number; + /** @description Search term for project name, participant name or username */ + search?: string; + /** @description Sort field */ + sortBy?: 'score' | 'name' | 'rank' | 'date'; + /** @description Sort order */ + order?: 'asc' | 'desc'; + /** @description If true, only returns submissions that have been assigned a rank */ + onlyWinners?: boolean; + }; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AggregatedJudgingResultDto'][]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_judgingCoverage: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_previewAllocation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_judgingCompleteness: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_publishResults: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Results published successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_listInvitations: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_inviteJudge: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['InviteJudgeDto']; + }; + }; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_cancelInvitation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + /** @description Invitation ID */ + invitationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsJudgingController_resendInvitation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID or slug */ + idOrSlug: string; + /** @description Invitation ID */ + invitationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_myInvitations: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_previewInvitation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Opaque invitation token */ + token: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_acceptInvitation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Opaque invitation token */ + token: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AcceptJudgeInvitationDto']; + }; + }; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_declineInvitation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Opaque invitation token */ + token: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_myHackathons: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Assigned hackathons */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_overview: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + hackathonId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Hackathon overview */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_submissions: { + parameters: { + query?: { + /** @description Page number (1-indexed) */ + page?: number; + /** @description Number of items per page */ + limit?: number; + /** @description Search term for project name, description, participant name or username */ + search?: string; + /** @description Sort field */ + sortBy?: 'date' | 'name' | 'score' | 'rank'; + /** @description Sort order */ + order?: 'asc' | 'desc'; + }; + header?: never; + path: { + /** @description Hackathon ID or slug */ + hackathonId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['JudgingSubmissionsResponseDto']; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_submission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Submission ID */ + submissionId: string; + /** @description Hackathon ID or slug */ + hackathonId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_neighbors: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Submission ID */ + submissionId: string; + /** @description Hackathon ID or slug */ + hackathonId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_criteria: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + hackathonId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_results: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon ID or slug */ + hackathonId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JudgeController_score: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Submission ID */ + submissionId: string; + /** @description Hackathon ID or slug */ + hackathonId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsUpdatesController_getHackathonStatistics: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Statistics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example 45 */ + totalSubmissions?: number; + /** @example 120 */ + activeParticipants?: number; + /** @example 340 */ + totalFollowers?: number; + /** @example 50000 */ + prizePool?: number; + categories?: string[]; + /** @example active */ + status?: string; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsUpdatesController_updatePublishedContent: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdatePublishedHackathonContentDto']; + }; + }; + responses: { + /** @description Published hackathon content updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonResponseDto']; + }; + }; + /** @description Invalid payload or hackathon state */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsUpdatesController_updatePublishedSchedule: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdatePublishedHackathonScheduleDto']; + }; + }; + responses: { + /** @description Published hackathon schedule updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonResponseDto']; + }; + }; + /** @description Invalid payload or schedule changes are no longer allowed */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsUpdatesController_updatePublishedFinancial: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdatePublishedHackathonFinancialDto']; + }; + }; + responses: { + /** @description Published hackathon financial settings updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonResponseDto']; + }; + }; + /** @description Invalid payload or escrow-restricted financial change */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsUpdatesController_previewPublishedFinancial: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdatePublishedHackathonFinancialDto']; + }; + }; + responses: { + /** @description Cost preview computed successfully (no changes made) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example 180 */ + currentPrizePool?: number; + /** @example 250 */ + newPrizePool?: number; + /** @example 8.5 */ + currentPlatformFee?: number; + /** @example 11.8 */ + newPlatformFee?: number; + /** @example 188.5 */ + currentTotalRequired?: number; + /** @example 261.8 */ + newTotalRequired?: number; + /** @example 73.3 */ + additionalFundingRequired?: number; + /** @example 78.8 */ + walletBalance?: number | null; + /** @example true */ + sufficient?: boolean; + /** @example 0 */ + shortfall?: number; + /** @example funded */ + escrowStatus?: string | null; + breakdown?: { + /** @example 1st Place */ + place?: string; + /** @example 50 */ + amount?: number; + /** @example 2.25 */ + fee?: number; + /** @example 52.25 */ + total?: number; + }[]; + }; + }; + }; + /** @description Invalid payload or hackathon state */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsUpdatesController_updatePublishedAdvancedSettings: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + id: string; + /** @description Hackathon ID or slug */ + idOrSlug: unknown; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdatePublishedHackathonAdvancedSettingsDto']; + }; + }; + responses: { + /** @description Published hackathon advanced settings updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonResponseDto']; + }; + }; + /** @description Invalid payload or unsupported hackathon state */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsExportController_exportHackathon: { + parameters: { + query: { + /** @description Output format */ + format: 'csv' | 'pdf'; + /** @description Dataset scope. Defaults to "full" (all sections). */ + dataset?: + | 'overview' + | 'participants' + | 'submissions' + | 'prize_tiers' + | 'winners' + | 'judging' + | 'full'; + }; + header?: never; + path: { + /** @description ID of the organization that owns the hackathon */ + organizationId: string; + /** @description ID or slug of the hackathon */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Binary file stream (CSV or PDF) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'text/csv': string; + 'application/pdf': string; + }; + }; + /** @description Unsupported format or dataset */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not an organizer of this hackathon */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Hackathon not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsPartnersController_invite: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID */ + hackathonId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['InvitePartnerDto']; + }; + }; + responses: { + /** @description Invitation created and email sent */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsPartnersController_list: { + parameters: { + query?: { + status?: 'PENDING' | 'CONFIRMED' | 'FAILED' | 'REFUNDED' | 'CANCELLED'; + page?: number; + limit?: number; + }; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID */ + hackathonId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Contributions retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsPartnersController_cancel: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + organizationId: string; + /** @description Hackathon ID */ + hackathonId: string; + /** @description Contribution ID */ + contributionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invitation cancelled */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsPartnersController_getAllocations: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + hackathonId: string; + contributionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Allocation summary */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsPartnersController_allocate: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + hackathonId: string; + contributionId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AllocateContributionDto']; + }; + }; + responses: { + /** @description Contribution allocated */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsPartnersController_undoAllocation: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + hackathonId: string; + allocationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Allocation undone */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PartnersContributeController_getByToken: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hex-encoded invite token */ + token: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Invitation details */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PartnersContributeController_prepareFundTx: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hex-encoded invite token */ + token: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PrepareFundTransactionDto']; + }; + }; + responses: { + /** @description Unsigned transaction prepared */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PartnersContributeController_submitTx: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hex-encoded invite token */ + token: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SubmitSignedTransactionDto']; + }; + }; + responses: { + /** @description Contribution confirmed */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonsTracksController_listTracks: { + parameters: { + query?: { + /** @description Set true to include archived tracks. */ + includeArchived?: boolean; + }; + header?: never; + path: { + /** @description Hackathon ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TrackResponseDto'][]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsTracksController_list: { + parameters: { + query?: { + includeArchived?: boolean; + }; + header?: never; + path: { + /** @description Hackathon ID or slug */ + id: string; + organizationId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TrackResponseDto'][]; + }; + }; + }; + }; + OrganizationHackathonsTracksController_create: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateTrackDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TrackResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsTracksController_remove: { + parameters: { + query?: never; + header?: never; + path: { + trackId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deleted or archived */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsTracksController_update: { + parameters: { + query?: never; + header?: never; + path: { + trackId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateTrackDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TrackResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsTracksController_bulkOptIn: { + parameters: { + query?: never; + header?: never; + path: { + trackId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bulk opt-in complete; returns counts. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + trackName?: string; + added?: number; + alreadyOptedIn?: number; + skippedDisqualified?: number; + totalSubmissions?: number; + newCap?: number | null; + }; + }; + }; + }; + }; + OrganizationHackathonsEscrowController_requestFundingOtp: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon id */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['RequestFundingOtpResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsEscrowController_verifyFundingOtp: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['VerifyFundingOtpDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['VerifyFundingOtpResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsEscrowController_publish: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon draft id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PublishHackathonEscrowDto']; + }; + }; + responses: { + /** @description Escrow op created; unsigned XDR ready for wallet signing. Hackathon transitioned to DRAFT_AWAITING_FUNDING. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + /** @description Validation error or hackathon not in DRAFT status */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationHackathonsEscrowController_cancel: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CancelHackathonEscrowDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsEscrowController_selectWinners: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SelectHackathonWinnersDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsEscrowController_submitSigned: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon id */ + id: string; + /** @description EscrowOp cuid returned by the publish call */ + opRowId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['HackathonSubmitSignedXdrDto']; + }; + }; + responses: { + /** @description Signed XDR submitted; op is now PENDING_CONFIRM. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsEscrowController_getOp: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon id */ + id: string; + /** @description EscrowOp cuid */ + opRowId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationHackathonsEscrowController_resetToDraft: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Hackathon id */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Hackathon reset to DRAFT. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HackathonParticipantEscrowController_submit: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon id */ + id: string; + /** @description HackathonSubmission cuid */ + submissionId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SubmitHackathonDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + HackathonParticipantEscrowController_withdrawSubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon id */ + id: string; + /** @description HackathonSubmission cuid */ + submissionId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['WithdrawHackathonSubmissionDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + HackathonParticipantEscrowController_contribute: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ContributeHackathonDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + HackathonParticipantEscrowController_submitSigned: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon id */ + id: string; + /** @description EscrowOp cuid */ + opRowId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['HackathonSubmitSignedXdrDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + HackathonParticipantEscrowController_getOp: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Hackathon id */ + id: string; + /** @description EscrowOp cuid */ + opRowId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['HackathonEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationsController_getOrganizations: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_createOrganization: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateOrganizationDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_getMyOrganizations: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_getOrganizationProfile: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID or slug */ + idOrSlug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Organization profile retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['OrganizationProfileDto']; + }; + }; + /** @description Organization not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_searchOrganizations: { + parameters: { + query?: { + /** @description Search term (name, slug, tagline) */ + q?: string; + isProfileComplete?: 'true' | 'false'; + hasHackathons?: 'true' | 'false'; + hasGrants?: 'true' | 'false'; + /** @description Max results (default 10) */ + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated organizations */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_getOrganization: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Organization retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example org_1234567890 */ + id?: string; + /** @example Tech Innovators */ + name?: string; + /** @example https://example.com/logo.png */ + logo?: string; + /** @example Building the future of technology */ + tagline?: string; + /** @example We are a community of developers... */ + about?: string; + links?: { + /** @example https://techinnovators.com */ + website?: string; + /** @example https://twitter.com/techinnovators */ + x?: string; + /** @example https://github.com/techinnovators */ + github?: string; + /** @example https://linkedin.com/company/techinnovators */ + others?: string; + }; + /** + * @example [ + * "user_123", + * "user_456" + * ] + */ + members?: string[]; + /** + * @example [ + * "user_123" + * ] + */ + admins?: string[]; + /** @example user_123 */ + owner?: string; + /** @example [] */ + hackathons?: string[]; + /** @example [] */ + grants?: string[]; + /** @example true */ + isProfileComplete?: boolean; + /** + * @example [ + * "invite_123" + * ] + */ + pendingInvites?: string[]; + /** @example better_auth_org_123 */ + betterAuthOrgId?: string; + /** @example false */ + isArchived?: boolean; + /** @example null */ + archivedBy?: string; + /** @example null */ + archivedAt?: string; + /** @example 2024-01-15T10:30:00.000Z */ + createdAt?: string; + /** @example 2024-01-15T10:30:00.000Z */ + updatedAt?: string; + analytics?: { + trends?: { + members?: { + /** @example 25 */ + current?: number; + /** @example 22 */ + previous?: number; + /** @example 3 */ + change?: number; + /** @example 13.64 */ + changePercentage?: number; + /** @example true */ + isPositive?: boolean; + }; + hackathons?: { + /** @example 5 */ + current?: number; + /** @example 4 */ + previous?: number; + /** @example 1 */ + change?: number; + /** @example 25 */ + changePercentage?: number; + /** @example true */ + isPositive?: boolean; + }; + grants?: { + /** @example 0 */ + current?: number; + /** @example 0 */ + previous?: number; + /** @example 0 */ + change?: number; + /** @example 0 */ + changePercentage?: number; + /** @example true */ + isPositive?: boolean; + }; + }; + timeSeries?: { + hackathons?: { + /** @example January */ + month?: string; + /** @example 2024 */ + year?: number; + /** @example 2 */ + count?: number; + /** @example 2024-01-01T00:00:00.000Z */ + timestamp?: string; + }[]; + }; + }; + }; + }; + }; + /** @description Organization not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_updateOrganization: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateOrganizationDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_deleteOrganization: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_getOrganizationMembers: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationsController_getOrganizationStats: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MembersController_getMembers: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MembersController_addMember: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MembersController_removeMember: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MembersController_updateMemberRole: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + userId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateMemberRoleDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + MembersController_getMyMembership: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitationsController_getInvitations: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitationsController_inviteMember: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['InviteMemberDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitationsController_acceptInvitation: { + parameters: { + query?: never; + header?: never; + path: { + invitationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitationsController_rejectInvitation: { + parameters: { + query?: never; + header?: never; + path: { + invitationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitationsController_cancelInvitation: { + parameters: { + query?: never; + header?: never; + path: { + invitationId: string; + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitationsController_getMyInvitations: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationTreasuryController_listWallets: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryWalletResponseDto'][]; + }; + }; + }; + }; + OrganizationTreasuryController_getDefaultWallet: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryWalletResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_createManagedWallet: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateManagedWalletDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryWalletResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_registerConnectedWallet: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RegisterConnectedWalletDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryWalletResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_refreshSigners: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + walletId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryWalletResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_updateWallet: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + walletId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateTreasuryWalletDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryWalletResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_archiveWallet: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + walletId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryWalletResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_walletBalance: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + walletId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['WalletBalanceResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_getPolicy: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryPolicyResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_updatePolicy: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateTreasuryPolicyDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryPolicyResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_listSpend: { + parameters: { + query?: { + status?: string; + }; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto'][]; + }; + }; + }; + }; + OrganizationTreasuryController_initiateSpend: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['InitiateSpendDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_getSpend: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + requestId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_approveSpend: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + requestId: string; + }; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': components['schemas']['SpendDecisionDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_rejectSpend: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + requestId: string; + }; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': components['schemas']['SpendDecisionDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_cancelSpend: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + requestId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_executeSpend: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + requestId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_buildSpendXdr: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + requestId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BuildSpendXdrResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_submitSpendSignedXdr: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + requestId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SubmitSpendSignedXdrDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['SpendRequestResponseDto']; + }; + }; + }; + }; + OrganizationTreasuryController_auditLog: { + parameters: { + query?: { + page?: string; + limit?: string; + }; + header?: never; + path: { + organizationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['TreasuryAuditLogResponseDto']; + }; + }; + }; + }; + VotesController_getVotes: { + parameters: { + query: { + /** @description Project ID */ + projectId?: string; + /** @description Entity Type */ + entityType?: string; + /** @description Vote Type */ + voteType: string; + /** @description User ID */ + userId: string; + /** @description Limit */ + limit: number; + /** @description Offset */ + offset: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VotesController_createVote: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateVoteDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VotesController_removeVote: { + parameters: { + query?: never; + header?: never; + path: { + projectId: string; + entityType: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VotesController_getVoteCounts: { + parameters: { + query?: never; + header?: never; + path: { + projectId: string; + entityType: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VotesController_getUserVote: { + parameters: { + query?: never; + header?: never; + path: { + projectId: string; + entityType: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VotesController_getProjectVotes: { + parameters: { + query?: { + entityType?: + | 'PROJECT' + | 'CROWDFUNDING_CAMPAIGN' + | 'HACKATHON_SUBMISSION' + | 'GRANT'; + voteType?: 'UPVOTE' | 'DOWNVOTE'; + limit?: number; + offset?: number; + /** @description Include voter list and vote counts in response */ + includeVoters?: boolean; + }; + header?: never; + path: { + projectId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + LeaderboardController_getLeaderboard: { + parameters: { + query?: { + /** @description Filter by reputation tier */ + tier?: 'NEWCOMER' | 'CONTRIBUTOR' | 'ESTABLISHED' | 'EXPERT' | 'LEGEND'; + /** @description Time window for score aggregation */ + timeframe?: 'ALL_TIME' | 'THIS_MONTH' | 'THIS_WEEK' | 'THIS_DAY'; + /** @description Items per page, max 50 (default: 20) */ + limit?: number; + /** @description Page number (default: 1) */ + page?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Leaderboard retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BlogPostsController_listBlogPosts: { + parameters: { + query?: { + /** @description Author ID to filter posts */ + authorId?: string; + /** @description Post status to filter */ + status?: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED' | 'SCHEDULED'; + /** @description Search query for post title/content */ + search?: string; + /** @description Filter by tags (comma-separated) */ + tags?: string; + /** @description Filter by categories (comma-separated) */ + categories?: string; + /** @description Include only featured posts */ + isFeatured?: boolean; + /** @description Include pinned posts first */ + includePinned?: boolean; + /** @description Page number */ + page?: number; + /** @description Number of items per page */ + limit?: number; + /** @description Sort field */ + sortBy?: + | 'createdAt' + | 'updatedAt' + | 'publishedAt' + | 'viewCount' + | 'title'; + /** @description Sort order */ + sortOrder?: 'asc' | 'desc'; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog posts retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BlogPostsController_createBlogPost: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateBlogPostDto']; + }; + }; + responses: { + /** @description Blog post created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BlogPostsController_getBlogPostById: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog post retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Post is not published */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BlogPostsController_getBlogPostBySlug: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog post retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Post is not published */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BlogPostsController_getRelatedPosts: { + parameters: { + query: { + limit: string; + }; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Related posts retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BlogPostsController_updateBlogPost: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateBlogPostDto']; + }; + }; + responses: { + /** @description Blog post updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BlogPostsController_deleteBlogPost: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog post deleted successfully */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AiController_generateExcerpt: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + content: string; + }; + }; + }; + responses: { + /** @description Excerpt generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AiController_generateReadingTime: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + content: string; + }; + }; + }; + responses: { + /** @description Reading time generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AiController_generateSEO: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + content: string; + }; + }; + }; + responses: { + /** @description SEO settings generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AiController_generateTags: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + content: string; + }; + }; + }; + responses: { + /** @description Tags generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AiController_generateCategory: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + content: string; + }; + }; + }; + responses: { + /** @description Category generated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getOverview: { + parameters: { + query?: { + /** @description Time range for the overview data */ + timeRange?: '7d' | '30d' | '90d'; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Overview data retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AdminOverviewResponseDto']; + }; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getUsers: { + parameters: { + query?: { + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + /** @description Search by name, email, or username */ + search?: string; + /** @description Filter by user role */ + role?: string; + /** @description Filter by active status (not banned) */ + isActive?: boolean; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Users retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_exportUsers: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description CSV file download */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getUserDetails: { + parameters: { + query?: never; + header?: never; + path: { + /** @description User username or ID */ + usernameOrId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getUserStats: { + parameters: { + query?: never; + header?: never; + path: { + /** @description User username or ID */ + usernameOrId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User statistics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getUserActivity: { + parameters: { + query?: { + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + }; + header?: never; + path: { + /** @description User username or ID */ + usernameOrId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User activity retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getUserProjects: { + parameters: { + query?: { + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + /** @description Filter by project status */ + status?: string; + /** @description Filter by project category */ + category?: string; + }; + header?: never; + path: { + /** @description User username or ID */ + usernameOrId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User projects retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getOrganizations: { + parameters: { + query?: { + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + /** @description Search by organization name or slug */ + search?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Organizations retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getOrganizationDetails: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Organization ID */ + orgId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Organization details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Organization not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminController_getUserOrganizations: { + parameters: { + query?: never; + header?: never; + path: { + /** @description User username or ID */ + usernameOrId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User organizations retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Authentication required */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_listAllBlogPosts: { + parameters: { + query?: { + /** @description Author ID to filter posts */ + authorId?: string; + /** @description Post status to filter */ + status?: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED' | 'SCHEDULED'; + /** @description Search query for post title/content */ + search?: string; + /** @description Filter by tags (comma-separated) */ + tags?: string; + /** @description Filter by categories (comma-separated) */ + categories?: string; + /** @description Include only featured posts */ + isFeatured?: boolean; + /** @description Include pinned posts first */ + includePinned?: boolean; + /** @description Page number */ + page?: number; + /** @description Number of items per page */ + limit?: number; + /** @description Sort field */ + sortBy?: + | 'createdAt' + | 'updatedAt' + | 'publishedAt' + | 'viewCount' + | 'title'; + /** @description Sort order */ + sortOrder?: 'asc' | 'desc'; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog posts retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_createBlogPost: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateBlogPostDto']; + }; + }; + responses: { + /** @description Blog post created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_getBlogPostById: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog post retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_updateBlogPost: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdateBlogPostDto']; + }; + }; + responses: { + /** @description Blog post updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden - Admin access required */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_deleteBlogPost: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog post deleted successfully */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_permanentlyDeleteBlogPost: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog post permanently deleted successfully */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_restoreBlogPost: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Blog post ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blog post restored successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blog post not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_getAllTags: { + parameters: { + query: { + limit: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Tags retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_getTagBySlug: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Tag slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Tag retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Tag not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_deleteUnusedTags: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Unused tags deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminBlogsController_publishScheduledPosts: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Scheduled posts published successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_list: { + parameters: { + query?: { + limit?: unknown; + page?: unknown; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of campaigns */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_listByUser: { + parameters: { + query?: { + limit?: unknown; + page?: unknown; + }; + header?: never; + path: { + /** @description Username or User ID */ + usernameOrId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of campaigns by user */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description User not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_getCampaign: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID */ + campaignId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign details */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_listPending: { + parameters: { + query?: { + limit?: unknown; + page?: unknown; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of pending campaigns */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_approve: { + parameters: { + query?: never; + header?: never; + path: { + campaignId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign approved */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_reject: { + parameters: { + query?: never; + header?: never; + path: { + campaignId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminCrowdfundingRejectDto']; + }; + }; + responses: { + /** @description Campaign rejected */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_requestRevision: { + parameters: { + query?: never; + header?: never; + path: { + campaignId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminCrowdfundingRequestRevisionDto']; + }; + }; + responses: { + /** @description Revision request created */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_addReviewNote: { + parameters: { + query?: never; + header?: never; + path: { + campaignId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminCrowdfundingNoteDto']; + }; + }; + responses: { + /** @description Review note added */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminCrowdfundingController_assignReviewer: { + parameters: { + query?: never; + header?: never; + path: { + campaignId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AdminCrowdfundingAssignDto']; + }; + }; + responses: { + /** @description Reviewer assigned */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminMilestonesController_listAllMilestonesByCampaign: { + parameters: { + query?: { + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + /** @description Filter by review status */ + status?: + | 'PENDING' + | 'SUBMITTED' + | 'UNDER_REVIEW' + | 'APPROVED' + | 'REJECTED' + | 'RESUBMISSION_REQUIRED'; + /** @description Sort by field */ + sortBy?: + | 'submittedAt' + | 'campaignSize' + | 'creatorReputation' + | 'createdAt'; + /** @description Filter by campaign ID */ + campaignId?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of campaigns with their milestones */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminMilestonesController_listPendingMilestones: { + parameters: { + query?: { + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + /** @description Filter by review status */ + status?: + | 'PENDING' + | 'SUBMITTED' + | 'UNDER_REVIEW' + | 'APPROVED' + | 'REJECTED' + | 'RESUBMISSION_REQUIRED'; + /** @description Sort by field */ + sortBy?: + | 'submittedAt' + | 'campaignSize' + | 'creatorReputation' + | 'createdAt'; + /** @description Filter by campaign ID */ + campaignId?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of pending milestones */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminMilestonesController_getMilestoneForReview: { + parameters: { + query?: never; + header?: never; + path: { + milestoneId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Milestone details */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Milestone not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminMilestonesController_approveMilestone: { + parameters: { + query?: never; + header?: never; + path: { + milestoneId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ApproveMilestoneDto']; + }; + }; + responses: { + /** @description Milestone approved */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Milestone not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminMilestonesController_rejectMilestone: { + parameters: { + query?: never; + header?: never; + path: { + milestoneId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RejectMilestoneDto']; + }; + }; + responses: { + /** @description Milestone rejected */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Milestone not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminMilestonesController_requestResubmission: { + parameters: { + query?: never; + header?: never; + path: { + milestoneId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RequestMilestoneResubmissionDto']; + }; + }; + responses: { + /** @description Resubmission requested */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Milestone not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminMilestonesController_addReviewNote: { + parameters: { + query?: never; + header?: never; + path: { + milestoneId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AddMilestoneReviewNoteDto']; + }; + }; + responses: { + /** @description Review note added */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Milestone not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminEscrowController_getEscrowInfo: { + parameters: { + query?: never; + header?: never; + path: { + campaignId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Escrow information */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminEscrowController_executeEscrowAction: { + parameters: { + query?: never; + header?: never; + path: { + campaignId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ManualEscrowActionDto']; + }; + }; + responses: { + /** @description Escrow action executed */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminDisputesController_listDisputes: { + parameters: { + query?: { + /** @description Page number */ + page?: number; + /** @description Items per page */ + limit?: number; + /** @description Filter by dispute status */ + status?: + | 'OPEN' + | 'UNDER_REVIEW' + | 'AWAITING_RESPONSE' + | 'RESOLVED' + | 'ESCALATED' + | 'CLOSED'; + /** @description Filter by campaign ID */ + campaignId?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of disputes */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminDisputesController_getDisputeDetail: { + parameters: { + query?: never; + header?: never; + path: { + disputeId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Dispute details */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Dispute not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminDisputesController_assignDispute: { + parameters: { + query?: never; + header?: never; + path: { + disputeId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AssignDisputeDto']; + }; + }; + responses: { + /** @description Dispute assigned */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Dispute not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminDisputesController_addDisputeNote: { + parameters: { + query?: never; + header?: never; + path: { + disputeId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['AddDisputeNoteDto']; + }; + }; + responses: { + /** @description Note added */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Dispute not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminDisputesController_resolveDispute: { + parameters: { + query?: never; + header?: never; + path: { + disputeId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ResolveDisputeDto']; + }; + }; + responses: { + /** @description Dispute resolved */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Dispute not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminDisputesController_escalateDispute: { + parameters: { + query?: never; + header?: never; + path: { + disputeId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['EscalateDisputeDto']; + }; + }; + responses: { + /** @description Dispute escalated */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Dispute not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminManualProjectsController_listPendingManualProjects: { + parameters: { + query?: { + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminManualProjectsController_approveManualProject: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + projectId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminManualProjectsController_rejectManualProject: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + projectId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RejectManualProjectDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminManualProjectsController_requestChanges: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + projectId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RequestManualProjectChangesDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminProjectEditsController_listPendingProjectEdits: { + parameters: { + query?: { + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminProjectEditsController_approveProjectEdit: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ProjectEdit ID */ + editId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminProjectEditsController_rejectProjectEdit: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ProjectEdit ID */ + editId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['RejectProjectEditDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminWalletsController_getStats: { + parameters: { + query?: { + timeRange?: '7d' | '30d' | '90d'; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + default: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AdminWalletStatsDto']; + }; + }; + }; + }; + AdminWalletsController_listWallets: { + parameters: { + query?: { + search?: string; + limit?: number; + page?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + default: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AdminWalletListResponseDto']; + }; + }; + }; + }; + AdminWalletsController_getByUserId: { + parameters: { + query?: never; + header?: never; + path: { + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + default: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AdminWalletListItemDto'][]; + }; + }; + }; + }; + AdminWalletsController_getDetails: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + default: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['AdminWalletDetailsDto']; + }; + }; + }; + }; + AdminWalletsController_activateWallet: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Wallet activated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminWalletsController_sponsorActivateUser: { + parameters: { + query?: never; + header?: never; + path: { + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns activation result for the user (activated, alreadyActivated, addedTrustlines, hash). */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminWalletsController_sponsorActivateHackathon: { + parameters: { + query?: never; + header?: never; + path: { + hackathonId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Job enqueued. Returns { jobId, hackathonId, estimatedParticipants, statusUrl }. */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminWalletsController_getSponsorActivationJobStatus: { + parameters: { + query?: never; + header?: never; + path: { + jobId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HealthController_liveness: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HealthController_readiness: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The Health Check is successful */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example ok */ + status?: string; + /** + * @example { + * "database": { + * "status": "up" + * } + * } + */ + info?: { + [key: string]: { + status: string; + } & { + [key: string]: unknown; + }; + } | null; + /** @example {} */ + error?: { + [key: string]: { + status: string; + } & { + [key: string]: unknown; + }; + } | null; + /** + * @example { + * "database": { + * "status": "up" + * } + * } + */ + details?: { + [key: string]: { + status: string; + } & { + [key: string]: unknown; + }; + }; + }; + }; + }; + /** @description The Health Check is not successful */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @example error */ + status?: string; + /** + * @example { + * "database": { + * "status": "up" + * } + * } + */ + info?: { + [key: string]: { + status: string; + } & { + [key: string]: unknown; + }; + } | null; + /** + * @example { + * "redis": { + * "status": "down", + * "message": "Could not connect" + * } + * } + */ + error?: { + [key: string]: { + status: string; + } & { + [key: string]: unknown; + }; + } | null; + /** + * @example { + * "database": { + * "status": "up" + * }, + * "redis": { + * "status": "down", + * "message": "Could not connect" + * } + * } + */ + details?: { + [key: string]: { + status: string; + } & { + [key: string]: unknown; + }; + }; + }; + }; + }; + }; + }; + DiditController_getStatus: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['VerificationStatusDto']; + }; + }; + }; + }; + DiditController_callback: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DiditController_createSession: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateDiditSessionDto']; + }; + }; + responses: { + /** @description Session created */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + /** @description Missing DIDIT_API_KEY or DIDIT_WORKFLOW_ID */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DiditController_webhook: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Webhook accepted */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid signature */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PricingController_preview: { + parameters: { + query: { + pillar: 'Hackathon' | 'Bounty' | 'Grant' | 'Crowdfunding'; + organizationId: string; + /** @description Budget in stroops (7-decimal). String to preserve precision. */ + budgetStroops: string; + /** @description Override fee bps from a sales authority. 0 = waiver. */ + salesOverrideBps?: number; + /** @description Free-text reason for the audit log. */ + salesOverrideReason?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['PricingPreviewResponseDto']; + }; + }; + }; + }; + AdminOpsController_pause: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminOpsController_unpause: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminOpsController_setFeeBps: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PricesController_getAll: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Map of asset symbol → USD price as a decimal string (6 dp). */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + }; + }; + PricesController_getDebug: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Per-asset debug info. `source` is which provider won the resolution chain. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + }; + }; + PricesController_getOne: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Asset ticker (case-insensitive). */ + symbol: 'XLM' | 'USDC' | 'EURC' | 'USDGLO'; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description USD price as a decimal string (6 dp). */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + }; + }; + ProjectsController_createDraft: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Full payload for the stepped draft creation */ + requestBody: { + content: { + 'application/json': Record; + }; + }; + responses: { + /** @description Draft created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_saveDraft: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: string; + }; + cookie?: never; + }; + /** @description Full payload for stepped draft autosave */ + requestBody: { + content: { + 'application/json': Record; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_listPublicProjects: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_searchPublicProjects: { + parameters: { + query?: { + search?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_listFeaturedProjects: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_listProjectEdits: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_submitProjectEdit: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['Function']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_publishProject: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: string; + }; + cookie?: never; + }; + /** @description Publish/submit action (Review & Submit) */ + requestBody: { + content: { + 'application/json': { + /** @example true */ + isCampaign?: boolean; + }; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_getMyProjects: { + parameters: { + query: { + limit?: number; + offset?: number; + status: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_getPublicProjectBySlug: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ProjectsController_getProject: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationBountiesEscrowController_publish: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Bounty draft id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PublishBountyEscrowDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + /** @description Validation failed or bounty not in draft status */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationBountiesEscrowController_cancel: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Bounty id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CancelBountyEscrowDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationBountiesEscrowController_selectWinners: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Bounty id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SelectBountyWinnersDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationBountiesEscrowController_submitSigned: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Bounty id */ + id: string; + /** @description EscrowOp cuid */ + opRowId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['BountySubmitSignedXdrDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationBountiesEscrowController_getOp: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Bounty id */ + id: string; + /** @description EscrowOp cuid */ + opRowId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyParticipantEscrowController_apply: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Bounty id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ApplyBountyDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyParticipantEscrowController_withdrawApplication: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Bounty id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['WithdrawApplicationDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyParticipantEscrowController_submit: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Bounty id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SubmitBountyDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyParticipantEscrowController_withdrawSubmission: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Bounty id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['WithdrawSubmissionDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyParticipantEscrowController_contribute: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Bounty id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ContributeBountyDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyParticipantEscrowController_submitSigned: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Bounty id */ + id: string; + /** @description EscrowOp cuid */ + opRowId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['BountySubmitSignedXdrDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyParticipantEscrowController_getOp: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Bounty id */ + id: string; + /** @description EscrowOp cuid */ + opRowId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyEscrowOpResponseDto']; + }; + }; + }; + }; + BountyApplicationController_create: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateBountyApplicationDto']; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BountyApplicationController_getMine: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BountyApplicationController_withdraw: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + appId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BountyApplicationController_edit: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + appId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['EditBountyApplicationDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationBountyShortlistController_list: { + parameters: { + query?: { + /** @description Filter by application status */ + status?: + | 'SUBMITTED' + | 'SHORTLISTED' + | 'SELECTED' + | 'DECLINED' + | 'WITHDRAWN'; + }; + header?: never; + path: { + bountyId: string; + organizationId: unknown; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationBountyShortlistController_selectForPick: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SelectForPickDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationBountyShortlistController_createShortlist: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateShortlistDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationBountyShortlistController_decline: { + parameters: { + query?: never; + header?: never; + path: { + appId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['DeclineApplicationDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BountyShowdownJoinController_join: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['JoinShowdownDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BountyShowdownJoinController_leave: { + parameters: { + query?: never; + header?: never; + path: { + bountyId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['JoinShowdownDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + BountyPublicController_list: { + parameters: { + query?: { + page?: number; + limit?: number; + search?: unknown; + status?: unknown; + organizationId?: unknown; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyPublicListDto']; + }; + }; + }; + }; + BountyPublicController_findOne: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['BountyPublicDto']; + }; + }; + }; + }; + OrganizationGrantsEscrowController_publish: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + /** @description Grant id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['PublishGrantEscrowDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantEscrowOpResponseDto']; + }; + }; + /** @description Draft not in DRAFT status */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OrganizationGrantsEscrowController_cancel: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CancelGrantEscrowDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationGrantsEscrowController_selectWinners: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SelectGrantWinnersDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationGrantsEscrowController_claimMilestone: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ClaimGrantMilestoneDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationGrantsEscrowController_submitSigned: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + id: string; + opRowId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['GrantSubmitSignedXdrDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantEscrowOpResponseDto']; + }; + }; + }; + }; + OrganizationGrantsEscrowController_getOp: { + parameters: { + query?: never; + header?: never; + path: { + organizationId: string; + id: string; + opRowId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantEscrowOpResponseDto']; + }; + }; + }; + }; + GrantContributeEscrowController_contribute: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Grant id */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['ContributeGrantDto']; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantEscrowOpResponseDto']; + }; + }; + }; + }; + GrantsPublicController_list: { + parameters: { + query?: { + /** @description Pillar-specific status filter (open, closed, in_progress). */ + status?: string; + /** @description Case-insensitive substring match against project title and summary. */ + search?: string; + /** @description Filter by the underlying project category. */ + category?: string; + /** @description Page number (1-indexed). */ + page?: number; + /** @description Items per page. */ + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Grants page */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['GrantPublicListResponseDto']; + }; + }; + }; + }; + OpportunitiesController_list: { + parameters: { + query?: { + /** @description Which pillar to query. "all" fans out across the four adapters; the others restrict to a single adapter. */ + type?: 'all' | 'bounty' | 'hackathon' | 'grant' | 'crowdfunding'; + /** @description Pillar-specific status filter. Adapters match case-insensitively against their own enum and return [] when no value matches. */ + status?: string; + /** @description Case-insensitive substring match against title and summary across adapters. */ + search?: string; + /** @description Comma-separated tag list. Pillar-aware: bounty has no tag field and returns [] for any tags filter. */ + tags?: string; + /** @description Sort mode. "deadline" sorts ascending by the next deadline (NULLS LAST); "prize_desc" sorts by reward descending. */ + sort?: 'newest' | 'deadline' | 'prize_desc'; + /** @description Opaque pagination cursor returned by the previous response. Omit to start from page 1. */ + cursor?: string; + /** @description Items per page. Capped at 50. */ + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Opportunities page */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['OpportunityListResponseDto']; + }; + }; + }; + }; + NewsletterController_subscribe: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['SubscribeDto']; + }; + }; + responses: { + /** @description Confirmation email sent successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + /** @description Invalid tags provided */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Email is already subscribed */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Too many requests — rate limited */ + 429: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_confirmSubscription: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Confirmation token received via email */ + token: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Redirects to frontend confirmation page */ + 302: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Confirmation token has expired */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid or expired confirmation token */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_unsubscribeByToken: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unsubscribe token from the email footer */ + token: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Redirects to frontend unsubscribe confirmation page */ + 302: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid unsubscribe link */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_unsubscribe: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UnsubscribeDto']; + }; + }; + responses: { + /** @description Successfully unsubscribed */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Subscriber not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_updatePreferences: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['UpdatePreferencesDto']; + }; + }; + responses: { + /** @description Preferences updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid tags provided */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Subscriber not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_trackOpen: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID */ + campaignId: string; + /** @description Subscriber ID */ + subscriberId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returns 1x1 transparent GIF */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_trackClick: { + parameters: { + query: { + /** @description Target URL to redirect to after tracking */ + url: string; + }; + header?: never; + path: { + /** @description Campaign ID */ + campaignId: string; + /** @description Subscriber ID */ + subscriberId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Redirects to the target URL */ + 302: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_getSubscribers: { + parameters: { + query?: { + /** @description Filter by status */ + status?: 'active' | 'pending' | 'unsubscribed' | 'bounced'; + /** @description Filter by source */ + source?: string; + /** @description Filter by tags (comma-separated) */ + tags?: string; + /** @description Search by email or name */ + search?: string; + /** @description Page number (default: 1) */ + page?: number; + /** @description Items per page (default: 50) */ + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Subscribers retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_getStats: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Statistics retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_exportSubscribers: { + parameters: { + query?: { + /** @description Filter by subscriber status */ + status?: 'active' | 'pending' | 'unsubscribed' | 'bounced'; + /** @description Filter by tags (comma-separated) */ + tags?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description CSV file downloaded */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'text/csv': unknown; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_deleteSubscriber: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Subscriber ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Subscriber deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Subscriber not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_getCampaigns: { + parameters: { + query?: { + /** @description Page number (default: 1) */ + page?: number; + /** @description Items per page (default: 20) */ + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaigns retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_createCampaign: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': components['schemas']['CreateNewsletterCampaignDto']; + }; + }; + responses: { + /** @description Campaign created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid tags provided */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_getCampaign: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + NewsletterController_sendCampaign: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Campaign ID to send */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign sent successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': unknown; + }; + }; + /** @description Campaign already sent or currently sending */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DlqAdminController_getDepth: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Total parked jobs */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DlqAdminController_list: { + parameters: { + query?: { + /** @description Max entries to return (1 to 200, default 50) */ + limit?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DlqAdminController_getOne: { + parameters: { + query?: never; + header?: never; + path: { + jobId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DlqAdminController_replay: { + parameters: { + query?: never; + header?: never; + path: { + jobId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + socialSignIn: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Callback URL to redirect to after the user has signed in */ + callbackURL?: string | null; + newUserCallbackURL?: string | null; + /** @description Callback URL to redirect to if an error happens */ + errorCallbackURL?: string | null; + provider: string; + /** @description Disable automatic redirection to the provider. Useful for handling the redirection yourself */ + disableRedirect?: boolean | null; + idToken?: { + /** @description ID token from the provider */ + token: string; + /** @description Nonce used to generate the token */ + nonce?: string | null; + /** @description Access token from the provider */ + accessToken?: string | null; + /** @description Refresh token from the provider */ + refreshToken?: string | null; + /** @description Expiry date of the token */ + expiresAt?: number | null; + } | null; + /** @description Array of scopes to request from the provider. This will override the default scopes passed. */ + scopes?: unknown[] | null; + /** @description Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider */ + requestSignUp?: boolean | null; + /** @description The login hint to use for the authorization code request */ + loginHint?: string | null; + additionalData?: string | null; + }; + }; + }; + responses: { + /** @description Success - Returns either session details or redirect URL */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + token: string; + user: components['schemas']['User']; + url?: string; + /** @enum {boolean} */ + redirect: false; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + getSession: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + session: components['schemas']['Session']; + user: components['schemas']['User']; + } | null; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + signOut: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': Record; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + signUpWithEmailAndPassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': { + /** @description The name of the user */ + name: string; + /** @description The email of the user */ + email: string; + /** @description The password of the user */ + password: string; + /** @description The profile image URL of the user */ + image?: string; + /** @description The URL to use for email verification callback */ + callbackURL?: string; + /** @description If this is false, the session will not be remembered. Default is `true`. */ + rememberMe?: boolean; + }; + }; + }; + responses: { + /** @description Successfully created user */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Authentication token for the session */ + token?: string | null; + user: { + /** @description The unique identifier of the user */ + id: string; + /** + * Format: email + * @description The email address of the user + */ + email: string; + /** @description The name of the user */ + name: string; + /** + * Format: uri + * @description The profile image URL of the user + */ + image?: string | null; + /** @description Whether the email has been verified */ + emailVerified: boolean; + /** + * Format: date-time + * @description When the user was created + */ + createdAt: string; + /** + * Format: date-time + * @description When the user was last updated + */ + updatedAt: string; + }; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Unprocessable Entity. User already exists or failed to create user. */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + signInEmail: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email of the user */ + email: string; + /** @description Password of the user */ + password: string; + /** @description Callback URL to use as a redirect for email verification */ + callbackURL?: string | null; + /** + * @description If this is false, the session will not be remembered. Default is `true`. + * @default true + */ + rememberMe?: boolean | null; + }; + }; + }; + responses: { + /** @description Success - Returns either session details or redirect URL */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @enum {boolean} */ + redirect: false; + /** @description Session token */ + token: string; + url?: string | null; + user: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + resetPassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The new password to set */ + newPassword: string; + /** @description The token to reset the password */ + token?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + verifyPassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The password to verify */ + password: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + sendVerificationEmail: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': { + /** + * @description The email to send the verification email to + * @example user@example.com + */ + email: string; + /** + * @description The URL to use for email verification callback + * @example https://example.com/callback + */ + callbackURL?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** + * @description Indicates if the email was sent successfully + * @example true + */ + status?: boolean; + }; + }; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** + * @description Error message + * @example Verification email isn't enabled + */ + message?: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + changeEmail: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The new email address to set must be a valid email address */ + newEmail: string; + /** @description The URL to redirect to after email verification */ + callbackURL?: string | null; + }; + }; + }; + responses: { + /** @description Email change request processed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + /** @description Indicates if the request was successful */ + status: boolean; + /** + * @description Status message of the email change process + * @enum {string|null} + */ + message?: 'Email updated' | 'Verification email sent' | null; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Unprocessable Entity. Email already exists */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + changePassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The new password to set */ + newPassword: string; + /** @description The current password is required */ + currentPassword: string; + /** @description Must be a boolean value */ + revokeOtherSessions?: boolean | null; + }; + }; + }; + responses: { + /** @description Password successfully changed */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description New session token if other sessions were revoked */ + token?: string | null; + user: { + /** @description The unique identifier of the user */ + id: string; + /** + * Format: email + * @description The email address of the user + */ + email: string; + /** @description The name of the user */ + name: string; + /** + * Format: uri + * @description The profile image URL of the user + */ + image?: string | null; + /** @description Whether the email has been verified */ + emailVerified: boolean; + /** + * Format: date-time + * @description When the user was created + */ + createdAt: string; + /** + * Format: date-time + * @description When the user was last updated + */ + updatedAt: string; + }; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + updateUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': { + /** @description The name of the user */ + name?: string; + /** @description The image of the user */ + image?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + deleteUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + 'application/json': { + /** @description The callback URL to redirect to after the user is deleted */ + callbackURL?: string; + /** @description The user's password. Required if session is not fresh */ + password?: string; + /** @description The deletion verification token */ + token?: string; + }; + }; + }; + responses: { + /** @description User deletion processed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if the operation was successful */ + success: boolean; + /** + * @description Status message of the deletion process + * @enum {string} + */ + message: 'User deleted' | 'Verification email sent'; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + requestPasswordReset: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The email address of the user to send a password reset email to */ + email: string; + /** @description The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN */ + redirectTo?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + message?: string; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + resetPasswordCallback: { + parameters: { + query: { + /** @description The URL to redirect the user to reset their password */ + callbackURL: string; + }; + header?: never; + path: { + /** @description The token to reset the password */ + token: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + token?: string; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + listUserSessions: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Session'][]; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + linkSocialAccount: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The URL to redirect to after the user has signed in */ + callbackURL?: string | null; + provider: string; + idToken?: { + token: string; + nonce?: string | null; + accessToken?: string | null; + refreshToken?: string | null; + scopes?: unknown[] | null; + } | null; + requestSignUp?: boolean | null; + /** @description Additional scopes to request from the provider */ + scopes?: unknown[] | null; + /** @description The URL to redirect to if there is an error during the link process */ + errorCallbackURL?: string | null; + /** @description Disable automatic redirection to the provider. Useful for handling the redirection yourself */ + disableRedirect?: boolean | null; + additionalData?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description The authorization URL to redirect the user to */ + url?: string; + /** @description Indicates if the user should be redirected to the authorization URL */ + redirect: boolean; + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + listUserAccounts: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + id: string; + providerId: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + accountId: string; + userId: string; + scopes: string[]; + }[]; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + sendEmailVerificationOTP: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address to send the OTP */ + email: string; + /** @description Type of the OTP */ + type: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + verifyEmailWithOTP: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address the OTP was sent to */ + email: string; + /** @description Type of the OTP */ + type: string; + /** @description OTP to verify */ + otp: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + signInWithEmailOTP: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address to sign in */ + email: string; + /** @description OTP sent to the email */ + otp: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Session token for the authenticated session */ + token: string; + user: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + requestPasswordResetWithEmailOTP: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address to send the OTP */ + email: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if the OTP was sent successfully */ + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + forgetPasswordWithEmailOTP: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address to send the OTP */ + email: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + /** @description Indicates if the OTP was sent successfully */ + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + resetPasswordWithEmailOTP: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address to reset the password */ + email: string; + /** @description OTP sent to the email */ + otp: string; + /** @description New password */ + password: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + setActiveOrganization: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + organizationId?: string | null; + /** @description The organization slug to set as active. It can be null to unset the active organization if organizationId is not provided. Eg: "org-slug" */ + organizationSlug?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Organization']; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + getOrganization: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Organization']; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + createOrganizationInvitation: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The email address of the user to invite */ + email: string; + /** @description The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: "member" */ + role: string; + /** @description The organization ID to invite the user to */ + organizationId?: string | null; + /** @description Resend the invitation email, if the user is already invited. Eg: true */ + resend?: boolean | null; + teamId: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + id: string; + email: string; + role: string; + organizationId: string; + inviterId: string; + status: string; + expiresAt: string; + createdAt: string; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + updateOrganizationMemberRole: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The new role to be applied. This can be a string or array of strings representing the roles. Eg: ["admin", "sale"] */ + role: string; + /** @description The member id to apply the role update to. Eg: "member-id" */ + memberId: string; + /** @description An optional organization ID which the member is a part of to apply the role update. If not provided, you must provide session headers to get the active organization. Eg: "organization-id" */ + organizationId?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + member: { + id: string; + userId: string; + organizationId: string; + role: string; + }; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + setUserRole: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + /** @description The role to set, this can be a string or an array of strings. Eg: `admin` or `[admin, user]` */ + role: string; + }; + }; + }; + responses: { + /** @description User role updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + getUser: { + parameters: { + query?: { + id?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + createUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The email of the user */ + email: string; + password?: string | null; + /** @description The name of the user */ + name: string; + role?: string | null; + data?: string | null; + }; + }; + }; + responses: { + /** @description User created */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + updateUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + /** @description The user data to update */ + data: string; + }; + }; + }; + responses: { + /** @description User updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + listUsers: { + parameters: { + query?: { + searchValue?: string | null; + searchField?: string | null; + searchOperator?: string | null; + limit?: string | null; + offset?: string | null; + sortBy?: string | null; + sortDirection?: string | null; + filterField?: string | null; + filterValue?: string | null; + filterOperator?: string | null; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of users */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + users: components['schemas']['User'][]; + total: number; + limit?: number; + offset?: number; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + listUserSessions: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + }; + }; + }; + responses: { + /** @description List of user sessions */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + sessions?: components['schemas']['Session'][]; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + unbanUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + }; + }; + }; + responses: { + /** @description User unbanned */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + banUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + /** @description The reason for the ban */ + banReason?: string | null; + /** @description The number of seconds until the ban expires */ + banExpiresIn?: number | null; + }; + }; + }; + responses: { + /** @description User banned */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + impersonateUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + }; + }; + }; + responses: { + /** @description Impersonation session created */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + session?: components['schemas']['Session']; + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + revokeUserSession: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The session token */ + sessionToken: string; + }; + }; + }; + responses: { + /** @description Session revoked */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + revokeUserSessions: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + }; + }; + }; + responses: { + /** @description Sessions revoked */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + removeUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The user id */ + userId: string; + }; + }; + }; + responses: { + /** @description User removed */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + success?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + setUserPassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description The new password */ + newPassword: string; + /** @description The user id */ + userId: string; + }; + }; + }; + responses: { + /** @description Password set */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + generatePasskeyRegistrationOptions: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + challenge?: string; + rp?: { + name?: string; + id?: string; + }; + user?: { + id?: string; + name?: string; + displayName?: string; + }; + pubKeyCredParams?: { + type?: string; + alg?: number; + }[]; + timeout?: number; + excludeCredentials?: { + id?: string; + type?: string; + transports?: string[]; + }[]; + authenticatorSelection?: { + authenticatorAttachment?: string; + requireResidentKey?: boolean; + userVerification?: string; + }; + attestation?: string; + extensions?: Record; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + passkeyGenerateAuthenticateOptions: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + challenge?: string; + rp?: { + name?: string; + id?: string; + }; + user?: { + id?: string; + name?: string; + displayName?: string; + }; + timeout?: number; + allowCredentials?: { + id?: string; + type?: string; + transports?: string[]; + }[]; + userVerification?: string; + authenticatorSelection?: { + authenticatorAttachment?: string; + requireResidentKey?: boolean; + userVerification?: string; + }; + extensions?: Record; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + passkeyVerifyRegistration: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + response: string; + /** @description Name of the passkey */ + name?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['Passkey']; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + passkeyVerifyAuthentication: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + response: string; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + session?: components['schemas']['Session']; + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + signInWithMagicLink: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + 'application/json': { + /** @description Email address to send the magic link */ + email: string; + /** @description User display name. Only used if the user is registering for the first time. Eg: "my-name" */ + name?: string | null; + /** @description URL to redirect after magic link verification */ + callbackURL?: string | null; + /** @description URL to redirect after new user signup. Only used if the user is registering for the first time. */ + newUserCallbackURL?: string | null; + /** @description URL to redirect after error. */ + errorCallbackURL?: string | null; + }; + }; + }; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + status?: boolean; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; + verifyMagicLink: { + parameters: { + query?: { + token?: string; + callbackURL?: string | null; + errorCallbackURL?: string | null; + newUserCallbackURL?: string | null; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + session?: components['schemas']['Session']; + user?: components['schemas']['User']; + }; + }; + }; + /** @description Bad Request. Usually due to missing parameters, or invalid parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Unauthorized. Due to missing or invalid authentication. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message: string; + }; + }; + }; + /** @description Forbidden. You do not have permission to access this resource or to perform this action. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Not Found. The requested resource was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Too Many Requests. You have exceeded the rate limit. Try again later. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + /** @description Internal Server Error. This is a problem with the server that you cannot fix. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': { + message?: string; + }; + }; + }; + }; + }; +} diff --git a/lib/api/hackathons.ts b/lib/api/hackathons.ts index 2e571a3da..177e926f9 100644 --- a/lib/api/hackathons.ts +++ b/lib/api/hackathons.ts @@ -1,5 +1,6 @@ import api from './api'; import { ApiResponse, ErrorResponse, PaginatedResponse } from './types'; +import type { Schemas } from './openapi'; // Discussion type removed - using generic Comment type from @/types/comment // Enums matching backend models @@ -299,7 +300,9 @@ export interface HackathonDraftData { // Draft Types export interface HackathonDraft { id: string; - status: 'draft'; + // Real Hackathon status. Normally DRAFT; a hackathon mid-publish stays in the + // drafts list as DRAFT_AWAITING_FUNDING until its escrow op settles. + status: 'DRAFT' | 'DRAFT_AWAITING_FUNDING'; currentStep: number; completedSteps: string[]; data: HackathonDraftData; @@ -336,6 +339,8 @@ export type Hackathon = { status: | 'DRAFT' + // Between escrow publish-request and on-chain create_event settling. + | 'DRAFT_AWAITING_FUNDING' | 'UPCOMING' | 'ACTIVE' | 'JUDGING' @@ -876,12 +881,6 @@ export interface GetParticipantsResponse extends ApiResponse { // teamMembers?: string[]; // } -export interface RegisterForHackathonResponse extends ApiResponse { - success: true; - data: Participant; - message: string; -} - export interface CheckRegistrationStatusResponse extends ApiResponse { success: true; data: Participant | null; @@ -1168,52 +1167,6 @@ export interface AssignRanksResponse { }; } -export interface HackathonEscrowData { - contractId: string; - escrowAddress: string; - balance: number; - milestones: Array<{ - description: string; - amount: number; - receiver: string; - status: string; - evidence: string; - flags?: { - approved: boolean; - disputed: boolean; - released: boolean; - resolved: boolean; - }; - }>; - isFunded: boolean; - canUpdate: boolean; -} - -export interface GetHackathonEscrowResponse extends ApiResponse { - success: true; - data: HackathonEscrowData; - message: string; -} - -export interface CreateWinnerMilestonesRequest { - winners: Array<{ - participantId: string; - rank: number; - walletAddress: string; - amount?: number; - currency?: string; - }>; -} - -export interface CreateWinnerMilestonesResponse { - success: boolean; - message: string; - data: { - transactionHash?: string; - milestonesCreated: number; - }; -} - // Public Hackathons List API Types export interface PublicHackathonsListData { @@ -1305,19 +1258,21 @@ export const updateDraftStep = async ( }; /** - * Publish a hackathon draft (new API) + * Update several draft steps in one transactional PATCH (new API). Replaces + * firing one request per step when saving/finishing the wizard. */ -export const publishDraft = async ( - draftId: string, +export const updateDraftSteps = async ( organizationId: string, - options?: { skipAnnouncement?: boolean; announcementSubject?: string } -): Promise => { - const res = await api.put>( - `/organizations/${organizationId}/hackathons/draft/${draftId}/publish`, - options ?? {} + draftId: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + steps: { step: string; data: any }[] +) => { + const res = await api.patch( + `/organizations/${organizationId}/hackathons/draft/${draftId}/batch`, + { steps } ); - return res.data as unknown as PublishHackathonResponse; + return res.data; }; /** @@ -1605,112 +1560,6 @@ export const assignRanks = async ( return res.data; }; -// ─── Reward Distribution Status Types ───────────────────────────────────────── - -export type RewardDistributionStatusEnum = - | 'NOT_TRIGGERED' - | 'PENDING_ADMIN_REVIEW' - | 'APPROVED' - | 'REJECTED' - | 'EXECUTING' - | 'COMPLETED' - | 'FAILED' - | 'PARTIAL_SUCCESS'; - -export interface WinnerSnapshot { - submissionId: string; - rank: number; - submissionTitle: string; - prizeTierName: string; - prizeAmount: number; - walletAddresses: string; -} - -export interface RewardDistributionSnapshot { - idempotencyKey: string; - winners: WinnerSnapshot[]; - totalPrizePool: number; - platformFee: number; - totalRequired: number; - currency: string; - escrowAddress: string; - winnersChecksum: string; - snapshotAt: string; - organizerNote: string | null; -} - -export interface RewardDistributionStatusResponse { - distributionId: string | null; - status: RewardDistributionStatusEnum; - snapshot: RewardDistributionSnapshot; - triggeredAt: string; - adminDecisionAt: string | null; - adminNote: string | null; - adminUserId: string | null; - rejectionReason: string | null; - updatedAt: string; -} - -/** - * Get reward distribution status (organizer) - * Returns the latest distribution status: PENDING_ADMIN_REVIEW, APPROVED, REJECTED, EXECUTING, etc. - */ -export const getRewardDistributionStatus = async ( - organizationId: string, - hackathonId: string -): Promise => { - const res = await api.get( - `/organizations/${organizationId}/hackathons/${hackathonId}/rewards/status` - ); - return res.data?.data ?? res.data; -}; - -export interface TriggerRewardDistributionRequest { - idempotencyKey: string; - organizerNote?: string; -} - -/** - * Trigger a new reward distribution for a hackathon. - * Moves the snapshot into PENDING_ADMIN_REVIEW. Requires published results, funds in escrow. - */ -export const triggerRewardDistribution = async ( - organizationId: string, - hackathonId: string, - data: TriggerRewardDistributionRequest -): Promise => { - const res = await api.post( - `/organizations/${organizationId}/hackathons/${hackathonId}/rewards/trigger`, - data - ); - return res.data?.data ?? res.data; -}; - -export const getHackathonEscrow = async ( - organizationId: string, - hackathonId: string -): Promise => { - const res = await api.get( - `/organizations/${organizationId}/hackathons/${hackathonId}/rewards/escrow` - ); - return res.data; -}; - -/** - * Create winner milestones in escrow - */ -export const createWinnerMilestones = async ( - organizationId: string, - hackathonId: string, - data: CreateWinnerMilestonesRequest -): Promise => { - const res = await api.post( - `/organizations/${organizationId}/hackathons/${hackathonId}/rewards/milestones`, - data - ); - return res.data; -}; - /** * Get participants for a hackathon */ @@ -1850,28 +1699,6 @@ export const getExploreSubmissions = async ( return res.data; }; -/** - * Register for a hackathon - * Supports both slug-based (public) and organization/hackathon ID (authenticated) endpoints - */ -export const registerForHackathon = async ( - hackathonSlugOrId: string, - organizationId?: string -): Promise => { - let url: string; - - // If organizationId is provided, use authenticated endpoint - if (organizationId) { - url = `/organizations/${organizationId}/hackathons/${hackathonSlugOrId}/join`; - } else { - // Otherwise, use public slug-based endpoint - url = `/hackathons/${hackathonSlugOrId}/join`; - } - - const res = await api.post(url); - return res.data; -}; - /** * Leave a hackathon * Supports both slug-based (public) and organization/hackathon ID (authenticated) endpoints @@ -2197,14 +2024,19 @@ export const isHackathon = (obj: unknown): obj is Hackathon => { }; export const isHackathonDraft = (obj: unknown): obj is HackathonDraft => { - return ( - typeof obj === 'object' && - obj !== null && - 'id' in obj && - 'organizationId' in obj && - 'status' in obj && - (obj as unknown as HackathonDraft).status === 'draft' - ); + if ( + typeof obj !== 'object' || + obj === null || + !('id' in obj) || + !('organizationId' in obj) || + !('status' in obj) + ) { + return false; + } + const status = String( + (obj as { status?: unknown }).status ?? '' + ).toUpperCase(); + return status === 'DRAFT' || status === 'DRAFT_AWAITING_FUNDING'; }; export const isCreateDraftRequest = ( diff --git a/lib/api/hackathons/draft.ts b/lib/api/hackathons/draft.ts deleted file mode 100644 index dd752e82a..000000000 --- a/lib/api/hackathons/draft.ts +++ /dev/null @@ -1,171 +0,0 @@ -// Hackathon Draft Operations -import api from '../api'; -import { ApiResponse, PaginatedResponse } from '../types'; -import type { HackathonDraft, Hackathon } from '@/types/hackathon'; - -// Response Types -export interface CreateDraftResponse extends ApiResponse { - success: true; - data: HackathonDraft; - message: string; -} - -export interface UpdateDraftResponse extends ApiResponse { - success: true; - data: HackathonDraft; - message: string; -} - -export interface GetDraftResponse extends ApiResponse { - success: true; - data: HackathonDraft; - message: string; -} - -export interface PreviewDraftResponse extends ApiResponse { - success: true; - data: Hackathon; - message: string; -} - -export interface GetDraftsResponse extends PaginatedResponse { - success: true; -} - -export interface PublishHackathonResponse extends ApiResponse { - success: true; - data: Hackathon; - message: string; -} - -export interface DeleteHackathonResponse extends ApiResponse { - success: true; - message: string; - data: null; -} - -/** - * Initialize a new hackathon draft - */ -export const initializeDraft = async ( - organizationId: string -): Promise => { - const res = await api.post( - `organizations/${organizationId}/hackathons/draft` - ); - return res.data as CreateDraftResponse; -}; - -/** - * Update a specific step in hackathon draft - */ -export const updateDraftStep = async ( - organizationId: string, - draftId: string, - step: string, - data: any, - autoSave?: boolean -) => { - const res = await api.patch>( - `/organizations/${organizationId}/hackathons/draft/${draftId}`, - { - step, - data, - autoSave, - } - ); - - return res.data; -}; - -export interface PublishDraftOptions { - /** Skip the launch announcement email entirely. */ - skipAnnouncement?: boolean; - /** Override the default email subject (max 120 chars). */ - announcementSubject?: string; -} - -/** - * Publish a hackathon draft - */ -export const publishDraft = async ( - draftId: string, - organizationId: string, - options?: PublishDraftOptions -): Promise => { - const res = await api.put>( - `/organizations/${organizationId}/hackathons/draft/${draftId}/publish`, - options ?? {} - ); - - return res.data.data as PublishHackathonResponse; -}; - -export interface AnnouncementAudiencePreview { - audienceSize: number; -} - -/** - * Preview how many subscribers would receive the launch announcement email. - */ -export const previewAnnouncementAudience = async ( - draftIdOrHackathonId: string, - organizationId: string -): Promise => { - const res = await api.get>( - `/organizations/${organizationId}/hackathons/hackathons/${draftIdOrHackathonId}/announcement-preview` - ); - return (res.data.data as AnnouncementAudiencePreview) || { audienceSize: 0 }; -}; - -/** - * Delete Draft Hackathon - */ -export const deleteDraft = async ( - draftId: string, - organizationId: string -): Promise => { - const res = await api.delete( - `/organizations/${organizationId}/hackathons/draft/${draftId}` - ); - - if (res.status === 204) { - return { success: true, message: 'Deleted successfully', data: null }; - } - - return res.data as DeleteHackathonResponse; -}; - -/** - * Get a single hackathon draft by ID - */ -export const getDraft = async ( - organizationId: string, - draftId: string -): Promise => { - const res = await api.get>( - `/organizations/${organizationId}/hackathons/draft/${draftId}` - ); - - return res.data.data as GetDraftResponse; -}; - -/** - * Get all hackathon drafts for an organization - */ -export const getDrafts = async ( - organizationId: string, - page = 1, - limit = 10 -): Promise => { - const params = new URLSearchParams({ - page: page.toString(), - limit: limit.toString(), - }); - - const res = await api.get>( - `/organizations/${organizationId}/hackathons/drafts?${params.toString()}` - ); - - return res.data as GetDraftsResponse; -}; diff --git a/lib/api/hackathons/index.ts b/lib/api/hackathons/index.ts index 5ef86d4f6..b1ca5abe0 100644 --- a/lib/api/hackathons/index.ts +++ b/lib/api/hackathons/index.ts @@ -55,9 +55,6 @@ export type { // Rewards types AssignRanksRequest, AssignRanksResponse, - HackathonEscrowData, - CreateWinnerMilestonesRequest, - CreateWinnerMilestonesResponse, // Team types AcceptTeamInvitationRequest, } from '@/types/hackathon'; @@ -79,3 +76,4 @@ export * from './resources'; export * from './announcements'; export * from './partners'; export * from './tracks'; +// Hackathon escrow now lives in features/hackathons (typed openapi-fetch client). diff --git a/lib/api/hackathons/partners.ts b/lib/api/hackathons/partners.ts index 4f4903ac8..34facd636 100644 --- a/lib/api/hackathons/partners.ts +++ b/lib/api/hackathons/partners.ts @@ -1,5 +1,6 @@ import api from '../api'; import type { ApiResponse } from '../types'; +import type { Schemas } from '../openapi'; export type PartnerContributionStatus = | 'PENDING' @@ -88,16 +89,9 @@ export interface ContributionAllocationDetail { allocations: AllocationRecord[]; } -export interface AllocationTarget { - tierId?: string; - newTierLabel?: string; - newTierDescription?: string; - amount: number; -} +export type AllocationTarget = Schemas['AllocationTargetDto']; -export interface AllocateContributionRequest { - targets: AllocationTarget[]; -} +export type AllocateContributionRequest = Schemas['AllocateContributionDto']; export interface PrizeTierShape { id?: string; diff --git a/lib/api/hackathons/rewards.ts b/lib/api/hackathons/rewards.ts index 58a75aa90..72e148528 100644 --- a/lib/api/hackathons/rewards.ts +++ b/lib/api/hackathons/rewards.ts @@ -1,17 +1,10 @@ import api from '../api'; -import { ApiResponse } from '../types'; +import type { Schemas } from '../openapi'; // ── Fee Estimate ───────────────────────────────────────────────────────────── // GET /api/hackathons/fee-estimate?totalPool=... -export interface FeeEstimateData { - totalPool: number; - feeRate: number; - feeRatePercent: number; - feeAmount: number; - totalFunds: number; - feeLabel: string; -} +export type FeeEstimateData = Schemas['FeeEstimateResponseDto']; export interface GetFeeEstimateResponse { success: boolean; @@ -112,52 +105,6 @@ export interface AssignRanksResponse { }; } -export interface HackathonEscrowData { - contractId: string; - escrowAddress: string; - balance: number; - milestones: Array<{ - description: string; - amount: number; - receiver: string; - status: string; - evidence: string; - flags?: { - approved: boolean; - disputed: boolean; - released: boolean; - resolved: boolean; - }; - }>; - isFunded: boolean; - canUpdate: boolean; -} - -export interface GetHackathonEscrowResponse extends ApiResponse { - success: true; - data: HackathonEscrowData; - message: string; -} - -export interface CreateWinnerMilestonesRequest { - winners: Array<{ - participantId: string; - rank: number; - walletAddress: string; - amount?: number; - currency?: string; - }>; -} - -export interface CreateWinnerMilestonesResponse { - success: boolean; - message: string; - data: { - transactionHash?: string; - milestonesCreated: number; - }; -} - /** * Assign ranks to submissions */ @@ -173,33 +120,6 @@ export const assignRanks = async ( return res.data; }; -/** - * Get hackathon escrow details - */ -export const getHackathonEscrow = async ( - organizationId: string, - hackathonId: string -): Promise => { - const res = await api.get( - `/organizations/${organizationId}/hackathons/${hackathonId}/rewards/escrow` - ); - return res.data; -}; - -/** - * Create winner milestones in escrow - */ -export const createWinnerMilestones = async ( - organizationId: string, - hackathonId: string, - data: CreateWinnerMilestonesRequest -): Promise => { - const res = await api.post( - `/organizations/${organizationId}/hackathons/${hackathonId}/rewards/milestones`, - data - ); - return res.data; -}; /** * Export hackathon data (organizer only) * GET /api/organizations/:organizationId/hackathons/:id/export?format=csv|pdf&dataset=full|... diff --git a/lib/api/hackathons/tracks.ts b/lib/api/hackathons/tracks.ts index a33a86c11..7ad4e04d3 100644 --- a/lib/api/hackathons/tracks.ts +++ b/lib/api/hackathons/tracks.ts @@ -1,5 +1,6 @@ import api from '../api'; import { ApiResponse } from '../types'; +import type { Schemas } from '../openapi'; // ── Types ─────────────────────────────────────────────────────────────── @@ -10,69 +11,15 @@ export type HackathonPrizeStructure = | 'OVERALL_AND_TRACKS' | 'TRACKS_ONLY'; -export interface TrackCustomQuestion { - id: string; - label: string; - type: 'short' | 'long' | 'url'; - maxLength?: number; - required?: boolean; -} +export type TrackCustomQuestion = Schemas['TrackCustomQuestionDto']; -export interface TrackRequiredArtifact { - id: string; - label: string; - type: 'figma' | 'github' | 'video' | 'pdf' | 'url'; - required?: boolean; -} +export type TrackRequiredArtifact = Schemas['TrackRequiredArtifactDto']; -export interface HackathonTrack { - id: string; - hackathonId: string; - slug: string; - name: string; - description?: string; - /** Free-form classifier: 'skill' | 'technology' | 'theme' | 'special'. */ - type?: string; - eligibility: TrackEligibility; - displayOrder: number; - isArchived: boolean; - /** Number of submissions opted into this track. */ - entryCount: number; - /** Single open-ended prompt rendered on the submission form. */ - prompt?: string; - /** Organizer-defined custom questions. Phase B. */ - customQuestions?: TrackCustomQuestion[]; - /** Required artifact slots (e.g. Figma file URL). Phase B. */ - requiredArtifacts?: TrackRequiredArtifact[]; - createdAt: string; - updatedAt: string; -} +export type HackathonTrack = Schemas['TrackResponseDto']; -export interface CreateTrackRequest { - name: string; - /** Optional. Auto-generated from name if omitted. */ - slug?: string; - description?: string; - type?: string; - eligibility?: TrackEligibility; - displayOrder?: number; - prompt?: string; - customQuestions?: TrackCustomQuestion[]; - requiredArtifacts?: TrackRequiredArtifact[]; -} +export type CreateTrackRequest = Schemas['CreateTrackDto']; -export interface UpdateTrackRequest { - name?: string; - slug?: string; - description?: string; - type?: string; - eligibility?: TrackEligibility; - displayOrder?: number; - isArchived?: boolean; - prompt?: string; - customQuestions?: TrackCustomQuestion[]; - requiredArtifacts?: TrackRequiredArtifact[]; -} +export type UpdateTrackRequest = Schemas['UpdateTrackDto']; /** Submitter responses to a single track's customization. */ export interface TrackAnswer { diff --git a/lib/api/index.ts b/lib/api/index.ts new file mode 100644 index 000000000..e958bedb6 --- /dev/null +++ b/lib/api/index.ts @@ -0,0 +1,22 @@ +// Public surface for the modern, OpenAPI-typed data layer (mirrors +// boundless-platform's `@/lib/api`). New + migrated feature code imports from +// here: `import { apiClient, unwrapData, type Schemas } from '@/lib/api'`. +// +// NOTE: legacy code still imports the axios client + hand-written types from the +// explicit paths `@/lib/api/api`, `@/lib/api/hackathons`, etc. Those are being +// migrated to this layer gradually and intentionally left untouched here. +export { + apiClient, + unwrapData, + ApiError, + toApiError, + getResponseMeta, +} from './client'; + +export type { + Schemas, + paths, + components, + ApiFieldError, + ApiMeta, +} from './openapi'; diff --git a/lib/api/openapi.ts b/lib/api/openapi.ts new file mode 100644 index 000000000..5761b1496 --- /dev/null +++ b/lib/api/openapi.ts @@ -0,0 +1,28 @@ +// Re-exports of the OpenAPI-generated schema. Generated types come from the +// backend spec via `npm run codegen` (do NOT hand-edit lib/api/generated/). +// New/migrated code derives request + response types from `Schemas['']` +// instead of hand-writing them. +import type { components, paths } from './generated/schema'; + +export type { components, paths }; + +/** All backend DTOs, keyed by name: `Schemas['PublishHackathonEscrowDto']`. */ +export type Schemas = components['schemas']; + +/** A single field-level validation error in the backend's error envelope. */ +export interface ApiFieldError { + field?: string; + message: string; +} + +/** The `meta` block on the backend's `{ success, message, data, meta }` envelope. */ +export interface ApiMeta { + requestId?: string; + timestamp?: string; + pagination?: { + page: number; + limit: number; + total: number; + totalPages: number; + }; +} diff --git a/lib/api/organization.ts b/lib/api/organization.ts index 909d92f25..2c512de42 100644 --- a/lib/api/organization.ts +++ b/lib/api/organization.ts @@ -1,6 +1,7 @@ import api from './api'; import { Logger } from '@/lib/logger'; import { ApiResponse, ErrorResponse, PaginatedResponse } from './types'; +import type { Schemas } from './openapi'; export interface OrganizationLinks { website: string; @@ -35,18 +36,7 @@ export interface Organization { /** * Public organization profile (by slug) - GET /organizations/profile/:slug */ -export interface OrganizationProfile { - id: string; - name: string; - logoUrl: string; - description: string; - stats: { - projectsCount: number; - totalHackathons: number; - totalBounties: number; - totalGrants: number; - }; -} +export type OrganizationProfile = Schemas['OrganizationProfileDto']; export type Role = 'member' | 'admin' | 'owner'; diff --git a/lib/api/types.ts b/lib/api/types.ts index d418161a3..ea1cdbdce 100644 --- a/lib/api/types.ts +++ b/lib/api/types.ts @@ -1,5 +1,6 @@ import { CrowdfundingProject, Crowdfunding } from '@/features/projects/types'; import type { Hackathon } from '@/types/hackathon/core'; +import type { Schemas } from './openapi'; // Backend API Response Structure export interface ApiResponse { @@ -251,19 +252,7 @@ export interface GetMeResponse { username?: string; image?: string; isVerified?: boolean; - stats: { - projectsCreated: number; - projectsFunded: number; - totalContributed: number; - commentsPosted: number; - votes: number; - grants: number; - hackathons: number; - followers: number; - following: number; - reputation: number; - communityScore: number; - }; + stats: Schemas['UserStatsDto']; chart: Array<{ date: string; count: number }>; activitiesGraph: Array<{ date: string; count: number }>; recentActivities: Array<{ @@ -885,6 +874,9 @@ export interface DeleteCrowdfundingProjectResponse { } // Funding Types +// NOT migrated to Schemas['ContributeCampaignDto']: the /crowdfunding/projects/:id/fund +// endpoint this feeds (features/projects/api fundCrowdfundingProject) sends a +// frontend-computed transactionHash, which the contribute DTO does not model. export interface FundCrowdfundingProjectRequest { amount: number; transactionHash?: string; @@ -1016,36 +1008,10 @@ export interface RemoveVoteResponse { // Alias for backward compatibility // export type CrowdfundingCampaign = CreateCrowdfundingProjectResponse; -export interface AnnouncementAuthor { - id: string; - name: string; - image?: string; - username?: string; -} +export type AnnouncementAuthor = Schemas['AnnouncementAuthorDto']; -export interface HackathonAnnouncement { - id: string; - hackathonId: string; - title: string; - content: string; - isDraft: boolean; - isPinned: boolean; - publishedAt?: string; - createdAt: string; - updatedAt: string; - author: AnnouncementAuthor; -} +export type HackathonAnnouncement = Schemas['AnnouncementResponseDto']; -export interface CreateAnnouncementRequest { - title: string; - content: string; - isDraft?: boolean; - isPinned?: boolean; -} +export type CreateAnnouncementRequest = Schemas['CreateAnnouncementDto']; -export interface UpdateAnnouncementRequest { - title?: string; - content?: string; - isDraft?: boolean; - isPinned?: boolean; -} +export type UpdateAnnouncementRequest = Schemas['UpdateAnnouncementDto']; diff --git a/lib/api/user/earnings.ts b/lib/api/user/earnings.ts index 31e5a90a7..c62621fff 100644 --- a/lib/api/user/earnings.ts +++ b/lib/api/user/earnings.ts @@ -1,29 +1,10 @@ import { api } from '../api'; import { ApiResponse } from '../types'; +import type { Schemas } from '../openapi'; -export interface EarningActivity { - id: string; - source: 'hackathons' | 'grants' | 'crowdfunding' | 'bounties'; - title: string; - amount: number; - currency: string; - occurredAt: string; -} +export type EarningActivity = Schemas['EarningActivityDto']; -export interface EarningsData { - summary: { - totalEarned: number; - pendingWithdrawal: number; - completedWithdrawal: number; - }; - breakdown: { - hackathons: number; - grants: number; - crowdfunding: number; - bounties: number; - }; - activities: EarningActivity[]; -} +export type EarningsData = Schemas['EarningsResponseDto']; export type GetEarningsResponse = | { success: true; data: EarningsData; message?: string } diff --git a/lib/api/wallet.ts b/lib/api/wallet.ts index fc3e8625c..265894a91 100644 --- a/lib/api/wallet.ts +++ b/lib/api/wallet.ts @@ -1,4 +1,5 @@ import { api } from '@/lib/api/api'; +import type { Schemas } from '@/lib/api/openapi'; import type { WalletBalance, WalletData, @@ -28,14 +29,7 @@ export interface ValidateSendDestinationResponse { hasTrustline?: boolean; } -export interface SendFundsRequest { - destinationPublicKey: string; - amount: number; - currency: string; - memo?: string; - memoRequired?: boolean; - idempotencyKey?: string; -} +export type SendFundsRequest = Schemas['UserSendDto']; /** Backend wraps payload in { success, message, data, meta } */ interface BackendWrapped { @@ -99,6 +93,17 @@ export const addTrustline = async ( return unwrap(data); }; +/** Live USDC + XLM balance for any Stellar address (public on-chain data). */ +export const getWalletBalanceByAddress = async ( + address: string +): Promise<{ address: string; usdc: string; xlm: string }> => { + const { data } = await api.get< + | { address: string; usdc: string; xlm: string } + | BackendWrapped<{ address: string; usdc: string; xlm: string }> + >(`wallet/balance/${address}`); + return unwrap(data); +}; + export const validateSendDestination = async ( destinationPublicKey: string, currency: string @@ -130,5 +135,6 @@ export const walletApi = { getSupportedTrustlineAssets, addTrustline, validateSendDestination, + getWalletBalanceByAddress, sendFunds, }; diff --git a/lib/auth/logger.ts b/lib/auth/logger.ts index fade9a8b2..c6a886793 100644 --- a/lib/auth/logger.ts +++ b/lib/auth/logger.ts @@ -17,14 +17,14 @@ export class AuthLogger { } /** - * Log authentication errors (reported to Sentry when configured) + * Log authentication errors (forwarded to the error-reporting service when configured) */ static error(event: string, error: Error, data?: Record) { reportError(error, { context: 'auth', event, ...data }); } /** - * Log authentication warnings (reported to Sentry when configured) + * Log authentication warnings (forwarded to the error-reporting service when configured) */ static warn(event: string, data?: Record) { reportMessage(`[AUTH WARN] ${event}`, 'warning', data); diff --git a/lib/config/tokens.ts b/lib/config/tokens.ts new file mode 100644 index 000000000..3c42ccd7a --- /dev/null +++ b/lib/config/tokens.ts @@ -0,0 +1,89 @@ +/** + * Token contract (SAC) configuration for the boundless-events escrow flow. + * + * The v2 escrow endpoints take a `tokenAddress` that must be the Stellar Asset + * Contract (SAC) **C-address** whitelisted on the events contract — NOT the + * classic issuer G-address (e.g. the old `USDC_TRUSTLINE_ADDRESS`). The + * backend rejects anything that isn't a valid C-address. + * + * The concrete SAC values come from the backend admin runbook (the contract's + * whitelisted token registry) and are injected per network via env vars so + * testnet/mainnet stay in lockstep with the backend without a code change. + */ +import { getCurrentNetwork, type NetworkType } from '@/lib/wallet-utils'; + +// Stellar contract (SAC) address: 56-char base32, starts with C. Mirrors the +// backend C_ADDRESS_REGEX in hackathon-escrow.dto.ts. +const C_ADDRESS_REGEX = /^C[A-Z2-7]{55}$/; + +/** + * USDC SAC (Soroban) contract addresses per network. Defaults mirror the + * backend's canonical registry (boundless-nestjs + * src/common/utils/supported-currencies.ts) so the frontend is correct out of + * the box and the escrow token always matches the wallet's USDC. Override via + * env only if the backend registry changes. + */ +const USDC_SAC_BY_NETWORK: Record = { + testnet: + process.env.NEXT_PUBLIC_USDC_TOKEN_CONTRACT_TESTNET || + 'CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA', + public: + process.env.NEXT_PUBLIC_USDC_TOKEN_CONTRACT_PUBLIC || + 'CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75', +}; + +/** Currencies the prize pool can be denominated in. USDC only for now. */ +export type SupportedCurrency = 'USDC'; + +const SAC_BY_CURRENCY: Record< + SupportedCurrency, + Record +> = { + USDC: USDC_SAC_BY_NETWORK, +}; + +/** + * Resolve the SAC (C-address) for a currency on a given network, for use as the + * escrow `tokenAddress`. Defaults to the env-configured current network. + * + * @throws if the currency is unsupported or no SAC is configured for the network. + */ +export function getTokenAddress( + currency: string, + network: NetworkType = getCurrentNetwork() +): string { + const normalized = currency?.toUpperCase() as SupportedCurrency; + const byNetwork = SAC_BY_CURRENCY[normalized]; + if (!byNetwork) { + throw new Error( + `Unsupported escrow currency "${currency}". Only USDC is supported.` + ); + } + + const address = byNetwork[network]; + if (!address) { + throw new Error( + `No ${normalized} token contract configured for ${network}. Set ` + + `NEXT_PUBLIC_USDC_TOKEN_CONTRACT_${network.toUpperCase()} to the ` + + 'whitelisted SAC C-address from the backend admin runbook.' + ); + } + if (!C_ADDRESS_REGEX.test(address)) { + throw new Error( + `Configured ${normalized} token contract for ${network} ("${address}") ` + + 'is not a valid Stellar contract (C-) address.' + ); + } + return address; +} + +/** Whether a SAC is configured for the given currency/network (no throw). */ +export function hasTokenAddress( + currency: string, + network: NetworkType = getCurrentNetwork() +): boolean { + const byNetwork = + SAC_BY_CURRENCY[currency?.toUpperCase() as SupportedCurrency]; + const address = byNetwork?.[network]; + return !!address && C_ADDRESS_REGEX.test(address); +} diff --git a/lib/config/wallet-kit.ts b/lib/config/wallet-kit.ts index f4c4b77e1..40b611ecb 100644 --- a/lib/config/wallet-kit.ts +++ b/lib/config/wallet-kit.ts @@ -1,17 +1,21 @@ /** - * Transaction signing stub. Wallet is managed by the backend; signing is not - * available until the backend exposes a sign endpoint (e.g. POST /api/wallet/sign). - * Escrow and funding flows will fail at runtime until then. + * Connected-wallet transaction signer. + * + * Previously a stub that threw (signing was unavailable). Now delegates to the + * Stellar Wallets Kit (Freighter / xBull / Albedo / Lobstr / Hana) so the + * legacy escrow + crowdfunding flows that call signTransaction({ ... }) get a + * real multi-wallet signer with the Kit's built-in connect modal. */ +import { signXdrWithKit } from '@/lib/wallet/wallet-kit'; + interface SignTransactionProps { unsignedTransaction: string; address: string; } -export const signTransaction = async ( - _props: SignTransactionProps -): Promise => { - throw new Error( - 'Transaction signing is not available. Backend must expose a sign endpoint for escrow and funding.' - ); +export const signTransaction = async ({ + unsignedTransaction, + address, +}: SignTransactionProps): Promise => { + return signXdrWithKit(unsignedTransaction, address); }; diff --git a/lib/error-reporting.ts b/lib/error-reporting.ts index 22cafdae4..ab57a8f4d 100644 --- a/lib/error-reporting.ts +++ b/lib/error-reporting.ts @@ -1,95 +1,40 @@ /** - * Central error reporting for production observability. - * When NEXT_PUBLIC_SENTRY_DSN is set, errors are sent to Sentry. - * Otherwise logs to console in development and no-ops in production. + * Central error-reporting seam for production observability. + * + * A previous third-party error reporter was removed; a new one will be wired in + * here later. Until then this logs to the console in development and no-ops in + * production. Call sites (`reportError` / `reportMessage`) stay unchanged when + * the replacement lands — only this module does. */ -import type { Scope } from '@sentry/nextjs'; - type ReportContext = Record; -const hasSentry = (): boolean => - typeof process !== 'undefined' && - typeof process.env !== 'undefined' && - Boolean(process.env.NEXT_PUBLIC_SENTRY_DSN); - /** - * Report an error to the configured service (e.g. Sentry). - * Safe to call from any environment; no-ops when Sentry is not configured. + * Report an error to the configured error-reporting service. + * Safe to call from any environment. Currently console-only in development. */ export const reportError = (error: unknown, context?: ReportContext): void => { - if (hasSentry()) { - try { - import('@sentry/nextjs') - .then(Sentry => { - const err = error instanceof Error ? error : new Error(String(error)); - if (context && Object.keys(context).length > 0) { - Sentry.withScope((scope: Scope) => { - scope.setContext('extra', context); - Sentry.captureException(err); - }); - } else { - Sentry.captureException(err); - } - }) - .catch(() => { - if (process.env.NODE_ENV === 'development') { - console.error( - '[reportError] Sentry capture failed', - error, - context - ); - } - }); - } catch { - if (process.env.NODE_ENV === 'development') { - console.error('[reportError]', error, context); - } - } - return; - } if (process.env.NODE_ENV === 'development') { console.error('[reportError]', error, context ?? ''); } + // TODO: forward to the replacement error-reporting service once configured. }; /** - * Report a message (warning or info) to the configured service. - * Use for non-exception events you want to track in production. + * Report a message (info / warning / error) to the configured error-reporting + * service. Use for non-exception events you want to track in production. */ export const reportMessage = ( message: string, level: 'info' | 'warning' | 'error' = 'info', context?: ReportContext ): void => { - if (hasSentry()) { - try { - import('@sentry/nextjs') - .then(Sentry => { - if (context && Object.keys(context).length > 0) { - Sentry.withScope((scope: Scope) => { - scope.setContext('extra', context); - Sentry.captureMessage(message, level); - }); - } else { - Sentry.captureMessage(message, level); - } - }) - .catch(() => { - if (process.env.NODE_ENV === 'development') { - console.warn(`[reportMessage] ${level}:`, message, context); - } - }); - } catch { - if (process.env.NODE_ENV === 'development') { - console.warn(`[reportMessage] ${level}:`, message, context); - } - } - return; - } if (process.env.NODE_ENV === 'development') { - if (level === 'error') + if (level === 'error') { console.error('[reportMessage]', message, context ?? ''); - else console.warn('[reportMessage]', message, context ?? ''); + } else { + console.warn(`[reportMessage] ${level}:`, message, context ?? ''); + } } + // TODO: forward to the replacement error-reporting service once configured. }; diff --git a/lib/providers/OrganizationProvider.tsx b/lib/providers/OrganizationProvider.tsx index f0b0a67a3..abd79ba6b 100644 --- a/lib/providers/OrganizationProvider.tsx +++ b/lib/providers/OrganizationProvider.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useRef, } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { Logger } from '@/lib/logger'; import { reportError } from '@/lib/error-reporting'; @@ -21,7 +22,7 @@ import { OrganizationFormData, } from './organization-types'; import { Organization } from '../api/types'; -import { getMe } from '../api/auth'; +import { getMe, ME_QUERY_KEY } from '../api/auth'; import { getOrganization, updateOrganizationProfile, @@ -285,9 +286,14 @@ export function OrganizationProvider({ initialOrgId, }: OrganizationProviderProps) { const [state, dispatch] = useReducer(organizationReducer, initialState); + const queryClient = useQueryClient(); const isInitializedRef = useRef(false); const isFetchingOrganizationsRef = useRef(false); const isFetchingActiveOrgRef = useRef(false); + // The org id already loaded into (or loading for) activeOrg. Lets repeat + // setActiveOrg(sameId) calls — the provider init AND the page both call it — + // skip a duplicate getOrganization. Reset on failure so a retry can refetch. + const lastActiveOrgFetchRef = useRef(null); const fetchOrganizationsTimeoutRef = useRef | null>(null); @@ -361,307 +367,336 @@ export function OrganizationProvider({ // }; // }, [autoRefresh, refreshInterval, state.activeOrgId]); - const fetchOrganizations = useCallback(async () => { - logger.info({ eventType: 'org.fetchOrganizations.called' }); + const fetchOrganizations = useCallback( + async (force = false) => { + logger.info({ eventType: 'org.fetchOrganizations.called' }); - if (isFetchingOrganizationsRef.current) { - logger.warn({ - eventType: 'org.fetchOrganizations.skipped', - reason: 'in_progress', - }); - return; - } - - isFetchingOrganizationsRef.current = true; - logger.info({ eventType: 'org.fetchOrganizations.start' }); + if (isFetchingOrganizationsRef.current) { + logger.warn({ + eventType: 'org.fetchOrganizations.skipped', + reason: 'in_progress', + }); + return; + } - try { - dispatch({ - type: 'SET_LOADING', - payload: { isLoading: false, isLoadingOrganizations: true }, - }); - dispatch({ - type: 'SET_ERROR', - payload: { error: null, organizationsError: null }, - }); + isFetchingOrganizationsRef.current = true; + logger.info({ eventType: 'org.fetchOrganizations.start' }); - const response = await getMe(); - logger.info({ eventType: 'org.fetchOrganizations.getMe_success' }); + try { + dispatch({ + type: 'SET_LOADING', + payload: { isLoading: false, isLoadingOrganizations: true }, + }); + dispatch({ + type: 'SET_ERROR', + payload: { error: null, organizationsError: null }, + }); - if (!response || typeof response !== 'object') { - throw new Error('Invalid response from getMe API'); - } + // Route the read through React Query so concurrent callers dedupe and the + // result is cached (60s) / inspectable in devtools. `force` (post-mutation + // refresh) bypasses the cache. + const response = await queryClient.fetchQuery({ + queryKey: ME_QUERY_KEY, + queryFn: getMe, + staleTime: force ? 0 : 60_000, + }); + logger.info({ eventType: 'org.fetchOrganizations.getMe_success' }); - const organizations = response.user.members || []; - logger.info({ - eventType: 'org.fetchOrganizations.organizations_loaded', - count: Array.isArray(organizations) ? organizations.length : 0, - }); + if (!response || typeof response !== 'object') { + throw new Error('Invalid response from getMe API'); + } - if (!Array.isArray(organizations)) { - logger.warn({ - eventType: 'org.fetchOrganizations.invalid_organizations_type', + const organizations = response.user.members || []; + logger.info({ + eventType: 'org.fetchOrganizations.organizations_loaded', + count: Array.isArray(organizations) ? organizations.length : 0, }); - dispatch({ type: 'SET_ORGANIZATIONS', payload: [] }); - return; - } - type OrgLike = { - id: string; - organizationId: string; - userId: string; - role: 'owner' | 'member'; - createdAt: string; - organization: { + if (!Array.isArray(organizations)) { + logger.warn({ + eventType: 'org.fetchOrganizations.invalid_organizations_type', + }); + dispatch({ type: 'SET_ORGANIZATIONS', payload: [] }); + return; + } + + type OrgLike = { id: string; - name: string; - slug: string; - logo?: string | null; + organizationId: string; + userId: string; + role: 'owner' | 'member'; createdAt: string; - _count: { - hackathons: number; - grants: number; - members: number; - }; - metadata?: { - tagline?: string; - about?: string; - links?: Record; - }; - }; - } & Record; - - const orgs = organizations as unknown as OrgLike[]; - - const organizationSummaries: OrganizationSummary[] = orgs - .filter( - org => org && typeof org === 'object' && org.id && org.organization - ) - .map(org => { - const orgData = org.organization; - return { - organizationId: orgData.id, - name: orgData.name || 'Unnamed Organization', - logo: orgData.logo || '/images/default-org-logo.png', - tagline: orgData.metadata?.tagline || '', - isProfileComplete: Boolean( - orgData.metadata?.about && - orgData.metadata?.tagline && - orgData.logo - ), - role: - org.role === 'owner' || org.role === 'member' - ? org.role - : 'member', - _count: orgData._count.hackathons, - memberCount: orgData._count.members, // Will be calculated separately if needed - hackathonCount: orgData._count.hackathons, // Will be calculated separately if needed - grantCount: orgData._count.grants, // Will be calculated separately if needed - createdAt: orgData.createdAt, + organization: { + id: string; + name: string; + slug: string; + logo?: string | null; + createdAt: string; + _count: { + hackathons: number; + grants: number; + members: number; + }; + metadata?: { + tagline?: string; + about?: string; + links?: Record; + }; }; - }); + } & Record; + + const orgs = organizations as unknown as OrgLike[]; + + const organizationSummaries: OrganizationSummary[] = orgs + .filter( + org => org && typeof org === 'object' && org.id && org.organization + ) + .map(org => { + const orgData = org.organization; + return { + organizationId: orgData.id, + name: orgData.name || 'Unnamed Organization', + logo: orgData.logo || '/images/default-org-logo.png', + tagline: orgData.metadata?.tagline || '', + isProfileComplete: Boolean( + orgData.metadata?.about && + orgData.metadata?.tagline && + orgData.logo + ), + role: + org.role === 'owner' || org.role === 'member' + ? org.role + : 'member', + _count: orgData._count.hackathons, + memberCount: orgData._count.members, // Will be calculated separately if needed + hackathonCount: orgData._count.hackathons, // Will be calculated separately if needed + grantCount: orgData._count.grants, // Will be calculated separately if needed + createdAt: orgData.createdAt, + }; + }); - logger.info({ - eventType: 'org.fetchOrganizations.transformed', - count: organizationSummaries.length, - sampleOrg: organizationSummaries[0] - ? { - organizationId: organizationSummaries[0].organizationId, - name: organizationSummaries[0].name, - hackathonCount: organizationSummaries[0].hackathonCount, - grantCount: organizationSummaries[0].grantCount, - memberCount: organizationSummaries[0].memberCount, - } - : null, - }); - dispatch({ type: 'SET_ORGANIZATIONS', payload: organizationSummaries }); - dispatch({ type: 'SET_LAST_UPDATED', payload: Date.now() }); + logger.info({ + eventType: 'org.fetchOrganizations.transformed', + count: organizationSummaries.length, + sampleOrg: organizationSummaries[0] + ? { + organizationId: organizationSummaries[0].organizationId, + name: organizationSummaries[0].name, + hackathonCount: organizationSummaries[0].hackathonCount, + grantCount: organizationSummaries[0].grantCount, + memberCount: organizationSummaries[0].memberCount, + } + : null, + }); + dispatch({ type: 'SET_ORGANIZATIONS', payload: organizationSummaries }); + dispatch({ type: 'SET_LAST_UPDATED', payload: Date.now() }); - localStorage.setItem( - STORAGE_KEYS.ORGANIZATIONS_CACHE, - JSON.stringify(organizationSummaries) - ); - localStorage.setItem(STORAGE_KEYS.LAST_UPDATED, Date.now().toString()); - } catch (error) { - logger.error({ eventType: 'org.fetchOrganizations.error', error }); + localStorage.setItem( + STORAGE_KEYS.ORGANIZATIONS_CACHE, + JSON.stringify(organizationSummaries) + ); + localStorage.setItem(STORAGE_KEYS.LAST_UPDATED, Date.now().toString()); + } catch (error) { + logger.error({ eventType: 'org.fetchOrganizations.error', error }); - let errorMessage: string | null = 'Failed to fetch organizations'; + let errorMessage: string | null = 'Failed to fetch organizations'; - if (error instanceof Error) { - errorMessage = error.message; - } else if (typeof error === 'object' && error !== null) { - // Check for ApiError structure (after interceptor transformation) - const apiErrorStatus = (error as { status?: number }).status; - if (apiErrorStatus === 429) { - errorMessage = - 'Too many requests. Please wait a moment and try again.'; - // Don't show error if we have cached data - use it instead - const cachedOrgs = localStorage.getItem( - STORAGE_KEYS.ORGANIZATIONS_CACHE - ); - if (cachedOrgs) { - try { - const parsed = JSON.parse(cachedOrgs); - if (Array.isArray(parsed) && parsed.length > 0) { - dispatch({ - type: 'SET_ORGANIZATIONS', - payload: parsed, - }); - errorMessage = null; // Clear error since we have cached data - logger.info({ - eventType: 'org.fetchOrganizations.rateLimited_using_cache', - cachedCount: parsed.length, - }); + if (error instanceof Error) { + errorMessage = error.message; + } else if (typeof error === 'object' && error !== null) { + // Check for ApiError structure (after interceptor transformation) + const apiErrorStatus = (error as { status?: number }).status; + if (apiErrorStatus === 429) { + errorMessage = + 'Too many requests. Please wait a moment and try again.'; + // Don't show error if we have cached data - use it instead + const cachedOrgs = localStorage.getItem( + STORAGE_KEYS.ORGANIZATIONS_CACHE + ); + if (cachedOrgs) { + try { + const parsed = JSON.parse(cachedOrgs); + if (Array.isArray(parsed) && parsed.length > 0) { + dispatch({ + type: 'SET_ORGANIZATIONS', + payload: parsed, + }); + errorMessage = null; // Clear error since we have cached data + logger.info({ + eventType: 'org.fetchOrganizations.rateLimited_using_cache', + cachedCount: parsed.length, + }); + } + } catch { + // Cache parse failed, keep error message } - } catch { - // Cache parse failed, keep error message } - } - } else if ( - 'response' in (error as Record) && - (error as Record).response - ) { - // Check axios error structure (before interceptor) - const apiError = ( - error as { - response?: { - status?: number; - statusText?: string; - data?: { message?: string }; - }; + } else if ( + 'response' in (error as Record) && + (error as Record).response + ) { + // Check axios error structure (before interceptor) + const apiError = ( + error as { + response?: { + status?: number; + statusText?: string; + data?: { message?: string }; + }; + } + ).response; + if (apiError?.data?.message) { + errorMessage = apiError.data.message; + } else if (apiError?.status === 401) { + errorMessage = 'Authentication required. Please log in again.'; + } else if (apiError?.status === 403) { + errorMessage = + 'Access denied. You do not have permission to view organizations.'; + } else if ((apiError?.status ?? 0) >= 500) { + errorMessage = 'Server error. Please try again later.'; + } else { + errorMessage = `API Error: ${apiError?.status} ${apiError?.statusText || 'Unknown error'}`; } - ).response; - if (apiError?.data?.message) { - errorMessage = apiError.data.message; - } else if (apiError?.status === 401) { - errorMessage = 'Authentication required. Please log in again.'; - } else if (apiError?.status === 403) { + } else if ('message' in (error as Record)) { errorMessage = - 'Access denied. You do not have permission to view organizations.'; - } else if ((apiError?.status ?? 0) >= 500) { - errorMessage = 'Server error. Please try again later.'; - } else { - errorMessage = `API Error: ${apiError?.status} ${apiError?.statusText || 'Unknown error'}`; + (error as { message?: string }).message || errorMessage; } - } else if ('message' in (error as Record)) { - errorMessage = - (error as { message?: string }).message || errorMessage; } - } - if (errorMessage) { + if (errorMessage) { + dispatch({ + type: 'SET_ERROR', + payload: { error: null, organizationsError: errorMessage }, + }); + } + + if (process.env.NODE_ENV === 'development') { + logger.warn({ + eventType: 'org.fetchOrganizations.dev_help', + notes: [ + 'endpoint missing', + 'unauthenticated', + 'response changed', + 'network issues', + ], + }); + } + } finally { + isFetchingOrganizationsRef.current = false; dispatch({ - type: 'SET_ERROR', - payload: { error: null, organizationsError: errorMessage }, + type: 'SET_LOADING', + payload: { isLoading: false, isLoadingOrganizations: false }, }); } + }, + [queryClient] + ); - if (process.env.NODE_ENV === 'development') { + const fetchActiveOrganization = useCallback( + async (orgId: string, force = false) => { + // Skip the network call when this exact org is already loaded (or loading). + // The provider init AND the org page both call setActiveOrg(orgId); without + // this guard they each fire getOrganization for the same org. + if (!force && lastActiveOrgFetchRef.current === orgId) { + return; + } + if (isFetchingActiveOrgRef.current) { logger.warn({ - eventType: 'org.fetchOrganizations.dev_help', - notes: [ - 'endpoint missing', - 'unauthenticated', - 'response changed', - 'network issues', - ], + eventType: 'org.fetchActiveOrganization.skipped', + reason: 'in_progress', }); + return; } - } finally { - isFetchingOrganizationsRef.current = false; - dispatch({ - type: 'SET_LOADING', - payload: { isLoading: false, isLoadingOrganizations: false }, - }); - } - }, []); - const fetchActiveOrganization = useCallback(async (orgId: string) => { - if (isFetchingActiveOrgRef.current) { - logger.warn({ - eventType: 'org.fetchActiveOrganization.skipped', - reason: 'in_progress', - }); - return; - } + isFetchingActiveOrgRef.current = true; + lastActiveOrgFetchRef.current = orgId; - isFetchingActiveOrgRef.current = true; - - try { - dispatch({ - type: 'SET_LOADING', - payload: { isLoading: false, isLoadingActiveOrg: true }, - }); - dispatch({ - type: 'SET_ERROR', - payload: { error: null, activeOrgError: null }, - }); + try { + dispatch({ + type: 'SET_LOADING', + payload: { isLoading: false, isLoadingActiveOrg: true }, + }); + dispatch({ + type: 'SET_ERROR', + payload: { error: null, activeOrgError: null }, + }); - const response = await getOrganization(orgId); - const organization = response; + const response = await queryClient.fetchQuery({ + queryKey: ['organization', orgId], + queryFn: () => getOrganization(orgId), + staleTime: force ? 0 : 60_000, + }); + const organization = response; - dispatch({ - type: 'SET_ACTIVE_ORG', - payload: { org: organization, orgId }, - }); - dispatch({ type: 'SET_LAST_UPDATED', payload: Date.now() }); - } catch (error) { - let errorMessage: string | null = - error instanceof Error ? error.message : 'Failed to fetch organization'; + dispatch({ + type: 'SET_ACTIVE_ORG', + payload: { org: organization, orgId }, + }); + dispatch({ type: 'SET_LAST_UPDATED', payload: Date.now() }); + } catch (error) { + // Allow a retry of this org after a failure. + lastActiveOrgFetchRef.current = null; + let errorMessage: string | null = + error instanceof Error + ? error.message + : 'Failed to fetch organization'; - const apiError = error as { - status?: number; - message?: string; - code?: string; - }; - if (apiError?.status === 429) { - errorMessage = 'Too many requests. Please wait a moment and try again.'; + const apiError = error as { + status?: number; + message?: string; + code?: string; + }; + if (apiError?.status === 429) { + errorMessage = + 'Too many requests. Please wait a moment and try again.'; - const cachedOrgs = localStorage.getItem( - STORAGE_KEYS.ORGANIZATIONS_CACHE - ); - if (cachedOrgs) { - try { - const parsed = JSON.parse(cachedOrgs); - if (Array.isArray(parsed)) { - const cachedOrg = parsed.find( - (org: { organizationId: string }) => - org.organizationId === orgId - ); - if (cachedOrg) { - dispatch({ - type: 'SET_ACTIVE_ORG', - payload: { org: cachedOrg, orgId }, - }); - errorMessage = null; - logger.info({ - eventType: - 'org.fetchActiveOrganization.rateLimited_using_cache', - orgId, - }); + const cachedOrgs = localStorage.getItem( + STORAGE_KEYS.ORGANIZATIONS_CACHE + ); + if (cachedOrgs) { + try { + const parsed = JSON.parse(cachedOrgs); + if (Array.isArray(parsed)) { + const cachedOrg = parsed.find( + (org: { organizationId: string }) => + org.organizationId === orgId + ); + if (cachedOrg) { + dispatch({ + type: 'SET_ACTIVE_ORG', + payload: { org: cachedOrg, orgId }, + }); + errorMessage = null; + logger.info({ + eventType: + 'org.fetchActiveOrganization.rateLimited_using_cache', + orgId, + }); + } } + } catch { + // Cache parse failed, keep error message } - } catch { - // Cache parse failed, keep error message } } - } - if (errorMessage) { + if (errorMessage) { + dispatch({ + type: 'SET_ERROR', + payload: { error: null, activeOrgError: errorMessage }, + }); + } + logger.error({ eventType: 'org.fetchActiveOrganization.error', error }); + } finally { + isFetchingActiveOrgRef.current = false; dispatch({ - type: 'SET_ERROR', - payload: { error: null, activeOrgError: errorMessage }, + type: 'SET_LOADING', + payload: { isLoading: false, isLoadingActiveOrg: false }, }); } - logger.error({ eventType: 'org.fetchActiveOrganization.error', error }); - } finally { - isFetchingActiveOrgRef.current = false; - dispatch({ - type: 'SET_LOADING', - payload: { isLoading: false, isLoadingActiveOrg: false }, - }); - } - }, []); + }, + [queryClient] + ); const setActiveOrg = useCallback( (orgId: string) => { @@ -689,7 +724,7 @@ export function OrganizationProvider({ const refreshOrganization = useCallback(async () => { if (state.activeOrgId) { - await fetchActiveOrganization(state.activeOrgId); + await fetchActiveOrganization(state.activeOrgId, true); dispatch({ type: 'INCREMENT_REFRESH_COUNT' }); } }, [state.activeOrgId, fetchActiveOrganization]); @@ -701,7 +736,8 @@ export function OrganizationProvider({ } fetchOrganizationsTimeoutRef.current = setTimeout(() => { - fetchOrganizations(); + // Debounced refresh follows a mutation -> force fresh, bypass the cache. + fetchOrganizations(true); }, 300); }, [fetchOrganizations]); @@ -714,9 +750,9 @@ export function OrganizationProvider({ dispatch({ type: 'SET_LOADING', payload: { isLoading: true } }); try { await Promise.all([ - fetchOrganizations(), + fetchOrganizations(true), state.activeOrgId - ? fetchActiveOrganization(state.activeOrgId) + ? fetchActiveOrganization(state.activeOrgId, true) : Promise.resolve(), ]); dispatch({ type: 'INCREMENT_REFRESH_COUNT' }); @@ -1217,31 +1253,34 @@ export function OrganizationProvider({ ); useEffect(() => { - if (!isInitializedRef.current) { - isInitializedRef.current = true; - logger.info({ eventType: 'org.initialize.start' }); - - fetchOrganizations() - .then(() => { - const savedOrgId = - initialOrgId || localStorage.getItem(STORAGE_KEYS.ACTIVE_ORG_ID); - if (savedOrgId) { - logger.info({ - eventType: 'org.initialize.set_active_after_fetch', - orgId: savedOrgId, - }); - setActiveOrgRef.current?.(savedOrgId); - } - }) - .catch(error => { - logger.error({ eventType: 'org.initialize.fetch_error', error }); - const savedOrgId = - localStorage.getItem(STORAGE_KEYS.ACTIVE_ORG_ID) || initialOrgId; - if (savedOrgId) { - setActiveOrgRef.current?.(savedOrgId); - } - }); - } + if (isInitializedRef.current) return; + isInitializedRef.current = true; + logger.info({ eventType: 'org.initialize.start' }); + + const savedOrgId = + initialOrgId || localStorage.getItem(STORAGE_KEYS.ACTIVE_ORG_ID); + + // getMe is shared (ME_QUERY_KEY) with the auth-profile query and cached 60s + // in React Query — since the auth hook fetches it on every authed page, this + // resolves from cache (or dedupes the in-flight request) rather than firing a + // second /users/me. loadCachedData still paints the list instantly from + // localStorage while this settles. + fetchOrganizations() + .then(() => { + if (savedOrgId) { + logger.info({ + eventType: 'org.initialize.set_active_after_fetch', + orgId: savedOrgId, + }); + setActiveOrgRef.current?.(savedOrgId); + } + }) + .catch(error => { + logger.error({ eventType: 'org.initialize.fetch_error', error }); + if (savedOrgId) { + setActiveOrgRef.current?.(savedOrgId); + } + }); }, [fetchOrganizations, initialOrgId]); const assignRole = useCallback( @@ -1328,7 +1367,7 @@ export function OrganizationProvider({ dispatch({ type: 'UPDATE_ORGANIZATION', payload: updatedOrg }); // Refresh organizations list to update current user's role in the UI - await fetchOrganizations(); + await fetchOrganizations(true); } else { logger.error({ eventType: 'org.transfer_ownership.error', diff --git a/lib/providers/hackathonProvider.tsx b/lib/providers/hackathonProvider.tsx index 898465a28..3f223ad41 100644 --- a/lib/providers/hackathonProvider.tsx +++ b/lib/providers/hackathonProvider.tsx @@ -90,7 +90,7 @@ export function HackathonDataProvider({ } = useHackathon(hackathonSlug, initialData); // The full submissions list is an organizer-only endpoint — calling it as - // a participant returns 403 and pollutes the network tab / Sentry. Only + // a participant returns 403 and pollutes the network tab. Only // fetch when the backend says this viewer can see everyone's submissions. const isOrganizerView = currentHackathon?.viewerRole === 'organizer' || diff --git a/lib/stores/auth-store.ts b/lib/stores/auth-store.ts deleted file mode 100644 index 08c092bd8..000000000 --- a/lib/stores/auth-store.ts +++ /dev/null @@ -1,422 +0,0 @@ -import { create } from 'zustand'; -import { persist, createJSONStorage } from 'zustand/middleware'; -import { getMe } from '@/lib/api/auth'; -import Cookies from 'js-cookie'; - -// Debounce utility for API calls -let refreshTimeout: ReturnType | null = null; - -// JWT payload interface -interface JWTPayload { - user_id?: string; - userId?: string; - sub?: string; - exp?: number; - iat?: number; - [key: string]: unknown; -} - -// Session user interface for NextAuth -interface SessionUser { - id: string; - _id?: string; - email: string; - name?: string; - image?: string; - role?: string; - accessToken?: string; - username?: string; - [key: string]: unknown; -} - -// Simple JWT decode function to extract user ID from token -function decodeJWT(token: string): JWTPayload | null { - try { - const base64Url = token.split('.')[1]; - const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); - const jsonPayload = decodeURIComponent( - atob(base64) - .split('') - .map(function (c) { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }) - .join('') - ); - return JSON.parse(jsonPayload); - } catch { - return null; - } -} - -// Check if token is expired -function isTokenExpired(token: string): boolean { - try { - const payload = decodeJWT(token); - if (!payload || !payload.exp) return true; - - const currentTime = Math.floor(Date.now() / 1000); - return payload.exp < currentTime; - } catch { - return true; - } -} - -export interface User { - id: string; - email: string; - name: string | null; - image: string | null; - role: 'USER' | 'ADMIN'; - username?: string | null; - isVerified?: boolean; - profile?: { - firstName?: string; - lastName?: string; - avatar?: string; - username?: string; - }; -} - -export interface AuthState { - // State - user: User | null; - accessToken: string | null; - refreshToken: string | null; - isAuthenticated: boolean; - isLoading: boolean; - error: string | null; - - // Actions - setUser: (user: User | null) => void; - setTokens: (accessToken: string | null, refreshToken?: string | null) => void; - setLoading: (loading: boolean) => void; - setError: (error: string | null) => void; - login: (accessToken: string, refreshToken?: string) => Promise; - logout: () => Promise; - refreshUser: () => Promise; - clearAuth: () => void; - updateUser: (updates: Partial) => void; - syncWithSession: (sessionUser: SessionUser) => Promise; -} - -// Safe localStorage access for SSR -const getStorage = () => { - if (typeof window !== 'undefined') { - return localStorage; - } - return { - getItem: () => null, - setItem: () => {}, - removeItem: () => {}, - }; -}; - -export const useAuthStore = create()( - persist( - (set, get) => ({ - // Initial state - user: null, - accessToken: null, - refreshToken: null, - isAuthenticated: false, - isLoading: false, - error: null, - - // Actions - setUser: user => { - set({ user, isAuthenticated: !!user }); - }, - - setTokens: (accessToken, refreshToken) => { - set({ accessToken, refreshToken }); - - // Update cookies only on client side - if (typeof window !== 'undefined') { - if (accessToken) { - Cookies.set('accessToken', accessToken); - } else { - Cookies.remove('accessToken'); - } - - if (refreshToken) { - Cookies.set('refreshToken', refreshToken); - } else { - Cookies.remove('refreshToken'); - } - } - }, - - setLoading: isLoading => { - set({ isLoading }); - }, - - setError: error => { - set({ error }); - }, - - login: async (accessToken, refreshToken) => { - try { - set({ isLoading: true, error: null }); - - // Store tokens for backward compatibility (though not used for API calls) - get().setTokens(accessToken, refreshToken); - - // Fetch user data using cookie-based auth (Better Auth) - const user = await getMe(); - - const transformedUser: User = { - id: user.user.id as string, - email: user.user.email as string, - name: user.user.name as string | null, - image: user.user.image as string | null, - username: user.user.username as string | null, - role: user.user.role as 'USER' | 'ADMIN', - isVerified: user.user.emailVerified as boolean | undefined, - profile: user.user.profile as User['profile'], - } as User; - - set({ - user: transformedUser, - isAuthenticated: true, - isLoading: false, - }); - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : 'Login failed'; - set({ - error: errorMessage, - isLoading: false, - }); - get().setTokens(null, null); - throw error; - } - }, - - logout: async () => { - const currentState = get(); - - // Prevent multiple logout calls - if (currentState.isLoading) { - return; - } - - try { - set({ isLoading: true }); - - // Better Auth handles logout via its own API - // We just need to clear local state - // The actual logout is handled by authClient.signOut() in useAuthActions - - // Clear all auth data - get().clearAuth(); - set({ isLoading: false }); - } catch (error) { - set({ - error: error instanceof Error ? error.message : 'Logout failed', - isLoading: false, - }); - throw error; - } - }, - - refreshUser: async () => { - // Clear any existing timeout - if (refreshTimeout) { - clearTimeout(refreshTimeout); - } - - return new Promise((resolve, reject) => { - refreshTimeout = setTimeout(async () => { - try { - set({ isLoading: true, error: null }); - - // Fetch user data using cookie-based auth (Better Auth handles session) - const user = await getMe(); - - const transformedUser: User = { - id: user.user.id as string, - email: user.user.email as string, - name: user.user.name as string | null, - image: user.user.image as string | null, - username: user.user.username as string | null, - role: user.user.role as 'USER' | 'ADMIN', - isVerified: user.user.emailVerified as boolean | undefined, - profile: user.user.profile as User['profile'], - } as User; - - set({ - user: transformedUser, - isAuthenticated: true, - isLoading: false, - }); - resolve(); - } catch (error) { - set({ - error: - error instanceof Error - ? error.message - : 'Failed to refresh user', - isLoading: false, - }); - - // If refresh fails, clear auth data - if ( - error instanceof Error && - (error.message.includes('401') || - error.message.includes('expired')) - ) { - get().clearAuth(); - } - - reject(error); - } - }, 300); // 300ms debounce - }); - }, - - clearAuth: () => { - // Clear state first - set({ - user: null, - accessToken: null, - refreshToken: null, - isAuthenticated: false, - isLoading: false, - error: null, - }); - - // Clear cookies on client side - if (typeof window !== 'undefined') { - Cookies.remove('accessToken'); - Cookies.remove('refreshToken'); - - // Clear persisted storage after state update - // Use setTimeout to ensure persist middleware has processed the state change - setTimeout(() => { - const storage = getStorage(); - storage.removeItem('auth-storage'); - }, 0); - } - }, - - updateUser: updates => { - const { user } = get(); - if (user) { - set({ user: { ...user, ...updates } }); - } - }, - - syncWithSession: async sessionUser => { - if (sessionUser && sessionUser.id && sessionUser.email) { - try { - // Always fetch fresh user data from API using cookie-based auth - // Better Auth handles authentication via cookies automatically - const user = await getMe(); - - const transformedUser: User = { - id: user.user.id as string, - email: user.user.email as string, - name: user.user.name as string | null, - image: user.user.image as string | null, - username: user.user.username as string | null, - role: user.user.role as 'USER' | 'ADMIN', - isVerified: user.user.emailVerified as boolean | undefined, - profile: user.user.profile as User['profile'], - } as User; - - set({ - user: transformedUser, - isAuthenticated: true, - isLoading: false, - }); - } catch { - // Fallback to session user data if API call fails - // This ensures we still have user data even if API is unavailable - const fallbackUser: User = { - id: sessionUser.id, - email: sessionUser.email, - name: sessionUser.name || null, - image: sessionUser.image || null, - username: sessionUser.username || null, - role: (sessionUser.role as 'USER' | 'ADMIN') || 'USER', - }; - - set({ - user: fallbackUser, - isAuthenticated: true, - isLoading: false, - }); - } - } - }, - }), - { - name: 'auth-storage', - storage: createJSONStorage(() => getStorage()), - partialize: state => ({ - user: state.user, - accessToken: state.accessToken, - refreshToken: state.refreshToken, - isAuthenticated: state.isAuthenticated, - }), - onRehydrateStorage: () => state => { - // Rehydrate cookies from localStorage on app start (client side only) - if (typeof window !== 'undefined' && state?.accessToken) { - // Check if access token is expired on app startup - if (isTokenExpired(state.accessToken)) { - // Clear expired tokens - state.accessToken = null; - state.refreshToken = null; - state.user = null; - state.isAuthenticated = false; - Cookies.remove('accessToken'); - Cookies.remove('refreshToken'); - return; - } - - Cookies.set('accessToken', state.accessToken); - } - if (typeof window !== 'undefined' && state?.refreshToken) { - // Check if refresh token is also expired - if (isTokenExpired(state.refreshToken)) { - state.refreshToken = null; - Cookies.remove('refreshToken'); - } else { - Cookies.set('refreshToken', state.refreshToken); - } - } - - // Initialize auth state from cookies if we have tokens but no user - if ( - typeof window !== 'undefined' && - state?.accessToken && - !state?.user && - !isTokenExpired(state.accessToken) - ) { - // This will trigger a refresh of user data - const timeoutId = setTimeout(() => { - const store = useAuthStore.getState(); - if ( - store.accessToken && - !store.user && - !isTokenExpired(store.accessToken) - ) { - store.refreshUser().catch(() => { - // Silently handle refresh failure - }); - } - }, 100); - - // Store timeout ID for potential cleanup - if (typeof window !== 'undefined') { - ( - window as unknown as { - __authTimeoutId?: ReturnType; - } - ).__authTimeoutId = timeoutId; - } - } - }, - } - ) -); diff --git a/lib/utils/hackathon-escrow.ts b/lib/utils/hackathon-escrow.ts index c6675dba5..b7445bf37 100644 --- a/lib/utils/hackathon-escrow.ts +++ b/lib/utils/hackathon-escrow.ts @@ -1,25 +1,24 @@ -import { InitializeMultiReleaseEscrowPayload } from '@trustless-work/escrow'; import { RewardsFormData } from '@/components/organization/hackathons/new/tabs/schemas/rewardsSchema'; +import type { WinnerDistributionEntry } from '@/features/hackathons'; /** - * USDC trustline address for Stellar network + * Hackathon prize-pool math helpers. + * + * The escrow itself is now created through the boundless-events contract via + * `lib/api/hackathons/escrow.ts` + `features/hackathons/api/use-escrow.ts`. + * The TrustlessWork payload builders that used to live here are gone; what + * remains is the pure prize-pool / fee math the configure + publish flows use. */ -const USDC_TRUSTLINE_ADDRESS = - 'GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5'; /** - * Platform fee percentage (4% as per plan) + * Platform fee percentage. Mirrors the boundless-events contract's default + * fee_bps (250 bps = 2.5%), charged on top of the prize budget at publish (the + * owner is debited budget + fee). Keep in sync with the contract default. */ -export const PLATFORM_FEE = 4; - -/** - * Minimal amount for placeholder milestone (1 USDC = 10000000 with 7 decimals) - */ -const PLACEHOLDER_MILESTONE_AMOUNT = 1; +export const PLATFORM_FEE = 2.5; /** * Boundless platform wallet address - * This address will act as approver and release signer to reduce user transactions. * Must be set via NEXT_PUBLIC_BOUNDLESS_PLATFORM_ADDRESS in production. */ const BOUNDLESS_PLATFORM_ADDRESS = @@ -94,10 +93,9 @@ export const extractRankFromPosition = ( }; /** - * Calculate total prize pool amount from prize tiers - * Converts prize amounts to Stellar format (7 decimals) + * Calculate total prize pool amount from prize tiers (token-native units). * @param rewards - Rewards form data containing prize tiers - * @returns Total amount in Stellar format (with 7 decimals) + * @returns Total prize amount */ export const calculateTotalPrizeAmount = (rewards: RewardsFormData): number => { if (!rewards.prizeTiers || rewards.prizeTiers.length === 0) { @@ -111,109 +109,6 @@ export const calculateTotalPrizeAmount = (rewards: RewardsFormData): number => { }, 0); }; -/** - * Create a placeholder milestone for initial escrow - * This milestone will be replaced/added to with winner milestones after judging - * @param organizationAddress - Organization wallet address (receiver) - * @returns Milestone payload for placeholder - */ -export const createPlaceholderMilestone = ( - organizationAddress: string -): { description: string; amount: number; receiver: string } => { - return { - description: 'Hackathon Prize Pool - Placeholder', - amount: PLACEHOLDER_MILESTONE_AMOUNT, // 1 USDC - receiver: organizationAddress, - }; -}; - -/** - * Create winner milestone payload (used after judging) - * @param position - Prize position (e.g., "1st Place") - * @param amount - Prize amount in Stellar format - * @param winnerAddress - Winner's wallet address - * @returns Milestone payload for winner - */ -export const createWinnerMilestone = ( - position: string, - amount: number, - winnerAddress: string -): { description: string; amount: number; receiver: string } => { - return { - description: `${position} Prize`, - amount: amount, - receiver: winnerAddress, - }; -}; - -/** - * Create hackathon escrow payload with placeholder milestone - * @param params - Parameters for escrow creation - * @returns Escrow payload ready for Trustless Work - */ -export const createHackathonEscrow = (params: { - signer: string; - organizationAddress: string; - hackathonTitle: string; - hackathonDescription: string; - rewards: RewardsFormData; - engagementId?: string; -}): InitializeMultiReleaseEscrowPayload => { - const { - signer, - organizationAddress, - hackathonTitle, - hackathonDescription, - engagementId, - } = params; - - // Validate Boundless platform address is configured - if (!BOUNDLESS_PLATFORM_ADDRESS) { - throw new Error( - 'Boundless platform address not configured. Please set NEXT_PUBLIC_BOUNDLESS_PLATFORM_ADDRESS environment variable.' - ); - } - - // Create placeholder milestone - const placeholderMilestone = createPlaceholderMilestone( - BOUNDLESS_PLATFORM_ADDRESS - ); - - // Generate engagement ID if not provided - const finalEngagementId = - engagementId || - `hackathon-${Date.now()}-${Math.random().toString(36).substring(7)}`; - - return { - signer, - engagementId: finalEngagementId, - title: hackathonTitle, - description: hackathonDescription, - platformFee: PLATFORM_FEE, - trustline: { - address: USDC_TRUSTLINE_ADDRESS, - symbol: 'USDC', - }, - roles: { - // Service Provider = Organizer (can update milestones, add evidence, raise disputes) - serviceProvider: organizationAddress, - - // Approver = Boundless (validates milestones, approves work) - approver: BOUNDLESS_PLATFORM_ADDRESS, - - // Release Signer = Boundless (triggers fund release after approval) - releaseSigner: BOUNDLESS_PLATFORM_ADDRESS, - - // Platform Address = Boundless (collects platform fees) - platformAddress: BOUNDLESS_PLATFORM_ADDRESS, - - // Dispute Resolver = Boundless (resolves conflicts) - disputeResolver: BOUNDLESS_PLATFORM_ADDRESS, - }, - milestones: [placeholderMilestone], - }; -}; - /** * Calculate platform fee amount from total prize pool * @param totalPrizePool - Total prize pool amount @@ -257,3 +152,66 @@ export const getTotalPrizePoolForFunding = ( ): number => { return calculateTotalFundingWithPlatformFee(rewards); }; + +/** + * Derive the on-chain winner distribution ([{position, percent}], summing to + * exactly 100) from the configured OVERALL prize tiers, proportional to each + * tier's prize amount. + * + * The events contract requires unique positions, each percent >= 1, and the + * set summing to exactly 100. We give every tier a base of 1 percent then + * distribute the remaining points by amount-weighted largest-remainder, so the + * totals are always exact regardless of rounding. Returns undefined when there + * are no fundable overall tiers (caller lets the backend default to 100% @ #1). + */ +export const buildWinnerDistribution = ( + rewards: RewardsFormData +): WinnerDistributionEntry[] | undefined => { + // Only OVERALL tiers fund the on-chain winner_distribution; TRACK prizes are + // a separate concept and not part of the events-contract payout split. + const overall = (rewards.prizeTiers ?? []).filter(t => t.kind !== 'TRACK'); + + // Merge by position (defensive: duplicate places sum their amounts). + const byPosition = new Map(); + for (const tier of overall) { + const position = extractRankFromPosition(tier.place); + const amount = parseFloat(tier.prizeAmount || '0'); + if (position == null || position < 1 || !(amount > 0)) continue; + byPosition.set(position, (byPosition.get(position) ?? 0) + amount); + } + + const entries = [...byPosition.entries()] + .map(([position, amount]) => ({ position, amount })) + .sort((a, b) => a.position - b.position); + + if (entries.length === 0) return undefined; + + const total = entries.reduce((sum, e) => sum + e.amount, 0); + if (!(total > 0)) return undefined; + + // Single tier (or everything to one position) -> 100% there. + if (entries.length === 1) { + return [{ position: entries[0].position, percent: 100 }]; + } + + const n = entries.length; + const remaining = 100 - n; // points to spread on top of the base 1-each + const spread = entries.map(e => { + const exact = (e.amount / total) * remaining; + const floor = Math.floor(exact); + return { position: e.position, extra: floor, remainder: exact - floor }; + }); + + let used = spread.reduce((sum, s) => sum + s.extra, 0); + const byRemainder = [...spread].sort((a, b) => b.remainder - a.remainder); + let i = 0; + while (used < remaining && byRemainder.length > 0) { + byRemainder[i % byRemainder.length].extra += 1; + used += 1; + i += 1; + } + + return spread + .map(s => ({ position: s.position, percent: 1 + s.extra })) + .sort((a, b) => a.position - b.position); +}; diff --git a/lib/utils/hackathon-form-transforms.ts b/lib/utils/hackathon-form-transforms.ts index 52c2e2e32..6d8c1b126 100644 --- a/lib/utils/hackathon-form-transforms.ts +++ b/lib/utils/hackathon-form-transforms.ts @@ -1,12 +1,4 @@ -import { - HackathonCategory, - ParticipantType, - VenueType, - type CreateDraftRequest, - type PublishHackathonRequest, - type HackathonDraft, - type HackathonResources, -} from '@/lib/api/hackathons'; +import type { HackathonDraft } from '@/features/hackathons'; import { InfoFormData } from '@/components/organization/hackathons/new/tabs/schemas/infoSchema'; import { TimelineFormData } from '@/components/organization/hackathons/new/tabs/schemas/timelineSchema'; import { ParticipantFormData } from '@/components/organization/hackathons/new/tabs/schemas/participantSchema'; @@ -15,146 +7,18 @@ import { ResourcesFormData } from '@/components/organization/hackathons/new/tabs import { JudgingFormData } from '@/components/organization/hackathons/new/tabs/schemas/judgingSchema'; import { CollaborationFormData } from '@/components/organization/hackathons/new/tabs/schemas/collaborationSchema'; -export const transformToApiFormat = (stepData: { - information?: InfoFormData; - timeline?: TimelineFormData; - participation?: ParticipantFormData; - rewards?: RewardsFormData; - resources?: ResourcesFormData; - judging?: JudgingFormData; - collaboration?: CollaborationFormData; -}): CreateDraftRequest | PublishHackathonRequest => { - const info = stepData.information; - const timeline = stepData.timeline; - const participation = stepData.participation; - const rewards = stepData.rewards; - const resources = stepData.resources; - const judging = stepData.judging; - const collaboration = stepData.collaboration; - - // Convert form categories array to API format - const categoriesArray: HackathonCategory[] = Array.isArray(info?.categories) - ? (info.categories as HackathonCategory[]).filter(cat => - Object.values(HackathonCategory).includes(cat) - ) - : []; - - return { - information: { - name: info?.name || '', - banner: info?.banner || '', - description: info?.description || '', - tagline: info?.tagline || '', - slug: info?.slug || '', - // Send categories array (new format, recommended) - categories: - categoriesArray.length > 0 - ? categoriesArray - : [HackathonCategory.OTHER], - venue: { - type: (info?.venueType as VenueType) || VenueType.VIRTUAL, - country: info?.country, - state: info?.state, - city: info?.city, - venueName: info?.venueName, - venueAddress: info?.venueAddress, - }, - }, - timeline: { - startDate: timeline?.startDate?.toISOString() || '', - submissionDeadline: timeline?.submissionDeadline?.toISOString() || '', - timezone: timeline?.timezone || 'UTC', - ...(timeline?.registrationDeadline - ? { registrationDeadline: timeline.registrationDeadline.toISOString() } - : {}), - ...(timeline?.judgingDeadline - ? { judgingDeadline: timeline.judgingDeadline.toISOString() } - : {}), - phases: timeline?.phases?.map(phase => ({ - name: phase.name, - startDate: phase.startDate.toISOString(), - endDate: phase.endDate.toISOString(), - description: phase.description, - })), - }, - participation: { - participantType: - (participation?.participantType as ParticipantType) || - ParticipantType.INDIVIDUAL, - teamMin: participation?.teamMin, - teamMax: participation?.teamMax, - ...(participation?.maxParticipants - ? { maxParticipants: participation.maxParticipants } - : {}), - submissionRequirements: { - requireGithub: participation?.require_github, - requireDemoVideo: participation?.require_demo_video, - requireOtherLinks: participation?.require_other_links, - }, - tabVisibility: { - detailsTab: participation?.detailsTab, - participantsTab: participation?.participantsTab, - resourcesTab: participation?.resourcesTab, - submissionTab: participation?.submissionTab, - announcementsTab: participation?.announcementsTab, - discussionTab: participation?.discussionTab, - winnersTab: participation?.winnersTab, - sponsorsTab: participation?.sponsorsTab, - joinATeamTab: participation?.joinATeamTab, - rulesTab: participation?.rulesTab, - }, - }, - rewards: { - prizeTiers: - rewards?.prizeTiers?.map(tier => ({ - place: tier.place, - prizeAmount: tier.prizeAmount || '0', - currency: tier.currency || 'USDC', - description: tier.description || '', - passMark: tier.passMark || 0, - })) || [], - }, - resources: { - resources: - resources?.resources?.map(resource => ({ - link: resource.link || undefined, - description: resource.description, - fileUrl: resource.file?.url || undefined, - fileName: resource.file?.name || undefined, - })) || [], - } as HackathonResources, - judging: { - criteria: - judging?.criteria?.map(criterion => ({ - // Preserve the server-issued id where present so the UI keys - // stay stable across edits. - id: criterion.id ?? criterion.name ?? '', - title: criterion.name, - weight: criterion.weight, - description: criterion.description, - })) || [], - }, - collaboration: { - contactEmail: collaboration?.contactEmail || '', - telegram: collaboration?.telegram, - discord: collaboration?.discord, - socialLinks: - collaboration?.socialLinks?.filter( - link => link && link.trim() !== '' - ) || [], - sponsorsPartners: - collaboration?.sponsorsPartners - ?.filter(sp => sp.name) // Filter out sponsors without names - .map(sp => ({ - id: sp.id, - name: sp.name || '', - logo: sp.logo || '', - link: sp.link || '', - })) || [], - }, - }; -}; - +/** + * Hydrate the wizard form state from a saved draft. + * + * The backend persists and returns each section FLAT (the generated + * HackathonDraftData shape): `information.venueType`, `participation.require_*` + * and `participation.*Tab`, `judging.criteria[].name`, `collaboration + * .sponsorsPartners[].{name,logo,link}`. Read those fields directly. (An earlier + * version read a nested shape - `venue.type`, `submissionRequirements.*`, + * `tabVisibility.*` - that the response never carried, so on resume venue + * fields, submission requirements and tab visibility silently reset to + * defaults.) + */ export const transformFromApiFormat = (draft: HackathonDraft) => { const info = draft.data?.information; const timeline = draft.data?.timeline; @@ -164,7 +28,6 @@ export const transformFromApiFormat = (draft: HackathonDraft) => { const judging = draft.data?.judging; const collaboration = draft.data?.collaboration; - // Handle categories array const categoriesArray: string[] = info?.categories ? info.categories : []; return { @@ -174,12 +37,12 @@ export const transformFromApiFormat = (draft: HackathonDraft) => { description: info?.description || '', tagline: info?.tagline || '', categories: categoriesArray, - venueType: info?.venue?.type || 'virtual', - country: info?.venue?.country || '', - state: info?.venue?.state || '', - city: info?.venue?.city || '', - venueName: info?.venue?.venueName || '', - venueAddress: info?.venue?.venueAddress || '', + venueType: info?.venueType || 'virtual', + country: info?.country || '', + state: info?.state || '', + city: info?.city || '', + venueName: info?.venueName || '', + venueAddress: info?.venueAddress || '', } as InfoFormData, timeline: { startDate: timeline?.startDate ? new Date(timeline.startDate) : undefined, @@ -206,22 +69,21 @@ export const transformFromApiFormat = (draft: HackathonDraft) => { teamMin: participation?.teamMin, teamMax: participation?.teamMax, maxParticipants: participation?.maxParticipants, - require_github: - participation?.submissionRequirements?.requireGithub || false, - require_demo_video: - participation?.submissionRequirements?.requireDemoVideo || false, - require_other_links: - participation?.submissionRequirements?.requireOtherLinks || false, - detailsTab: participation?.tabVisibility?.detailsTab || true, - participantsTab: participation?.tabVisibility?.participantsTab || true, - resourcesTab: participation?.tabVisibility?.resourcesTab || true, - submissionTab: participation?.tabVisibility?.submissionTab || true, - announcementsTab: participation?.tabVisibility?.announcementsTab || true, - discussionTab: participation?.tabVisibility?.discussionTab || true, - winnersTab: participation?.tabVisibility?.winnersTab || true, - sponsorsTab: participation?.tabVisibility?.sponsorsTab || true, - joinATeamTab: participation?.tabVisibility?.joinATeamTab || true, - rulesTab: participation?.tabVisibility?.rulesTab || true, + require_github: participation?.require_github ?? false, + require_demo_video: participation?.require_demo_video ?? false, + require_other_links: participation?.require_other_links ?? false, + // `?? true` (not `|| true`): preserve a tab the organizer explicitly + // disabled (false) instead of forcing it back on. + detailsTab: participation?.detailsTab ?? true, + participantsTab: participation?.participantsTab ?? true, + resourcesTab: participation?.resourcesTab ?? true, + submissionTab: participation?.submissionTab ?? true, + announcementsTab: participation?.announcementsTab ?? true, + discussionTab: participation?.discussionTab ?? true, + winnersTab: participation?.winnersTab ?? true, + sponsorsTab: participation?.sponsorsTab ?? true, + joinATeamTab: participation?.joinATeamTab ?? true, + rulesTab: participation?.rulesTab ?? true, } as ParticipantFormData, rewards: { prizeTiers: @@ -247,7 +109,7 @@ export const transformFromApiFormat = (draft: HackathonDraft) => { resources: { resources: resources?.resources?.map((resource, index) => ({ - id: `resource-${index}`, + id: resource.id ?? `resource-${index}`, link: resource.link || '', description: resource.description || '', file: resource.file?.url @@ -260,21 +122,12 @@ export const transformFromApiFormat = (draft: HackathonDraft) => { } as ResourcesFormData, judging: { criteria: - judging?.criteria?.map((criterion, index) => { - const c = criterion as { - title?: string; - name?: string; - weight?: number; - description?: string; - }; - const titleOrName = (c.title ?? c.name ?? '').trim(); - return { - id: `criterion-${index}`, - name: titleOrName || `Criterion ${index + 1}`, - weight: typeof criterion.weight === 'number' ? criterion.weight : 0, - description: criterion.description || '', - }; - }) || [], + judging?.criteria?.map((criterion, index) => ({ + id: criterion.id ?? `criterion-${index}`, + name: (criterion.name || '').trim() || `Criterion ${index + 1}`, + weight: typeof criterion.weight === 'number' ? criterion.weight : 0, + description: criterion.description || '', + })) || [], } as JudgingFormData, collaboration: { contactEmail: collaboration?.contactEmail || '', @@ -287,10 +140,10 @@ export const transformFromApiFormat = (draft: HackathonDraft) => { sp.id || (typeof crypto !== 'undefined' && 'randomUUID' in crypto ? crypto.randomUUID() - : `sponsor-${Date.now()}-${i}`), - name: sp.name ?? sp.sponsorName ?? '', - logo: sp.logo ?? sp.sponsorLogo ?? '', - link: sp.link ?? sp.partnerLink ?? '', + : `sponsor-${i}`), + name: sp.name ?? '', + logo: sp.logo ?? '', + link: sp.link ?? '', })) || [], } as CollaborationFormData, }; diff --git a/lib/utils/hackathon-step-validation.ts b/lib/utils/hackathon-step-validation.ts index 20e7d78d5..060a2a03d 100644 --- a/lib/utils/hackathon-step-validation.ts +++ b/lib/utils/hackathon-step-validation.ts @@ -1,5 +1,4 @@ import type { StepKey } from '@/components/organization/hackathons/new/constants'; -import type { HackathonDraft } from '@/lib/api/hackathons'; import type { InfoFormData } from '@/components/organization/hackathons/new/tabs/schemas/infoSchema'; import type { TimelineFormData } from '@/components/organization/hackathons/new/tabs/schemas/timelineSchema'; import type { ParticipantFormData } from '@/components/organization/hackathons/new/tabs/schemas/participantSchema'; @@ -19,61 +18,7 @@ interface StepData { } /** - * Checks if a step exists in the original draft API response - * This is more reliable than checking transformed data since transformFromApiFormat - * always returns objects with default values - */ -export const isStepSavedInDraft = ( - stepKey: StepKey, - draft: HackathonDraft -): boolean => { - switch (stepKey) { - case 'information': - return !!( - draft.data.information && - draft.data.information.name && - draft.data.information.banner && - draft.data.information.description - ); - case 'timeline': - return !!( - draft.data.timeline && - draft.data.timeline.startDate && - draft.data.timeline.submissionDeadline - ); - case 'participation': - return !!( - draft.data.participation && draft.data.participation.participantType - ); - case 'rewards': - return !!( - draft.data.rewards && - draft.data.rewards.prizeTiers && - draft.data.rewards.prizeTiers.length > 0 - ); - case 'resources': - // Resources are optional, so return true if the field exists (even if empty) - return draft.data.resources !== undefined; - case 'judging': - return !!( - draft.data.judging && - draft.data.judging.criteria && - draft.data.judging.criteria.length > 0 - ); - case 'collaboration': - return !!( - draft.data.collaboration && - draft.data.collaboration.contactEmail && - draft.data.collaboration.contactEmail.trim() !== '' - ); - default: - return false; - } -}; - -/** - * Checks if a step has meaningful data in the transformed form data - * This is a fallback when we don't have access to the original draft + * Checks if a step has meaningful data in the transformed form data. */ export const isStepDataValid = ( stepKey: StepKey, @@ -105,7 +50,6 @@ export const isStepDataValid = ( // Participation always has a default participantType from transformFromApiFormat. // For team types, we can check if team constraints exist. // For individual type, we check if participantType exists (it always will from transform). - // Note: This is a limitation - for accurate checking, use isStepSavedInDraft with the original draft. if ( participation.participantType === 'team' || participation.participantType === 'team_or_individual' diff --git a/lib/utils/hackathon-winner-distribution.ts b/lib/utils/hackathon-winner-distribution.ts deleted file mode 100644 index 91ddb1c98..000000000 --- a/lib/utils/hackathon-winner-distribution.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { MultiReleaseEscrow } from '@trustless-work/escrow'; -import { createWinnerMilestone } from './hackathon-escrow'; - -/** - * Winner data structure - */ -export interface Winner { - position: string; - amount: number; - walletAddress: string; -} - -/** - * Validation result for escrow update - */ -export interface EscrowValidationResult { - isValid: boolean; - errors: string[]; -} - -/** - * Prepare winner milestones from winner data - * Maps winners to milestone payloads for Update Escrow API - * @param winners - Array of winners with position, amount, and wallet address - * @returns Array of milestone payloads - */ -export const prepareWinnerMilestones = ( - winners: Winner[] -): Array<{ description: string; amount: number; receiver: string }> => { - if (!winners || winners.length === 0) { - return []; - } - - return winners.map(winner => { - // Validate winner data - if (!winner.walletAddress || !winner.walletAddress.trim()) { - throw new Error(`Invalid wallet address for ${winner.position}`); - } - - if (!winner.amount || winner.amount <= 0) { - throw new Error(`Invalid amount for ${winner.position}`); - } - - if (!winner.position || !winner.position.trim()) { - throw new Error('Position is required for winner'); - } - - return createWinnerMilestone( - winner.position, - winner.amount, - winner.walletAddress.trim() - ); - }); -}; - -// /** -// * Validate Stellar address format -// * @param address - Stellar address to validate -// * @returns true if valid, false otherwise -// */ -// const isValidStellarAddress = (address: string): boolean => { -// // Stellar addresses start with G and are 56 characters long -// const stellarAddressRegex = /^G[ABCDEFGHJKLMNPQRSTUVWXYZ23456789]{55}$/; -// return stellarAddressRegex.test(address); -// }; - -/** - * Validate escrow can be updated - * Checks escrow state before allowing milestone addition - * @param escrow - Current escrow data - * @returns Validation result with errors if any - */ -export const validateEscrowCanBeUpdated = ( - escrow: MultiReleaseEscrow | null -): EscrowValidationResult => { - const errors: string[] = []; - - if (!escrow) { - errors.push('Escrow not found'); - return { isValid: false, errors }; - } - - // Check if escrow is funded - if (!escrow.balance || escrow.balance === 0) { - errors.push('Escrow is not funded. Please fund the escrow first.'); - } - - // Check if any milestones are approved - const hasApprovedMilestones = - escrow.milestones?.some(milestone => milestone.flags?.approved === true) || - false; - - if (hasApprovedMilestones) { - errors.push( - 'Cannot update escrow: Some milestones are already approved. Escrow cannot be updated after milestones are approved.' - ); - } - - // Check if escrow is in dispute (flags may not exist on MultiReleaseEscrow type) - interface EscrowWithFlags extends MultiReleaseEscrow { - flags?: { - disputed?: boolean; - }; - } - const escrowWithFlags = escrow as EscrowWithFlags; - if (escrowWithFlags.flags?.disputed === true) { - errors.push( - 'Cannot update escrow: Escrow is in dispute. Please resolve the dispute first.' - ); - } - - return { - isValid: errors.length === 0, - errors, - }; -}; - -/** - * Validate winner data - * @param winners - Array of winners to validate - * @returns Validation result with errors if any - */ -export const validateWinners = (winners: Winner[]): EscrowValidationResult => { - const errors: string[] = []; - - if (!winners || winners.length === 0) { - errors.push('At least one winner is required'); - return { isValid: false, errors }; - } - - // Check for duplicate wallet addresses - const addresses = winners.map(w => w.walletAddress.trim().toLowerCase()); - const uniqueAddresses = new Set(addresses); - if (addresses.length !== uniqueAddresses.size) { - errors.push( - 'Duplicate wallet addresses found. Each winner must have a unique address.' - ); - } - - // Validate each winner - winners.forEach((winner, index) => { - if (!winner.position || !winner.position.trim()) { - errors.push(`Winner ${index + 1}: Position is required`); - } - - if (!winner.amount || winner.amount <= 0) { - errors.push(`Winner ${index + 1}: Amount must be greater than zero`); - } - - // if (!winner.walletAddress || !winner.walletAddress.trim()) { - // errors.push(`Winner ${index + 1}: Wallet address is required`); - // } else if (!isValidStellarAddress(winner.walletAddress.trim())) { - // errors.push( - // `Winner ${index + 1}: Invalid Stellar address format. Address must start with G and be 56 characters long.` - // ); - // } - }); - - return { - isValid: errors.length === 0, - errors, - }; -}; diff --git a/lib/utils/prize-tier-matcher.ts b/lib/utils/prize-tier-matcher.ts deleted file mode 100644 index 17fdcd8e4..000000000 --- a/lib/utils/prize-tier-matcher.ts +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Prize Tier Position Matcher - * - * Shared utility for matching prize tier positions with ranks. - * This can be used by both frontend and backend to ensure consistent validation. - * - * Backend Implementation Guide: - * Copy this function to your backend codebase and use it when validating - * prize tiers against winner ranks in the createWinnerMilestones endpoint. - */ - -/** - * Extract rank number from position string - * Handles formats like "1st Place", "2nd", "3", "Third Place", etc. - * - * @param position - Position string (e.g., "2nd Place", "2", "2nd") - * @returns Rank number or null if not found - * - * @example - * extractRankFromPosition("2nd Place") // returns 2 - * extractRankFromPosition("2nd") // returns 2 - * extractRankFromPosition("2") // returns 2 - * extractRankFromPosition("Second Place") // returns 2 - */ -export function extractRankFromPosition( - position: string | undefined | null -): number | null { - if (!position) return null; - - // Remove "Place" and trim, convert to lowercase - const cleaned = position.toLowerCase().replace(/place/g, '').trim(); - - // Try to extract number directly (e.g., "2", "2nd", "2nd place") - const numberMatch = cleaned.match(/^(\d+)/); - if (numberMatch) { - return parseInt(numberMatch[1], 10); - } - - // Handle ordinal formats: "1st", "2nd", "3rd", "4th", etc. - const ordinalMatch = cleaned.match(/^(\d+)(st|nd|rd|th)/); - if (ordinalMatch) { - return parseInt(ordinalMatch[1], 10); - } - - // Handle word formats: "first", "second", "third", etc. - const wordMap: Record = { - first: 1, - second: 2, - third: 3, - fourth: 4, - fifth: 5, - sixth: 6, - seventh: 7, - eighth: 8, - ninth: 9, - tenth: 10, - eleventh: 11, - twelfth: 12, - thirteenth: 13, - fourteenth: 14, - fifteenth: 15, - }; - - for (const [word, num] of Object.entries(wordMap)) { - if (cleaned.includes(word)) { - return num; - } - } - - return null; -} - -/** - * Check if a prize tier matches a given rank - * - * @param prizeTier - Prize tier object with position field - * @param rank - Rank number to match - * @returns true if the prize tier position matches the rank - * - * @example - * const tier = { position: "2nd Place", amount: 5000, currency: "USDC" }; - * matchesRank(tier, 2) // returns true - * matchesRank(tier, 1) // returns false - */ -export function matchesRank( - prizeTier: { position: string }, - rank: number -): boolean { - const tierRank = extractRankFromPosition(prizeTier.position); - return tierRank === rank; -} - -/** - * Find prize tier for a given rank - * - * @param prizeTiers - Array of prize tiers - * @param rank - Rank number to find - * @returns Prize tier that matches the rank, or null if not found - * - * @example - * const tiers = [ - * { position: "1st Place", amount: 10000 }, - * { position: "2nd Place", amount: 5000 } - * ]; - * findPrizeTierForRank(tiers, 2) // returns { position: "2nd Place", amount: 5000 } - */ -export function findPrizeTierForRank( - prizeTiers: T[], - rank: number -): T | null { - return prizeTiers.find(tier => matchesRank(tier, rank)) || null; -} - -/** - * Validate that prize tiers exist for all given ranks - * - * @param prizeTiers - Array of prize tiers - * @param ranks - Array of rank numbers to validate - * @returns Object with validation result and missing ranks - * - * @example - * const tiers = [ - * { position: "1st Place", amount: 10000 }, - * { position: "2nd Place", amount: 5000 } - * ]; - * validatePrizeTiersForRanks(tiers, [1, 2, 3]) - * // returns { valid: false, missingRanks: [3] } - */ -export function validatePrizeTiersForRanks( - prizeTiers: Array<{ position: string }>, - ranks: number[] -): { valid: boolean; missingRanks: number[] } { - const missingRanks: number[] = []; - - ranks.forEach(rank => { - const hasTier = prizeTiers.some(tier => matchesRank(tier, rank)); - if (!hasTier) { - missingRanks.push(rank); - } - }); - - return { - valid: missingRanks.length === 0, - missingRanks: [...new Set(missingRanks)].sort((a, b) => a - b), - }; -} diff --git a/lib/utils/publish-op-storage.ts b/lib/utils/publish-op-storage.ts new file mode 100644 index 000000000..897a8398d --- /dev/null +++ b/lib/utils/publish-op-storage.ts @@ -0,0 +1,39 @@ +/** + * Per-hackathon persistence of the in-flight publish escrow op id. + * + * Publishing is async: the backend moves the hackathon to DRAFT_AWAITING_FUNDING + * and a reconciliation worker settles the op later. Persisting the op row id + * lets the webapp resume polling after a reload / navigation instead of + * re-issuing publish (which the backend rejects once the row leaves DRAFT). + */ +const PUBLISH_OP_STORAGE_PREFIX = 'boundless_publish_op_'; + +const storageKey = (hackathonId: string) => + `${PUBLISH_OP_STORAGE_PREFIX}${hackathonId}`; + +export function readPublishOpId(hackathonId: string): string | null { + if (typeof window === 'undefined') return null; + try { + return sessionStorage.getItem(storageKey(hackathonId)); + } catch { + return null; + } +} + +export function persistPublishOpId(hackathonId: string, opRowId: string): void { + if (typeof window === 'undefined') return; + try { + sessionStorage.setItem(storageKey(hackathonId), opRowId); + } catch { + // ignore + } +} + +export function clearPublishOpId(hackathonId: string): void { + if (typeof window === 'undefined') return; + try { + sessionStorage.removeItem(storageKey(hackathonId)); + } catch { + // ignore + } +} diff --git a/lib/wallet/wallet-kit.ts b/lib/wallet/wallet-kit.ts new file mode 100644 index 000000000..83eb0d97a --- /dev/null +++ b/lib/wallet/wallet-kit.ts @@ -0,0 +1,114 @@ +/** + * Stellar Wallets Kit — connected-wallet signer for the EXTERNAL funding path. + * + * Replaces the Freighter-only signer with the Kit's multi-wallet support + * (Freighter, xBull, Albedo, Lobstr, Hana) and its built-in connect modal. + * + * The Kit (v2 static API) is browser-only and touches `window` at import time, + * so everything is loaded through a lazy dynamic import and initialized once on + * first use. Importing this module on the server is safe; nothing runs until a + * function is called in the browser. + */ +import { getCurrentNetwork, getNetworkPassphrase } from '@/lib/wallet-utils'; +import type { SignXdrFn } from '@/features/hackathons'; + +type KitClass = + typeof import('@creit.tech/stellar-wallets-kit').StellarWalletsKit; + +let kitRef: KitClass | null = null; +let initPromise: Promise | null = null; + +/** Initialize the Kit exactly once (idempotent across concurrent callers). */ +function initKit(): Promise { + if (!initPromise) { + initPromise = (async () => { + const [mod, freighter, xbull, albedo, lobstr, hana] = await Promise.all([ + import('@creit.tech/stellar-wallets-kit'), + import('@creit.tech/stellar-wallets-kit/modules/freighter'), + import('@creit.tech/stellar-wallets-kit/modules/xbull'), + import('@creit.tech/stellar-wallets-kit/modules/albedo'), + import('@creit.tech/stellar-wallets-kit/modules/lobstr'), + import('@creit.tech/stellar-wallets-kit/modules/hana'), + ]); + mod.StellarWalletsKit.init({ + network: + getCurrentNetwork() === 'public' + ? mod.Networks.PUBLIC + : mod.Networks.TESTNET, + modules: [ + new freighter.FreighterModule(), + new xbull.xBullModule(), + new albedo.AlbedoModule(), + new lobstr.LobstrModule(), + new hana.HanaModule(), + ], + }); + kitRef = mod.StellarWalletsKit; + })(); + } + return initPromise; +} + +async function getKit(): Promise { + await initKit(); + if (!kitRef) { + throw new Error('Wallet kit failed to initialize.'); + } + return kitRef; +} + +export interface ConnectedWallet { + address: string; +} + +/** Open the Kit's wallet picker; resolves with the connected address. */ +export async function connectWallet(): Promise { + const kit = await getKit(); + const { address } = await kit.authModal(); + return { address }; +} + +/** The currently connected address, or null if none is selected yet. */ +export async function getConnectedAddress(): Promise { + const kit = await getKit(); + try { + const { address } = await kit.getAddress(); + return address || null; + } catch { + return null; + } +} + +/** Forget the connected wallet. */ +export async function disconnectWallet(): Promise { + try { + const kit = await getKit(); + await kit.disconnect(); + } catch { + // Best-effort: nothing meaningful to do if disconnect fails. + } +} + +/** + * Sign an unsigned XDR with the connected wallet. Matches the EscrowOpRunner + * `SignXdrFn` so it can be handed straight to the runner for the EXTERNAL path. + * Prompts the wallet picker if nothing is connected yet. + */ +export const signXdrWithKit: SignXdrFn = async (unsignedXdr, signerHint) => { + const kit = await getKit(); + + let address: string | null = signerHint ?? (await getConnectedAddress()); + if (!address) { + const connected = await connectWallet(); + address = connected.address; + } + + const { signedTxXdr } = await kit.signTransaction(unsignedXdr, { + networkPassphrase: getNetworkPassphrase(), + address: address ?? undefined, + }); + if (!signedTxXdr) { + throw new Error('The wallet returned no signed transaction.'); + } + return signedTxXdr; +}; diff --git a/next.config.ts b/next.config.ts index 577f015f2..4ee1faba2 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,5 +1,4 @@ import type { NextConfig } from 'next'; -import { withSentryConfig } from '@sentry/nextjs'; const nextConfig: NextConfig = { outputFileTracingRoot: __dirname, @@ -108,10 +107,4 @@ const nextConfig: NextConfig = { }, }; -export default withSentryConfig(nextConfig, { - org: process.env.SENTRY_ORG ?? '', - project: process.env.SENTRY_PROJECT ?? '', - silent: !process.env.CI, - widenClientFileUpload: true, - authToken: process.env.SENTRY_AUTH_TOKEN, -}); +export default nextConfig; diff --git a/openapi.snapshot.json b/openapi.snapshot.json new file mode 100644 index 000000000..aaf4df91f --- /dev/null +++ b/openapi.snapshot.json @@ -0,0 +1,32611 @@ +{ + "openapi": "3.0.0", + "paths": { + "/api": { + "get": { + "operationId": "AppController_getHello", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["App"] + } + }, + "/api/notifications": { + "get": { + "operationId": "NotificationsController_getNotifications", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/notifications/unread-count": { + "get": { + "operationId": "NotificationsController_getUnreadCount", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/notifications/{id}/read": { + "put": { + "operationId": "NotificationsController_markAsRead", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/notifications/read-all": { + "put": { + "operationId": "NotificationsController_markAllAsRead", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/notifications/{id}": { + "delete": { + "operationId": "NotificationsController_deleteNotification", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/notifications/preferences": { + "get": { + "operationId": "NotificationsController_getPreferences", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + }, + "put": { + "operationId": "NotificationsController_updatePreferences", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationPreferencesDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/notifications/test": { + "post": { + "operationId": "NotificationsController_sendTestNotification", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/notifications/test-marketing-cron": { + "post": { + "operationId": "NotificationsController_triggerMarketingCron", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Notifications"] + } + }, + "/api/users/settings": { + "get": { + "operationId": "SettingsController_getSettings", + "parameters": [], + "responses": { + "200": { "description": "Settings retrieved successfully" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user settings", + "tags": ["users"] + } + }, + "/api/users/settings/notifications": { + "put": { + "operationId": "SettingsController_updateNotificationSettings", + "parameters": [], + "requestBody": { + "required": true, + "description": "Notification settings object", + "content": { "application/json": { "schema": { "type": "string" } } } + }, + "responses": { + "200": { + "description": "Notification settings updated successfully" + }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update notification settings", + "tags": ["users"] + } + }, + "/api/users/settings/privacy": { + "put": { + "operationId": "SettingsController_updatePrivacySettings", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePrivacySettingsDto" + } + } + } + }, + "responses": { + "200": { "description": "Privacy settings updated successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update privacy settings", + "tags": ["users"] + } + }, + "/api/users/settings/appearance": { + "put": { + "operationId": "SettingsController_updateAppearanceSettings", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAppearanceSettingsDto" + } + } + } + }, + "responses": { + "200": { "description": "Appearance settings updated successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update appearance settings", + "tags": ["users"] + } + }, + "/api/users/earnings/public": { + "get": { + "description": "Returns visibility-filtered earnings for the given username: total earned, breakdown by source, and completed activities only. No pending/claimable amounts or entityIds.", + "operationId": "EarningsController_getEarningsPublic", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "description": "Max activities to return (default 100)", + "schema": { "type": "number" } + }, + { + "name": "offset", + "required": false, + "in": "query", + "description": "Offset for activity pagination", + "schema": { "type": "number" } + }, + { + "name": "username", + "required": true, + "in": "query", + "description": "Username of the profile to fetch earnings for", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Public earnings retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicEarningsResponseDto" + } + } + } + }, + "400": { "description": "Missing or invalid username" }, + "404": { "description": "User not found" } + }, + "summary": "Get public earnings for a user (profile page)", + "tags": ["users"] + } + }, + "/api/users/earnings": { + "get": { + "description": "Returns summary (total earned, pending/completed withdrawal), breakdown by source (hackathons, grants, crowdfunding, bounties), and activity feed.", + "operationId": "EarningsController_getEarnings", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "description": "Max activities to return (default 100)", + "schema": { "type": "number" } + }, + { + "name": "offset", + "required": false, + "in": "query", + "description": "Offset for activity pagination", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { + "description": "Earnings data retrieved successfully", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/EarningsResponseDto" } + } + } + }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get current user earnings", + "tags": ["users"] + } + }, + "/api/users/earnings/withdraw": { + "post": { + "description": "Submit a withdrawal. Payout always goes to the user's linked wallet. Claiming (release flow) is for crowdfunding and grants; for crowdfunding, response may include pendingReleases to sign and submit via confirm-release. Hackathon winners do not claim here—admin releases and funds go to their wallet.", + "operationId": "EarningsController_withdraw", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/WithdrawRequestDto" } + } + } + }, + "responses": { + "200": { + "description": "Withdrawal submitted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean" }, + "withdrawalId": { "type": "string" }, + "transactionHash": { "type": "string" }, + "message": { "type": "string" } + } + } + } + } + }, + "400": { "description": "Invalid request or not claimable" }, + "401": { "description": "Unauthorized" }, + "403": { + "description": "Identity verification required. Complete KYC to withdraw funds." + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Request withdrawal / claim", + "tags": ["users"] + } + }, + "/api/users/earnings/withdraw/confirm-release": { + "post": { + "description": "After withdraw returns pendingReleases, creator signs the unsigned XDR with their wallet and submits here. On success, the milestone is marked released.", + "operationId": "EarningsController_confirmRelease", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ConfirmReleaseDto" } + } + } + }, + "responses": { + "200": { + "description": "Release submitted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfirmReleaseResponseDto" + } + } + } + }, + "400": { "description": "Invalid request or submit failed" }, + "401": { "description": "Unauthorized" }, + "403": { + "description": "Identity verification required. Complete KYC to release funds." + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Submit signed release transaction (crowdfunding)", + "tags": ["users"] + } + }, + "/api/users/me": { + "get": { + "operationId": "UserController_getProfile", + "parameters": [], + "responses": { + "200": { + "description": "User dashboard with profile, stats, chart data, activities graph, and recent activities retrieved successfully", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/DashboardDto" } + } + } + }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get current user dashboard with overview, chart, and activities graph", + "tags": ["users"] + } + }, + "/api/users/public": { + "get": { + "operationId": "UserController_getPublic", + "parameters": [], + "responses": { + "200": { "description": "Public route accessed successfully" } + }, + "summary": "Public test endpoint", + "tags": ["users"] + } + }, + "/api/users/optional": { + "get": { + "operationId": "UserController_getOptional", + "parameters": [], + "responses": { + "200": { "description": "Optional auth route accessed successfully" } + }, + "summary": "Optional authentication test endpoint", + "tags": ["users"] + } + }, + "/api/users/{username}": { + "get": { + "description": "Get a user profile by their username. Accessible to anyone without authentication.", + "operationId": "UserController_getUserByUsername", + "parameters": [ + { + "name": "username", + "required": true, + "in": "path", + "description": "Username of the user to retrieve", + "schema": { "example": "johndoe", "type": "string" } + } + ], + "responses": { + "200": { "description": "User profile retrieved successfully" }, + "404": { "description": "User not found" } + }, + "summary": "Get user profile by username", + "tags": ["users"] + } + }, + "/api/users/{username}/followers": { + "get": { + "description": "Get a list of users who follow this profile", + "operationId": "UserController_getUserFollowers", + "parameters": [ + { + "name": "username", + "required": true, + "in": "path", + "description": "Username of the user", + "schema": { "example": "johndoe", "type": "string" } + }, + { + "name": "offset", + "required": false, + "in": "query", + "description": "Pagination offset", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of followers to return", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { "description": "Followers retrieved successfully" }, + "404": { "description": "User not found" } + }, + "summary": "Get user followers", + "tags": ["users"] + } + }, + "/api/users/{username}/following": { + "get": { + "description": "Get a list of entities (users, projects, organizations) followed by this user", + "operationId": "UserController_getUserFollowing", + "parameters": [ + { + "name": "username", + "required": true, + "in": "path", + "description": "Username of the user", + "schema": { "example": "johndoe", "type": "string" } + }, + { + "name": "entityType", + "required": false, + "in": "query", + "description": "Filter by entity type", + "schema": { + "enum": [ + "USER", + "PROJECT", + "ORGANIZATION", + "CROWDFUNDING_CAMPAIGN", + "BOUNTY", + "GRANT", + "HACKATHON" + ], + "type": "string" + } + }, + { + "name": "offset", + "required": false, + "in": "query", + "description": "Pagination offset", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of following to return", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { "description": "Following list retrieved successfully" }, + "404": { "description": "User not found" } + }, + "summary": "Get users followed by this profile", + "tags": ["users"] + } + }, + "/api/users/profile": { + "get": { + "operationId": "ProfileController_getProfile", + "parameters": [], + "responses": { + "200": { "description": "Profile retrieved successfully" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get current user profile", + "tags": ["users"] + }, + "put": { + "operationId": "ProfileController_updateProfile", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateProfileDto" } + } + } + }, + "responses": { + "200": { "description": "Profile updated successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update current user profile", + "tags": ["users"] + } + }, + "/api/users/profile/stats": { + "get": { + "operationId": "ProfileController_getProfileStats", + "parameters": [], + "responses": { + "200": { "description": "Profile stats retrieved successfully" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user profile statistics", + "tags": ["users"] + } + }, + "/api/users/profile/activity": { + "get": { + "operationId": "ProfileController_getActivity", + "parameters": [], + "responses": { + "200": { "description": "Activity retrieved successfully" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user activity", + "tags": ["users"] + } + }, + "/api/users/profile/avatar": { + "post": { + "operationId": "ProfileController_uploadAvatar", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "avatar": { + "type": "string", + "format": "binary", + "description": "Avatar image file" + } + } + } + } + } + }, + "responses": { + "200": { "description": "Avatar uploaded successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Upload user avatar", + "tags": ["users"] + } + }, + "/api/users/preferences": { + "get": { + "operationId": "PreferencesController_getPreferences", + "parameters": [], + "responses": { + "200": { "description": "Preferences retrieved successfully" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user preferences", + "tags": ["users"] + } + }, + "/api/users/preferences/language": { + "put": { + "operationId": "PreferencesController_updateLanguage", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "language": { "type": "string", "example": "en" } + } + } + } + } + }, + "responses": { + "200": { "description": "Language preference updated successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update language preference", + "tags": ["users"] + } + }, + "/api/users/preferences/timezone": { + "put": { + "operationId": "PreferencesController_updateTimezone", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "timezone": { + "type": "string", + "example": "America/New_York" + } + } + } + } + } + }, + "responses": { + "200": { "description": "Timezone preference updated successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update timezone preference", + "tags": ["users"] + } + }, + "/api/users/preferences/categories": { + "put": { + "operationId": "PreferencesController_updateCategoryPreferences", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "categories": { + "type": "array", + "items": { "type": "string" }, + "example": ["tech", "design"] + } + } + } + } + } + }, + "responses": { + "200": { "description": "Category preferences updated successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update category preferences", + "tags": ["users"] + } + }, + "/api/users/preferences/skills": { + "put": { + "operationId": "PreferencesController_updateSkillPreferences", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "skills": { + "type": "array", + "items": { "type": "string" }, + "example": ["javascript", "react"] + } + } + } + } + } + }, + "responses": { + "200": { "description": "Skill preferences updated successfully" }, + "400": { "description": "Bad request" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update skill preferences", + "tags": ["users"] + } + }, + "/api/users": { + "get": { + "operationId": "UsersController_getUsers", + "parameters": [], + "responses": { + "200": { "description": "Users retrieved successfully" }, + "401": { "description": "Unauthorized" }, + "403": { "description": "Forbidden - Admin access required" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get paginated list of users (Admin only)", + "tags": ["users"] + } + }, + "/api/users/{id}": { + "get": { + "operationId": "UsersController_getUser", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "User ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "User retrieved successfully" }, + "400": { "description": "Invalid user ID" }, + "401": { "description": "Unauthorized" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user by ID", + "tags": ["users"] + }, + "put": { + "operationId": "UsersController_updateUser", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "User ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateUserDto" } + } + } + }, + "responses": { + "200": { "description": "User updated successfully" }, + "401": { "description": "Unauthorized" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update user by ID", + "tags": ["users"] + }, + "delete": { + "operationId": "UsersController_deleteUser", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "User ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "User deleted successfully" }, + "401": { "description": "Unauthorized" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Delete user by ID (Admin only)", + "tags": ["users"] + } + }, + "/api/users/{id}/profile": { + "get": { + "operationId": "UsersController_getUserProfile", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "User ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "User profile retrieved successfully" }, + "404": { "description": "User not found" } + }, + "summary": "Get user profile by ID", + "tags": ["users"] + } + }, + "/api/upload/single": { + "post": { + "description": "Upload a single file to Cloudinary with optional transformations and metadata", + "operationId": "UploadController_uploadSingle", + "parameters": [], + "requestBody": { + "required": true, + "description": "File upload data", + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary", + "description": "File to upload" + }, + "folder": { + "type": "string", + "example": "boundless/projects/project123", + "description": "Folder to upload to" + }, + "tags": { + "type": "array", + "items": { "type": "string" }, + "example": ["project", "logo"], + "description": "Tags for the file" + }, + "transformation": { + "type": "object", + "properties": { + "width": { "type": "number", "example": 400 }, + "height": { "type": "number", "example": 400 }, + "crop": { "type": "string", "example": "fit" }, + "quality": { "type": "string", "example": "auto" }, + "format": { "type": "string", "example": "auto" } + }, + "description": "Image transformation options" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "File uploaded successfully", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UploadResponseDto" } + } + } + }, + "400": { "description": "Invalid file or upload failed" } + }, + "security": [{ "bearer": [] }], + "summary": "Upload a single file", + "tags": ["Upload"] + } + }, + "/api/upload/multiple": { + "post": { + "description": "Upload multiple files to Cloudinary with optional folder and tags", + "operationId": "UploadController_uploadMultiple", + "parameters": [], + "requestBody": { + "required": true, + "description": "Multiple files upload data", + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "files": { + "type": "array", + "items": { "type": "string", "format": "binary" }, + "description": "Files to upload" + }, + "folder": { + "type": "string", + "example": "boundless/projects/project123/gallery", + "description": "Folder to upload to" + }, + "tags": { + "type": "array", + "items": { "type": "string" }, + "example": ["project", "gallery"], + "description": "Tags for the files" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Files uploaded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MultipleUploadResponseDto" + } + } + } + }, + "400": { "description": "Invalid files or upload failed" } + }, + "security": [{ "bearer": [] }], + "summary": "Upload multiple files", + "tags": ["Upload"] + } + }, + "/api/upload/{publicId}/{resourceType}": { + "delete": { + "description": "Delete a file from Cloudinary storage", + "operationId": "UploadController_deleteFile", + "parameters": [ + { + "name": "publicId", + "required": true, + "in": "path", + "description": "Public ID of the file to delete", + "schema": { + "example": "boundless/projects/project123/logo", + "type": "string" + } + }, + { + "name": "resourceType", + "required": true, + "in": "path", + "description": "Type of resource", + "schema": { "enum": ["image", "video", "raw"], "type": "string" } + } + ], + "responses": { + "200": { + "description": "File deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { + "type": "string", + "example": "File deleted successfully" + } + } + } + } + } + }, + "404": { "description": "File not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Delete a file", + "tags": ["Upload"] + } + }, + "/api/upload/info/{publicId}/{resourceType}": { + "get": { + "description": "Get detailed information about a file from Cloudinary", + "operationId": "UploadController_getFileInfo", + "parameters": [ + { + "name": "publicId", + "required": true, + "in": "path", + "description": "Public ID of the file", + "schema": { + "example": "boundless/projects/project123/logo", + "type": "string" + } + }, + { + "name": "resourceType", + "required": true, + "in": "path", + "description": "Type of resource", + "schema": { "enum": ["image", "video", "raw"], "type": "string" } + } + ], + "responses": { + "200": { + "description": "File information retrieved successfully", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/FileInfoResponseDto" } + } + } + }, + "404": { "description": "File not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get file information", + "tags": ["Upload"] + } + }, + "/api/upload/search": { + "get": { + "description": "Search files in Cloudinary with optional filters", + "operationId": "UploadController_searchFiles", + "parameters": [ + { + "name": "maxResults", + "required": false, + "in": "query", + "description": "Maximum number of results", + "schema": { "example": 50, "type": "number" } + }, + { + "name": "resourceType", + "required": false, + "in": "query", + "description": "Resource type to filter by", + "schema": { "enum": ["image", "video", "raw"], "type": "string" } + }, + { + "name": "folder", + "required": false, + "in": "query", + "description": "Folder to search in", + "schema": { "example": "boundless/projects/project123" } + }, + { + "name": "tags", + "required": false, + "in": "query", + "description": "Tags to filter by", + "schema": { + "example": ["project", "logo"], + "type": "array", + "items": { "type": "string" } + } + } + ], + "responses": { + "200": { + "description": "Files found successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchFilesResponseDto" + } + } + } + }, + "400": { "description": "Search failed" } + }, + "security": [{ "bearer": [] }], + "summary": "Search files", + "tags": ["Upload"] + } + }, + "/api/upload/optimize/{publicId}": { + "get": { + "description": "Generate an optimized URL with transformations for a file", + "operationId": "UploadController_generateOptimizedUrl", + "parameters": [ + { + "name": "publicId", + "required": true, + "in": "path", + "description": "Public ID of the file", + "schema": { + "example": "boundless/projects/project123/logo", + "type": "string" + } + }, + { + "name": "format", + "required": false, + "in": "query", + "description": "Output format", + "schema": { "example": "auto" } + }, + { + "name": "quality", + "required": false, + "in": "query", + "description": "Quality setting", + "schema": { "example": "auto" } + }, + { + "name": "crop", + "required": false, + "in": "query", + "description": "Crop mode", + "schema": { "example": "fit" } + }, + { + "name": "height", + "required": false, + "in": "query", + "description": "Desired height", + "schema": { "example": 400, "type": "number" } + }, + { + "name": "width", + "required": false, + "in": "query", + "description": "Desired width", + "schema": { "example": 400, "type": "number" } + } + ], + "responses": { + "200": { + "description": "Optimized URL generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptimizedUrlResponseDto" + } + } + } + }, + "400": { "description": "Failed to generate URL" } + }, + "security": [{ "bearer": [] }], + "summary": "Generate optimized URL", + "tags": ["Upload"] + } + }, + "/api/upload/responsive/{publicId}": { + "get": { + "description": "Generate multiple URLs with different sizes for responsive images", + "operationId": "UploadController_generateResponsiveUrls", + "parameters": [ + { + "name": "publicId", + "required": true, + "in": "path", + "description": "Public ID of the file", + "schema": { + "example": "boundless/projects/project123/logo", + "type": "string" + } + }, + { + "name": "format", + "required": false, + "in": "query", + "description": "Output format", + "schema": { "example": "auto" } + }, + { + "name": "quality", + "required": false, + "in": "query", + "description": "Quality setting", + "schema": { "example": "auto" } + }, + { + "name": "crop", + "required": false, + "in": "query", + "description": "Crop mode", + "schema": { "example": "fill" } + }, + { + "name": "height", + "required": false, + "in": "query", + "description": "Base height for responsive breakpoints", + "schema": { "example": 600, "type": "number" } + }, + { + "name": "width", + "required": false, + "in": "query", + "description": "Base width for responsive breakpoints", + "schema": { "example": 800, "type": "number" } + } + ], + "responses": { + "200": { + "description": "Responsive URLs generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponsiveUrlsResponseDto" + } + } + } + }, + "400": { "description": "Failed to generate responsive URLs" } + }, + "security": [{ "bearer": [] }], + "summary": "Generate responsive URLs", + "tags": ["Upload"] + } + }, + "/api/upload/avatar/{publicId}": { + "get": { + "description": "Generate a square cropped avatar URL with automatic optimizations", + "operationId": "UploadController_generateAvatarUrl", + "parameters": [ + { + "name": "publicId", + "required": true, + "in": "path", + "description": "Public ID of the image file", + "schema": { + "example": "boundless/users/user123/avatar", + "type": "string" + } + }, + { + "name": "size", + "required": false, + "in": "query", + "description": "Avatar size (square)", + "schema": { "example": 200, "type": "number" } + } + ], + "responses": { + "200": { + "description": "Avatar URL generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptimizedUrlResponseDto" + } + } + } + }, + "400": { "description": "Failed to generate avatar URL" } + }, + "security": [{ "bearer": [] }], + "summary": "Generate avatar URL", + "tags": ["Upload"] + } + }, + "/api/upload/logo/{publicId}": { + "get": { + "description": "Generate a logo URL with fit cropping and automatic optimizations", + "operationId": "UploadController_generateLogoUrl", + "parameters": [ + { + "name": "publicId", + "required": true, + "in": "path", + "description": "Public ID of the image file", + "schema": { + "example": "boundless/projects/project123/logo", + "type": "string" + } + }, + { + "name": "height", + "required": false, + "in": "query", + "description": "Logo height", + "schema": { "example": 400, "type": "number" } + }, + { + "name": "width", + "required": false, + "in": "query", + "description": "Logo width", + "schema": { "example": 400, "type": "number" } + } + ], + "responses": { + "200": { + "description": "Logo URL generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptimizedUrlResponseDto" + } + } + } + }, + "400": { "description": "Failed to generate logo URL" } + }, + "security": [{ "bearer": [] }], + "summary": "Generate logo URL", + "tags": ["Upload"] + } + }, + "/api/upload/banner/{publicId}": { + "get": { + "description": "Generate a banner URL with fill cropping and automatic optimizations", + "operationId": "UploadController_generateBannerUrl", + "parameters": [ + { + "name": "publicId", + "required": true, + "in": "path", + "description": "Public ID of the image file", + "schema": { + "example": "boundless/projects/project123/banner", + "type": "string" + } + }, + { + "name": "height", + "required": false, + "in": "query", + "description": "Banner height", + "schema": { "example": 600, "type": "number" } + }, + { + "name": "width", + "required": false, + "in": "query", + "description": "Banner width", + "schema": { "example": 1200, "type": "number" } + } + ], + "responses": { + "200": { + "description": "Banner URL generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OptimizedUrlResponseDto" + } + } + } + }, + "400": { "description": "Failed to generate banner URL" } + }, + "security": [{ "bearer": [] }], + "summary": "Generate banner URL", + "tags": ["Upload"] + } + }, + "/api/upload/stats": { + "get": { + "description": "Get Cloudinary usage statistics for the account", + "operationId": "UploadController_getUsageStats", + "parameters": [], + "responses": { + "200": { + "description": "Usage statistics retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsageStatsResponseDto" + } + } + } + }, + "400": { "description": "Failed to get usage stats" } + }, + "security": [{ "bearer": [] }], + "summary": "Get usage statistics", + "tags": ["Upload"] + } + }, + "/api/auth/register": { + "post": { + "operationId": "AuthController_register", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/RegisterDto" } + } + } + }, + "responses": { "201": { "description": "" } }, + "tags": ["Auth"] + } + }, + "/api/auth/login": { + "post": { + "operationId": "AuthController_login", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/LoginDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "tags": ["Auth"] + } + }, + "/api/auth/refresh": { + "post": { + "operationId": "AuthController_refreshToken", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/RefreshTokenDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "tags": ["Auth"] + } + }, + "/api/auth/logout": { + "post": { + "operationId": "AuthController_logout", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Auth"] + } + }, + "/api/auth/me": { + "get": { + "operationId": "AuthController_getProfile", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Auth"] + } + }, + "/api/auth/verify-stellar-signature": { + "post": { + "operationId": "AuthController_verifyStellarSignature", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/VerifySignatureDto" } + } + } + }, + "responses": { "201": { "description": "" } }, + "tags": ["Auth"] + } + }, + "/api/auth/oauth/google": { + "get": { + "operationId": "OAuthController_googleAuth", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["OAuth"] + } + }, + "/api/auth/oauth/google/callback": { + "get": { + "operationId": "OAuthController_googleAuthCallback", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["OAuth"] + } + }, + "/api/auth/oauth/github": { + "get": { + "operationId": "OAuthController_githubAuth", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["OAuth"] + } + }, + "/api/auth/oauth/github/callback": { + "get": { + "operationId": "OAuthController_githubAuthCallback", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["OAuth"] + } + }, + "/api/auth/oauth/twitter": { + "get": { + "operationId": "OAuthController_twitterAuth", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["OAuth"] + } + }, + "/api/auth/oauth/twitter/callback": { + "get": { + "operationId": "OAuthController_twitterAuthCallback", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["OAuth"] + } + }, + "/api/follows/{entityType}/{entityId}": { + "post": { + "operationId": "FollowsController_followEntity", + "parameters": [ + { + "name": "entityType", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "201": { "description": "" } }, + "tags": ["Follows"] + }, + "delete": { + "operationId": "FollowsController_unfollowEntity", + "parameters": [ + { + "name": "entityType", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Follows"] + } + }, + "/api/follows/user/{userId}/following": { + "get": { + "operationId": "FollowsController_getUserFollowing", + "parameters": [ + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityType", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Follows"] + } + }, + "/api/follows/entity/{entityType}/{entityId}/followers": { + "get": { + "operationId": "FollowsController_getEntityFollowers", + "parameters": [ + { + "name": "entityType", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Follows"] + } + }, + "/api/follows/user/{userId}/stats": { + "get": { + "operationId": "FollowsController_getFollowStats", + "parameters": [ + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Follows"] + } + }, + "/api/follows/{entityType}/{entityId}/check": { + "get": { + "operationId": "FollowsController_isFollowing", + "parameters": [ + { + "name": "entityType", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Follows"] + } + }, + "/api/chat/history": { + "get": { + "operationId": "ChatController_getMessages", + "parameters": [ + { + "name": "roomId", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "roomType", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "cursor", + "required": false, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + } + ], + "responses": { "200": { "description": "Returns list of messages." } }, + "security": [{ "bearer": [] }], + "summary": "Get chat message history", + "tags": ["Chat"] + } + }, + "/api/messages/conversations": { + "get": { + "operationId": "MessagesController_listConversations", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "offset", + "required": false, + "in": "query", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { "description": "Paginated list of conversations" } + }, + "security": [{ "bearer": [] }], + "summary": "List my conversations", + "tags": ["Messages"] + }, + "post": { + "operationId": "MessagesController_startOrGetConversation", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateConversationDto" } + } + } + }, + "responses": { + "200": { "description": "Conversation (created or existing)" } + }, + "security": [{ "bearer": [] }], + "summary": "Start or get existing conversation", + "tags": ["Messages"] + } + }, + "/api/messages/conversations/{id}": { + "get": { + "operationId": "MessagesController_getConversation", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Conversation ID", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Conversation details" } }, + "security": [{ "bearer": [] }], + "summary": "Get one conversation (thread header)", + "tags": ["Messages"] + } + }, + "/api/messages/conversations/{id}/messages": { + "get": { + "operationId": "MessagesController_listMessages", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Conversation ID", + "schema": { "type": "string" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "before", + "required": false, + "in": "query", + "description": "Cursor for older messages", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Paginated messages" } }, + "security": [{ "bearer": [] }], + "summary": "List messages in a conversation", + "tags": ["Messages"] + }, + "post": { + "operationId": "MessagesController_sendMessage", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Conversation ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateMessageDto" } + } + } + }, + "responses": { "201": { "description": "Message created" } }, + "security": [{ "bearer": [] }], + "summary": "Send a message", + "tags": ["Messages"] + } + }, + "/api/messages/conversations/{id}/read": { + "patch": { + "operationId": "MessagesController_markConversationRead", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Conversation ID", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Marked as read" } }, + "security": [{ "bearer": [] }], + "summary": "Mark conversation as read", + "tags": ["Messages"] + } + }, + "/api/crowdfunding/validate": { + "post": { + "description": "Validate campaign data before creation. returns 200 if valid, 400 if invalid.", + "operationId": "CampaignsController_validateCampaign", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateCampaignDto" } + } + } + }, + "responses": { + "200": { "description": "Campaign data is valid" }, + "400": { "description": "Invalid campaign data" } + }, + "security": [{ "bearer": [] }], + "summary": "Validate campaign data", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding": { + "post": { + "description": "Create a new crowdfunding campaign. This will also create the associated project automatically.", + "operationId": "CampaignsController_createCampaign", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateCampaignDto" } + } + } + }, + "responses": { + "201": { "description": "Campaign and project created successfully" }, + "400": { "description": "Invalid campaign data" } + }, + "security": [{ "bearer": [] }], + "summary": "Create a crowdfunding campaign", + "tags": ["crowdfunding"] + }, + "get": { + "description": "Get a paginated list of crowdfunding campaigns with optional filtering", + "operationId": "CampaignsController_getCampaigns", + "parameters": [ + { + "name": "category", + "required": false, + "in": "query", + "description": "Category of the campaign", + "schema": { "example": "web3", "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Status of the campaign", + "schema": { + "enum": ["active", "funded", "completed"], + "type": "string" + } + }, + { + "name": "minFundingGoal", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "maxFundingGoal", + "required": false, + "in": "query", + "description": "Minimum funding goal of the campaign", + "schema": { "example": 1000, "type": "number" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Maximum funding goal of the campaign", + "schema": { "example": 10000, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Limit of the campaign", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "sortBy", + "required": true, + "in": "query", + "description": "Sort by of the campaign", + "schema": { "example": "createdAt", "type": "string" } + }, + { + "name": "sortOrder", + "required": true, + "in": "query", + "description": "Sort order of the campaign", + "schema": { "example": "desc", "type": "string" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search of the campaign", + "schema": { "example": "web3", "type": "string" } + } + ], + "responses": { + "200": { "description": "Campaigns retrieved successfully" } + }, + "summary": "List crowdfunding campaigns", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/trigger-cron": { + "get": { + "description": "Manually trigger the campaign transition cron job for testing purposes.", + "operationId": "CampaignsController_triggerCron", + "parameters": [], + "responses": { + "200": { "description": "Cron job triggered successfully" } + }, + "summary": "Trigger campaign transition cron", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/me": { + "get": { + "description": "Get a paginated list of crowdfunding campaigns created by the authenticated user", + "operationId": "CampaignsController_getMyCampaigns", + "parameters": [ + { + "name": "category", + "required": true, + "in": "query", + "description": "Category of the campaign", + "schema": { "example": "web3", "type": "string" } + }, + { + "name": "status", + "required": true, + "in": "query", + "description": "Status of the campaign", + "schema": { "example": "active", "type": "string" } + }, + { + "name": "minFundingGoal", + "required": true, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "maxFundingGoal", + "required": true, + "in": "query", + "description": "Minimum funding goal of the campaign", + "schema": { "example": 1000, "type": "number" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Maximum funding goal of the campaign", + "schema": { "example": 10000, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Limit of the campaign", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort by of the campaign", + "schema": { "example": "createdAt", "type": "string" } + }, + { + "name": "sortOrder", + "required": false, + "in": "query", + "description": "Sort order of the campaign", + "schema": { "example": "desc", "type": "string" } + }, + { + "name": "search", + "required": true, + "in": "query", + "description": "Search of the campaign", + "schema": { "example": "web3", "type": "string" } + } + ], + "responses": { + "200": { "description": "User campaigns retrieved successfully" } + }, + "security": [{ "bearer": [] }], + "summary": "List authenticated user's campaigns", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/s/{slug}": { + "get": { + "description": "Get detailed information about a specific crowdfunding campaign by its URL slug", + "operationId": "CampaignsController_getCampaignBySlug", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Campaign URL slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Campaign details retrieved successfully" }, + "404": { "description": "Campaign not found" } + }, + "summary": "Get campaign by slug", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}": { + "get": { + "description": "Get detailed information about a specific crowdfunding campaign", + "operationId": "CampaignsController_getCampaign", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Campaign details retrieved successfully" }, + "404": { "description": "Campaign not found" } + }, + "summary": "Get campaign details", + "tags": ["crowdfunding"] + }, + "put": { + "description": "Update a crowdfunding campaign. Only campaign owners can update campaigns.", + "operationId": "CampaignsController_updateCampaign", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateCampaignDto" } + } + } + }, + "responses": { + "200": { "description": "Campaign updated successfully" }, + "403": { "description": "User does not own the campaign" } + }, + "security": [{ "bearer": [] }], + "summary": "Update campaign", + "tags": ["crowdfunding"] + }, + "delete": { + "description": "Delete a crowdfunding campaign. Only campaign owners can delete campaigns that are in draft/reviewing phase and have no contributions.", + "operationId": "CampaignsController_deleteCampaign", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Campaign deleted successfully" }, + "403": { + "description": "Cannot delete campaign with contributions, campaigns in funding phase, funded campaigns, completed campaigns, or user does not own the campaign" + } + }, + "security": [{ "bearer": [] }], + "summary": "Delete campaign", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/statistics": { + "get": { + "description": "Get funding statistics and progress for a campaign", + "operationId": "CampaignsController_getCampaignStatistics", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Campaign statistics retrieved successfully" } + }, + "summary": "Get campaign statistics", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/escrow": { + "put": { + "description": "Update escrow details including transaction hash, address, and status. Only campaign owners can update escrow details.", + "operationId": "CampaignsController_updateEscrowDetails", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateEscrowDto" } + } + } + }, + "responses": { + "200": { "description": "Escrow details updated successfully" }, + "403": { "description": "User does not own the campaign" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update escrow details", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/invitations": { + "post": { + "operationId": "CampaignsController_inviteTeamMember", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/InviteTeamMemberDto" } + } + } + }, + "responses": { "201": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Invite a team member to the campaign", + "tags": ["crowdfunding"] + }, + "get": { + "operationId": "CampaignsController_getInvitations", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Get all invitations for a campaign", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/invitations/accept": { + "post": { + "operationId": "CampaignsController_acceptInvitation", + "parameters": [ + { + "name": "token", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Accept a campaign team invitation", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/contribute": { + "post": { + "description": "Make a contribution to a crowdfunding campaign", + "operationId": "ContributionsController_contributeToCampaign", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ContributeCampaignDto" } + } + } + }, + "responses": { + "200": { "description": "Contribution added successfully" }, + "403": { "description": "Campaign has ended or is fully funded" } + }, + "security": [{ "bearer": [] }], + "summary": "Contribute to campaign", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/contributions": { + "get": { + "description": "Get paginated list of contributions for a campaign", + "operationId": "ContributionsController_getCampaignContributions", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { "description": "Contributions retrieved successfully" } + }, + "summary": "Get campaign contributions", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/contributions/stats": { + "get": { + "description": "Get contribution statistics and analytics for a campaign", + "operationId": "ContributionsController_getContributionStats", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Contribution statistics retrieved successfully" + } + }, + "summary": "Get contribution statistics", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/milestones": { + "get": { + "description": "Get all milestones for a crowdfunding campaign", + "operationId": "MilestonesController_getCampaignMilestones", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Milestones retrieved successfully" } + }, + "summary": "Get campaign milestones", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/milestones/{milestoneId}": { + "get": { + "description": "Get detailed information about a specific milestone", + "operationId": "MilestonesController_getMilestone", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + }, + { + "name": "milestoneId", + "required": true, + "in": "path", + "description": "Milestone ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Milestone details retrieved successfully" }, + "404": { "description": "Milestone not found" } + }, + "summary": "Get milestone details", + "tags": ["crowdfunding"] + }, + "put": { + "description": "Submit milestone with proof of work for review. Creators: Provide proof of work files/links and optional notes. Data will be strictly validated. Milestone will be marked as SUBMITTED status for admin review.", + "operationId": "MilestonesController_updateMilestone", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + }, + { + "name": "milestoneId", + "required": true, + "in": "path", + "description": "Milestone ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateMilestoneDto" } + } + } + }, + "responses": { + "200": { "description": "Milestone submitted successfully" }, + "400": { + "description": "Validation failed - invalid proof of work data" + }, + "403": { "description": "User does not own the campaign" } + }, + "security": [{ "bearer": [] }], + "summary": "Submit milestone for review", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/milestones/{milestoneId}/validate-submission": { + "post": { + "description": "Strictly validate milestone submission data (proof of work files/links) for creator submissions without performing any side effects. Creators submit milestones for review with proof of work. Admin reviews and approves later. Returns validated data if successful, or detailed error messages if validation fails. Use this before blockchain interaction to ensure data integrity.", + "operationId": "MilestonesController_validateMilestoneSubmission", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + }, + { + "name": "milestoneId", + "required": true, + "in": "path", + "description": "Milestone ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateMilestoneSubmissionDto" + } + } + } + }, + "responses": { + "200": { + "description": "Validation successful", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "validated": { "type": "boolean", "example": true }, + "data": { + "type": "object", + "properties": { + "status": { "type": "string", "example": "submitted" }, + "evidence": { + "type": "string", + "example": "Milestone completed - all deliverables ready for review." + }, + "documents": { + "type": "array", + "items": { "type": "string" }, + "example": ["https://example.com/report.pdf"] + } + } + } + } + } + } + } + }, + "400": { + "description": "Validation failed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "validated": { "type": "boolean", "example": false }, + "error": { + "type": "string", + "example": "Evidence must be at least 10 characters of meaningful content" + } + } + } + } + } + } + }, + "summary": "Validate milestone submission data", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/{id}/milestones/stats": { + "get": { + "description": "Get milestone completion statistics for a campaign", + "operationId": "MilestonesController_getMilestoneStats", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID or slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Milestone statistics retrieved successfully" + } + }, + "summary": "Get milestone statistics", + "tags": ["crowdfunding"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/submit-for-review": { + "post": { + "operationId": "BuilderCrowdfundingV2Controller_submitForReview", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Submit a DRAFT campaign to admin review", + "tags": ["Crowdfunding v2 - Builder"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/withdraw-submission": { + "post": { + "operationId": "BuilderCrowdfundingV2Controller_withdrawSubmission", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Withdraw a pending review back to DRAFT (D4)", + "tags": ["Crowdfunding v2 - Builder"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/revise-and-resubmit": { + "post": { + "operationId": "BuilderCrowdfundingV2Controller_reviseAndResubmit", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Resubmit a REVIEW_REJECTED campaign (D5: unlimited retries)", + "tags": ["Crowdfunding v2 - Builder"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/escrow/publish": { + "post": { + "operationId": "BuilderCrowdfundingV2Controller_publish", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublishCrowdfundingEscrowDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Publish a VOTE_PASSED campaign to the events contract", + "tags": ["Crowdfunding v2 - Builder"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/escrow/cancel": { + "post": { + "operationId": "BuilderCrowdfundingV2Controller_cancel", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelCrowdfundingEscrowDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Cancel a campaign and refund backers", + "tags": ["Crowdfunding v2 - Builder"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/escrow/claim-milestone": { + "post": { + "operationId": "BuilderCrowdfundingV2Controller_claimMilestone", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClaimCrowdfundingMilestoneDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Claim a milestone payout (reviewStatus must be APPROVED)", + "tags": ["Crowdfunding v2 - Builder"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/escrow/contribute": { + "post": { + "operationId": "BackerCrowdfundingV2Controller_contribute", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributeCrowdfundingDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Build (and optionally submit) an add_funds op against the campaign", + "tags": ["Crowdfunding v2 - Backer"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/vote": { + "post": { + "operationId": "CommunityCrowdfundingV2Controller_castVote", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CastCrowdfundingVoteDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Cast or change vote on a VOTING campaign", + "tags": ["Crowdfunding v2 - Community"] + }, + "get": { + "operationId": "CommunityCrowdfundingV2Controller_getTally", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Read the campaign vote tally", + "tags": ["Crowdfunding v2 - Community"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/vote/me": { + "get": { + "operationId": "CommunityCrowdfundingV2Controller_getMyVote", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Read the caller's current vote (or null)", + "tags": ["Crowdfunding v2 - Community"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/admin/approve": { + "post": { + "operationId": "AdminCrowdfundingV2Controller_approve", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApproveCrowdfundingCampaignDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Approve a submitted campaign; assigns reviewer", + "tags": ["Crowdfunding v2 - Admin"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/admin/reject": { + "post": { + "operationId": "AdminCrowdfundingV2Controller_reject", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectCrowdfundingCampaignDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Reject a submitted campaign with optional reason", + "tags": ["Crowdfunding v2 - Admin"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/admin/pause": { + "post": { + "operationId": "AdminCrowdfundingV2Controller_pause", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PauseCrowdfundingCampaignDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Pause a live campaign (D7)", + "tags": ["Crowdfunding v2 - Admin"] + } + }, + "/api/crowdfunding/campaigns/{id}/v2/admin/unpause": { + "post": { + "operationId": "AdminCrowdfundingV2Controller_unpause", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Unpause a campaign and restore previous status", + "tags": ["Crowdfunding v2 - Admin"] + } + }, + "/api/wallet": { + "get": { + "operationId": "WalletController_getWallet", + "parameters": [], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Get current user wallet", + "tags": ["wallet"] + } + }, + "/api/wallet/details": { + "get": { + "operationId": "WalletController_getWalletDetails", + "parameters": [], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Get wallet details including balances and transactions", + "tags": ["wallet"] + } + }, + "/api/wallet/sync": { + "post": { + "operationId": "WalletController_syncWallet", + "parameters": [], + "responses": { "201": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Sync wallet with blockchain", + "tags": ["wallet"] + } + }, + "/api/wallet/create": { + "post": { + "operationId": "WalletController_createWallet", + "parameters": [], + "responses": { "201": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Create a new wallet for the current user", + "tags": ["wallet"] + } + }, + "/api/wallet/activate": { + "post": { + "description": "Creates the on-chain account and configured trustlines (default: USDC) in a single sponsored transaction. The platform sponsor account pays all XLM reserves and the network fee. Idempotent: safe to retry if a prior call failed.", + "operationId": "WalletController_activate", + "parameters": [], + "responses": { + "201": { + "description": "Wallet activated. Returns tx hash and added trustlines." + }, + "500": { + "description": "Sponsorship not configured, or unexpected submit error." + }, + "503": { + "description": "Sponsor account is out of available XLM. Operators have been alerted; retry later." + } + }, + "security": [{ "bearer": [] }], + "summary": "Activate wallet on Stellar with sponsored reserves", + "tags": ["wallet"] + } + }, + "/api/wallet/admin/reclaim-dormant": { + "post": { + "description": "Finds wallets that have been idle for the given window with zero on-chain balances, and merges each one back into the sponsor account. Frees ~1 XLM per account and ~0.5 XLM per trustline. Defaults to dryRun=true; set dryRun=false to actually submit. The wallet row is preserved (isActivated reset to false), so a returning user can re-activate at the same address.", + "operationId": "WalletController_reclaimDormant", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ReclaimDormantDto" } + } + } + }, + "responses": { + "201": { + "description": "Reclaim summary: scanned, eligible, revoked, freedXlm, walletIds, errors" + }, + "403": { "description": "Admin role required." } + }, + "security": [{ "bearer": [] }], + "summary": "Admin: reclaim sponsor XLM from dormant zero-balance wallets", + "tags": ["wallet"] + } + }, + "/api/wallet/trustline/supported": { + "get": { + "operationId": "WalletController_getSupportedTrustlines", + "parameters": [], + "responses": { + "200": { "description": "List of supported trustline assets" } + }, + "security": [{ "bearer": [] }], + "summary": "List assets that can have a trustline added (e.g. USDC, EURC)", + "tags": ["wallet"] + } + }, + "/api/wallet/trustline": { + "post": { + "operationId": "WalletController_addTrustline", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AddTrustlineDto" } + } + } + }, + "responses": { + "201": { "description": "Trustline added or already exists" }, + "400": { + "description": "Wallet not activated, insufficient XLM for fees, or unsupported asset" + } + }, + "security": [{ "bearer": [] }], + "summary": "Add a trustline for a supported asset (e.g. USDC)", + "tags": ["wallet"] + } + }, + "/api/wallet/send/validate": { + "get": { + "description": "Returns whether the destination is a valid Stellar address, activated on the network, has a trustline for the given asset (for non-XLM), and whether the address requires a memo (e.g. exchange shared deposit address).", + "operationId": "WalletController_validateSendDestination", + "parameters": [ + { + "name": "destinationPublicKey", + "required": true, + "in": "query", + "description": "Stellar public key (G...)", + "schema": { "type": "string" } + }, + { + "name": "currency", + "required": true, + "in": "query", + "description": "Asset code (e.g. USDC, XLM)", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Validation result (valid, isActivated, hasTrustlineForAsset, memoRequired)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "valid": { "type": "boolean" }, + "isValidPublicKey": { "type": "boolean" }, + "isActivated": { "type": "boolean" }, + "hasTrustlineForAsset": { "type": "boolean" }, + "memoRequired": { + "type": "boolean", + "description": "True if this destination requires a memo (e.g. exchange shared address)" + }, + "message": { "type": "string", "nullable": true } + } + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Validate destination address before sending", + "tags": ["wallet"] + } + }, + "/api/wallet/send": { + "post": { + "description": "Sends funds from your Boundless wallet to a destination. Requires identity verification (KYC). Validates: your wallet is activated, destination is activated, destination has trustline for the asset (if not XLM), optional memo. Requires sufficient balance and XLM for network fee when sending non-XLM.", + "operationId": "WalletController_send", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UserSendDto" } + } + } + }, + "responses": { + "201": { "description": "Send submitted successfully" }, + "400": { + "description": "Validation or business rule error (e.g. destination not activated, no trustline, memo required, insufficient balance)" + }, + "403": { + "description": "Identity verification required. Complete KYC to send funds." + } + }, + "security": [{ "bearer": [] }], + "summary": "Send funds from your wallet to a Stellar address", + "tags": ["wallet"] + } + }, + "/api/wallet/payout": { + "post": { + "description": "Sends funds from the Boundless platform wallet to a destination. Validates: destination activated, trustline for asset, memo when required, platform balance. Idempotent when idempotencyKey is provided.", + "operationId": "WalletPayoutController_sendPayout", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SendPayoutDto" } + } + } + }, + "responses": { + "201": { "description": "Payout submitted successfully" }, + "400": { + "description": "Validation or business rule error (e.g. destination not activated, no trustline, memo required)" + }, + "403": { "description": "Forbidden – admin only" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Send payout from platform (Admin only)", + "tags": ["wallet"] + } + }, + "/api/api/comments": { + "post": { + "operationId": "CommentsController_createComment", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateCommentDto" } + } + } + }, + "responses": { + "201": { "description": "Comment created successfully" }, + "400": { "description": "Invalid input" }, + "429": { "description": "Rate limit exceeded" } + }, + "security": [{ "bearer": [] }], + "summary": "Create a comment", + "tags": ["comments"] + }, + "get": { + "operationId": "CommentsController_listComments", + "parameters": [ + { + "name": "entityType", + "required": false, + "in": "query", + "description": "Entity type to filter comments", + "schema": { + "type": "string", + "enum": [ + "PROJECT", + "BOUNTY", + "CROWDFUNDING_CAMPAIGN", + "GRANT", + "GRANT_APPLICATION", + "HACKATHON", + "HACKATHON_SUBMISSION", + "BLOG_POST" + ] + } + }, + { + "name": "entityId", + "required": false, + "in": "query", + "description": "Entity ID to filter comments", + "schema": { "type": "string" } + }, + { + "name": "authorId", + "required": false, + "in": "query", + "description": "Author ID to filter comments", + "schema": { "type": "string" } + }, + { + "name": "parentId", + "required": false, + "in": "query", + "description": "Parent comment ID to filter replies", + "schema": { "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Comment status to filter", + "schema": { + "type": "string", + "enum": ["ACTIVE", "HIDDEN", "DELETED", "PENDING_MODERATION"] + } + }, + { + "name": "includeReactions", + "required": false, + "in": "query", + "description": "Include reaction data in response", + "schema": { "default": true, "type": "boolean" } + }, + { + "name": "includeReports", + "required": false, + "in": "query", + "description": "Include report data in response (moderators only)", + "schema": { "default": false, "type": "boolean" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "minimum": 1, "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of items per page", + "schema": { + "minimum": 1, + "maximum": 100, + "default": 20, + "type": "number" + } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Field to sort by", + "schema": { "default": "createdAt", "type": "string" } + }, + { + "name": "sortOrder", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { + "default": "desc", + "type": "string", + "enum": ["asc", "desc"] + } + } + ], + "responses": { + "200": { "description": "Comments retrieved successfully" } + }, + "summary": "List comments with filters", + "tags": ["comments"] + } + }, + "/api/api/comments/{id}": { + "get": { + "operationId": "CommentsController_getComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Comment retrieved successfully" }, + "404": { "description": "Comment not found" } + }, + "summary": "Get comment by ID", + "tags": ["comments"] + }, + "put": { + "operationId": "CommentsController_updateComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateCommentDto" } + } + } + }, + "responses": { + "200": { "description": "Comment updated successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Comment not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update comment (author only)", + "tags": ["comments"] + }, + "delete": { + "operationId": "CommentsController_deleteComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "responses": { + "204": { "description": "Comment deleted successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Comment not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Delete comment (author or moderator only)", + "tags": ["comments"] + } + }, + "/api/api/comments/entity/{entityType}/{entityId}": { + "get": { + "operationId": "CommentsController_getCommentsByEntity", + "parameters": [ + { + "name": "entityType", + "required": true, + "in": "path", + "description": "Entity type", + "schema": { "type": "string" } + }, + { + "name": "entityId", + "required": true, + "in": "path", + "description": "Entity ID", + "schema": { "type": "string" } + }, + { + "name": "includeNested", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Comments retrieved successfully" } + }, + "summary": "Get comments for an entity", + "tags": ["comments"] + } + }, + "/api/api/comments/{id}/reactions": { + "post": { + "operationId": "CommentsController_addReaction", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AddReactionDto" } + } + } + }, + "responses": { + "201": { "description": "Reaction added successfully" }, + "429": { "description": "Rate limit exceeded" } + }, + "security": [{ "bearer": [] }], + "summary": "Add reaction to comment", + "tags": ["comments"] + }, + "get": { + "operationId": "CommentsController_getReactions", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Reactions retrieved successfully" } + }, + "summary": "Get reactions for comment", + "tags": ["comments"] + } + }, + "/api/api/comments/{id}/reactions/{reactionType}": { + "delete": { + "operationId": "CommentsController_removeReaction", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + }, + { + "name": "reactionType", + "required": true, + "in": "path", + "description": "Reaction type", + "schema": { "type": "string" } + } + ], + "responses": { + "204": { "description": "Reaction removed successfully" } + }, + "security": [{ "bearer": [] }], + "summary": "Remove reaction from comment", + "tags": ["comments"] + } + }, + "/api/api/comments/{id}/report": { + "post": { + "operationId": "CommentsController_reportComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ReportCommentDto" } + } + } + }, + "responses": { + "201": { "description": "Comment reported successfully" }, + "429": { "description": "Rate limit exceeded" } + }, + "security": [{ "bearer": [] }], + "summary": "Report a comment", + "tags": ["comments"] + } + }, + "/api/api/comments/moderation/queue": { + "get": { + "operationId": "CommentModerationController_getModerationQueue", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { "description": "Moderation queue retrieved successfully" }, + "403": { "description": "Forbidden" } + }, + "security": [{ "bearer": [] }], + "summary": "Get moderation queue (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/api/comments/moderation/reports": { + "get": { + "operationId": "CommentModerationController_getReports", + "parameters": [ + { + "name": "status", + "required": false, + "in": "query", + "schema": { + "enum": ["PENDING", "REVIEWED", "RESOLVED", "DISMISSED"], + "type": "string" + } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { "description": "Reports retrieved successfully" }, + "403": { "description": "Forbidden" } + }, + "security": [{ "bearer": [] }], + "summary": "Get all reports (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/api/comments/moderation/reports/{id}/resolve": { + "post": { + "operationId": "CommentModerationController_resolveReport", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Report ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ResolveReportDto" } + } + } + }, + "responses": { + "200": { "description": "Report resolved successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Report not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Resolve a report (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/api/comments/moderation/{id}/approve": { + "post": { + "operationId": "CommentModerationController_approveComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Comment approved successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Comment not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Approve a comment (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/api/comments/moderation/{id}/reject": { + "post": { + "operationId": "CommentModerationController_rejectComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Comment rejected successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Comment not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Reject/Hide a comment (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/api/comments/moderation/{id}/hide": { + "post": { + "operationId": "CommentModerationController_hideComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Comment hidden successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Comment not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Hide a comment (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/api/comments/moderation/{id}/restore": { + "post": { + "operationId": "CommentModerationController_restoreComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Comment restored successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Comment not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Restore a hidden comment (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/api/comments/moderation/stats": { + "get": { + "operationId": "CommentModerationController_getModerationStats", + "parameters": [], + "responses": { + "200": { "description": "Moderation stats retrieved successfully" }, + "403": { "description": "Forbidden" } + }, + "security": [{ "bearer": [] }], + "summary": "Get moderation statistics (moderators only)", + "tags": ["comment-moderation"] + } + }, + "/api/hackathons": { + "get": { + "description": "Retrieves a paginated list of published hackathons with optional filtering", + "operationId": "HackathonsController_getHackathons", + "parameters": [], + "responses": { + "200": { + "description": "Hackathons retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonsListResponseDto" + } + } + } + } + }, + "summary": "Get published hackathons", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/fee-estimate": { + "get": { + "description": "Returns platform fee breakdown for a given total prize pool (USDC). Used by the Rewards step when creating a hackathon.", + "operationId": "HackathonsController_getFeeEstimate", + "parameters": [ + { + "name": "totalPool", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Fee estimate", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeeEstimateResponseDto" + } + } + } + }, + "400": { + "description": "totalPool is missing, invalid, or below minimum (5 USDC)" + } + }, + "summary": "Get fee estimate for prize pool", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}/winners": { + "get": { + "description": "Retrieves ranked winners for a hackathon with prize details", + "operationId": "HackathonsController_getWinners", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Winners retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonWinnersResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get hackathon winners", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}/results": { + "get": { + "description": "Retrieves aggregated judging results after results are published", + "operationId": "HackathonsController_getPublicResults", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Results retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicJudgingResultsResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get public judging results", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}": { + "get": { + "description": "Retrieves a published hackathon by its ID or slug", + "operationId": "HackathonsController_getHackathon", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Hackathon retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get hackathon by ID or slug", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{slug}/contributors": { + "get": { + "description": "Returns confirmed partner contributions where the partner opted in to be shown publicly, plus the total amount contributed.", + "operationId": "HackathonsController_getPublicContributors", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Contributors retrieved successfully" } + }, + "summary": "List public partner contributors for a hackathon", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}/follow": { + "post": { + "description": "Toggles follow status for a published hackathon", + "operationId": "HackathonsController_followHackathon", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Follow status updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "following": { "type": "boolean", "example": true } + } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Follow or unfollow a hackathon", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}/join": { + "post": { + "description": "Register as a participant for a published hackathon", + "operationId": "HackathonsController_joinHackathon", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Successfully joined hackathon", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ParticipationResponseDto" + } + } + } + }, + "400": { + "description": "Registration closed or already participating" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Join a hackathon", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}/leave": { + "delete": { + "description": "Remove yourself as a participant from a hackathon", + "operationId": "HackathonsController_leaveHackathon", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Successfully left hackathon", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ParticipationResponseDto" + } + } + } + }, + "400": { + "description": "Not a participant or submission deadline passed" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Leave a hackathon", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}/participants": { + "get": { + "description": "Retrieve list of participants for a hackathon by ID or slug", + "operationId": "HackathonsController_getHackathonParticipants", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-based)", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "status", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "skill", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "type", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "search", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Participants retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonParticipantsResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get hackathon participants", + "tags": ["Hackathons"] + } + }, + "/api/hackathons/{idOrSlug}/submissions": { + "get": { + "description": "Retrieves submissions for a hackathon (organizer only)", + "operationId": "HackathonsSubmissionsController_getHackathonSubmissions", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by submission status", + "schema": { + "enum": ["SUBMITTED", "SHORTLISTED", "DISQUALIFIED"], + "type": "string" + } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-based)", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "search", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "type", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Submissions retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SubmissionResponseDto" + } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get hackathon submissions", + "tags": ["Hackathons - Submissions"] + }, + "post": { + "description": "Submit a project to a hackathon", + "operationId": "HackathonsSubmissionsController_createSubmission", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateSubmissionDto" } + } + } + }, + "responses": { + "201": { + "description": "Submission created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmissionResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Create a hackathon submission", + "tags": ["Hackathons - Submissions"] + } + }, + "/api/hackathons/{idOrSlug}/submissions/explore": { + "get": { + "description": "Retrieves all submissions for a hackathon for public viewing", + "operationId": "HackathonsSubmissionsController_exploreHackathonSubmissions", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-based)", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "search", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "type", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Submissions retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SubmissionResponseDto" + } + } + } + } + }, + "404": { "description": "Hackathon not found" } + }, + "summary": "Explore hackathon submissions", + "tags": ["Hackathons - Submissions"] + } + }, + "/api/hackathons/{idOrSlug}/my-submission": { + "get": { + "description": "Retrieve the current user's submission for a hackathon", + "operationId": "HackathonsSubmissionsController_getMySubmission", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Submission retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmissionResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get my submission for a hackathon", + "tags": ["Hackathons - Submissions"] + } + }, + "/api/hackathons/submissions/{submissionId}": { + "patch": { + "description": "Update your submission before the deadline", + "operationId": "HackathonsSubmissionsController_updateSubmission", + "parameters": [ + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "example": "sub_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateSubmissionDto" } + } + } + }, + "responses": { + "200": { + "description": "Submission updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmissionResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Update a hackathon submission", + "tags": ["Hackathons - Submissions"] + }, + "delete": { + "description": "Delete your submission before the deadline", + "operationId": "HackathonsSubmissionsController_deleteSubmission", + "parameters": [ + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "example": "sub_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Submission withdrawn successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Submission withdrawn successfully" + } + } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Withdraw a hackathon submission", + "tags": ["Hackathons - Submissions"] + }, + "get": { + "description": "Retrieve details of a specific submission", + "operationId": "HackathonsSubmissionsController_getSubmissionById", + "parameters": [ + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "example": "sub_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Submission retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmissionResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get a submission by ID", + "tags": ["Hackathons - Submissions"] + } + }, + "/api/hackathons/{id}/discussions": { + "get": { + "description": "Retrieve real-time comments and discussions for a hackathon", + "operationId": "HackathonsDiscussionsController_getHackathonDiscussions", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-based)", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort by field", + "schema": { "enum": ["createdAt", "updatedAt"], "type": "string" } + }, + { + "name": "sortOrder", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { "enum": ["asc", "desc"], "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { "description": "Discussions retrieved successfully" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get hackathon discussions", + "tags": ["Hackathons - Discussions"] + }, + "post": { + "description": "Create a new comment in the hackathon discussion thread", + "operationId": "HackathonsDiscussionsController_createHackathonComment", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["content"], + "properties": { + "content": { + "type": "string", + "description": "Comment content", + "example": "This hackathon looks amazing! When does registration open?" + }, + "parentId": { + "type": "string", + "description": "Parent comment ID for replies", + "example": "comment_1234567890" + } + } + } + } + } + }, + "responses": { + "201": { "description": "Comment posted successfully" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Post a comment in hackathon discussion", + "tags": ["Hackathons - Discussions"] + } + }, + "/api/hackathons/discussions/{commentId}": { + "patch": { + "description": "Edit your own comment in the hackathon discussion", + "operationId": "HackathonsDiscussionsController_updateHackathonComment", + "parameters": [ + { + "name": "commentId", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "example": "comment_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["content"], + "properties": { + "content": { + "type": "string", + "description": "Updated comment content", + "example": "Updated: This hackathon looks amazing!" + } + } + } + } + } + }, + "responses": { + "200": { "description": "Comment updated successfully" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Update a discussion comment", + "tags": ["Hackathons - Discussions"] + }, + "delete": { + "description": "Remove your own comment from the hackathon discussion", + "operationId": "HackathonsDiscussionsController_deleteHackathonComment", + "parameters": [ + { + "name": "commentId", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "example": "comment_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Comment deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Comment deleted successfully" + } + } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Delete a discussion comment", + "tags": ["Hackathons - Discussions"] + } + }, + "/api/hackathons/discussions/{commentId}/react": { + "post": { + "description": "Add or toggle a reaction (like, love, etc.) to a discussion comment", + "operationId": "HackathonsDiscussionsController_reactToComment", + "parameters": [ + { + "name": "commentId", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "example": "comment_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["reactionType"], + "properties": { + "reactionType": { + "type": "string", + "enum": ["LIKE", "LOVE", "CELEBRATE", "INSIGHTFUL"], + "description": "Type of reaction", + "example": "LIKE" + } + } + } + } + } + }, + "responses": { + "200": { "description": "Reaction updated" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "React to a comment", + "tags": ["Hackathons - Discussions"] + } + }, + "/api/hackathons/discussions/{commentId}/replies": { + "get": { + "description": "Retrieve replies to a specific comment", + "operationId": "HackathonsDiscussionsController_getCommentReplies", + "parameters": [ + { + "name": "commentId", + "required": true, + "in": "path", + "description": "Comment ID", + "schema": { "example": "comment_1234567890", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-based)", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 10, "type": "number" } + } + ], + "responses": { + "200": { "description": "Replies retrieved successfully" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get comment replies", + "tags": ["Hackathons - Discussions"] + } + }, + "/api/hackathons/{id}/teams": { + "get": { + "description": "Retrieve all teams for a hackathon with optional filtering", + "operationId": "HackathonsTeamsController_getHackathonTeams", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search query", + "schema": { "example": "DeFi", "type": "string" } + }, + { + "name": "openOnly", + "required": false, + "in": "query", + "description": "Filter by open teams only", + "schema": { "example": true, "type": "boolean" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "minimum": 1, "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { + "minimum": 1, + "maximum": 50, + "example": 10, + "type": "number" + } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "Teams retrieved successfully", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TeamListResponseDto" } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get hackathon teams", + "tags": ["Hackathons - Teams"] + }, + "post": { + "description": "Create a new team for the hackathon. Team is closed by default unless skills are specified.", + "operationId": "HackathonsTeamsController_createTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateTeamDto" } + } + } + }, + "responses": { + "201": { + "description": "Team created successfully", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TeamResponseDto" } + } + } + }, + "400": { + "description": "Not a participant, already in a team, or hackathon does not allow teams" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Create a team", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}": { + "get": { + "description": "Get detailed information about a specific team", + "operationId": "HackathonsTeamsController_getTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "Team found", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TeamResponseDto" } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get team details", + "tags": ["Hackathons - Teams"] + }, + "patch": { + "description": "Update team information (leader only). Team opens when skills are added, closes when removed.", + "operationId": "HackathonsTeamsController_updateTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateTeamDto" } + } + } + }, + "responses": { + "200": { "description": "Team updated" }, + "400": { "description": "Not team leader or invalid update" }, + "404": { "description": "Resource not found" } + }, + "summary": "Update team", + "tags": ["Hackathons - Teams"] + }, + "delete": { + "description": "Disband the team and remove all members. Refuses if the team has already submitted — withdraw the submission first.", + "operationId": "HackathonsTeamsController_disbandTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { "description": "Team disbanded" }, + "400": { + "description": "Team has an existing submission and cannot be disbanded" + }, + "403": { "description": "Only the team leader can disband the team" }, + "404": { "description": "Resource not found" } + }, + "summary": "Disband a team (leader only)", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}/join": { + "post": { + "description": "Join an existing open team", + "operationId": "HackathonsTeamsController_joinTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Optional message to team leader", + "example": "I have 5 years of Rust development experience" + } + } + } + } + } + }, + "responses": { + "200": { "description": "Successfully joined team" }, + "400": { + "description": "Team is closed, full, or user already in a team" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Join a team", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}/members/{userId}": { + "delete": { + "description": "Team leader removes a specific member. Leaders cannot remove themselves — they must transfer leadership first or disband the team.", + "operationId": "HackathonsTeamsController_removeTeamMember", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { "description": "Member removed from team" }, + "400": { + "description": "Target user is not a member, or leader tried to remove themselves" + }, + "403": { "description": "Only the team leader can remove members" }, + "404": { "description": "Resource not found" } + }, + "summary": "Remove a member from the team (leader only)", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}/leave": { + "post": { + "description": "Leave your current team. Leaders must transfer leadership first if team has other members.", + "operationId": "HackathonsTeamsController_leaveTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { "description": "Successfully left team" }, + "400": { + "description": "Not a member or leader cannot leave with members" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Leave a team", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/my-team": { + "get": { + "description": "Get your team in this hackathon", + "operationId": "HackathonsTeamsController_getMyTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "Team found or null if not in a team", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TeamResponseDto" } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get my team", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}/invite": { + "post": { + "description": "Team leader can invite hackathon participants to join the team. Invitation expires in 7 days.", + "operationId": "HackathonsTeamsController_inviteToTeam", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/InviteToTeamDto" } + } + } + }, + "responses": { + "201": { + "description": "Invitation sent successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamInvitationResponseDto" + } + } + } + }, + "400": { + "description": "User already in team, team full, or pending invitation exists" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Invite a user to join team", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/my-invitations": { + "get": { + "description": "Get all team invitations received by the current user", + "operationId": "HackathonsTeamsController_getMyInvitations", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by invitation status", + "schema": { + "enum": ["pending", "accepted", "rejected", "expired"], + "type": "string" + } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "List of invitations", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamInvitationListResponseDto" + } + } + } + } + }, + "summary": "Get my team invitations", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/invitations/{inviteId}/accept": { + "post": { + "description": "Accept a pending team invitation and join the team", + "operationId": "HackathonsTeamsController_acceptInvitation", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "inviteId", + "required": true, + "in": "path", + "description": "Invitation ID", + "schema": { "example": "inv_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "Successfully accepted invitation and joined team", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvitationActionResponseDto" + } + } + } + }, + "400": { + "description": "Invitation expired, already processed, or team full" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Accept team invitation", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/invitations/{inviteId}/reject": { + "post": { + "description": "Reject a pending team invitation", + "operationId": "HackathonsTeamsController_rejectInvitation", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "inviteId", + "required": true, + "in": "path", + "description": "Invitation ID", + "schema": { "example": "inv_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "Successfully rejected invitation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvitationActionResponseDto" + } + } + } + }, + "400": { "description": "Invitation already processed" }, + "404": { "description": "Resource not found" } + }, + "summary": "Reject team invitation", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/invitations/{inviteId}": { + "delete": { + "description": "Team leader can cancel a pending invitation", + "operationId": "HackathonsTeamsController_cancelInvitation", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "inviteId", + "required": true, + "in": "path", + "description": "Invitation ID", + "schema": { "example": "inv_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { "description": "Successfully cancelled invitation" }, + "400": { + "description": "Not team leader or invitation already processed" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Cancel team invitation", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}/invitations": { + "get": { + "description": "Team leader can view all invitations sent by the team (pending, accepted, rejected)", + "operationId": "HackathonsTeamsController_getTeamInvitations", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by invitation status", + "schema": { + "enum": ["pending", "accepted", "rejected", "expired"], + "type": "string" + } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "List of team invitations", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamInvitationListResponseDto" + } + } + } + }, + "400": { "description": "Only team leader can view" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get team invitations", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}/roles/toggle-hired": { + "patch": { + "description": "Team leader can toggle whether a role has been filled (hired) or is still open", + "operationId": "HackathonsTeamsController_toggleRoleHiredStatus", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ToggleRoleHiredDto" } + } + } + }, + "responses": { + "200": { "description": "Role status toggled successfully" }, + "400": { "description": "Not team leader or invalid role" }, + "404": { "description": "Resource not found" } + }, + "summary": "Toggle role hired status", + "tags": ["Hackathons - Teams"] + } + }, + "/api/hackathons/{id}/teams/{teamId}/transfer-leadership": { + "post": { + "description": "Current team leader can transfer leadership to another team member. This action is logged in audit logs for accountability.", + "operationId": "HackathonsTeamsController_transferLeadership", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "required": true, + "in": "path", + "description": "Team ID", + "schema": { "example": "team_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TransferLeadershipDto" } + } + } + }, + "responses": { + "200": { + "description": "Leadership successfully transferred", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LeadershipTransferResponseDto" + } + } + } + }, + "400": { + "description": "Not current leader, new leader not a member, or invalid request" + }, + "403": { + "description": "Only current team leader can transfer leadership" + }, + "404": { "description": "Resource not found" } + }, + "summary": "Transfer team leadership", + "tags": ["Hackathons - Teams"] + } + }, + "/api/organizations/{organizationId}/hackathons/draft/{id}": { + "delete": { + "description": "Deletes a hackathon draft by ID for an organization", + "operationId": "OrganizationHackathonsDraftsController_deleteDraft", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon draft ID to delete", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "204": { "description": "Draft deleted successfully" }, + "400": { "description": "Draft not found or user not authorized" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Delete hackathon draft", + "tags": ["Organization Hackathons - Drafts"] + }, + "patch": { + "description": "Applies any subset of wizard sections in a single PATCH. Send one section for a per-step \"Continue\", or several for \"Save draft\". Each present section is validated and transformed independently, then merged into one write.", + "operationId": "OrganizationHackathonsDraftsController_updateDraft", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon draft ID", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateHackathonDraftDto" + }, + "examples": { + "singleSection": { + "summary": "Update one section (per-step Continue)", + "value": { + "information": { + "name": "Web3 Innovation Hackathon", + "banner": "https://example.com/banner.jpg", + "description": "A hackathon for building the future of Web3", + "categories": ["DeFi", "NFTs"], + "venueType": "virtual", + "tagline": "Build the future of Web3" + } + } + }, + "multipleSections": { + "summary": "Update several sections (Save draft)", + "value": { + "information": { + "name": "Web3 Innovation Hackathon", + "banner": "https://example.com/banner.jpg", + "description": "A hackathon for building the future of Web3", + "categories": ["DeFi", "NFTs"], + "venueType": "virtual", + "tagline": "Build the future of Web3" + }, + "timeline": { + "startDate": "2024-02-01T00:00:00Z", + "submissionDeadline": "2024-02-03T18:00:00Z", + "timezone": "America/New_York" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Draft updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonDraftResponseDto" + } + } + } + }, + "400": { + "description": "Validation failed for one or more sections" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update one or more sections of a hackathon draft", + "tags": ["Organization Hackathons - Drafts"] + }, + "get": { + "description": "Retrieves the current state of a hackathon draft for editing", + "operationId": "OrganizationHackathonsDraftsController_getDraft", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon draft ID", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Draft retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonDraftResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get hackathon draft details", + "tags": ["Organization Hackathons - Drafts"] + } + }, + "/api/organizations/{organizationId}/hackathons": { + "get": { + "description": "Retrieves all published hackathons for an organization with pagination", + "operationId": "OrganizationHackathonsDraftsController_getOrganizationHackathons", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "page", + "required": true, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": true, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by hackathon status", + "schema": { + "enum": ["upcoming", "active", "ended"], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Hackathons retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonsListResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Get organization's published hackathons", + "tags": ["Organization Hackathons - Drafts"] + } + }, + "/api/organizations/{organizationId}/hackathons/draft": { + "post": { + "description": "Creates a new hackathon in draft status that can be edited by organization members", + "operationId": "OrganizationHackathonsDraftsController_createDraft", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "responses": { + "201": { + "description": "Draft created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonDraftResponseDto" + } + } + } + }, + "400": { "description": "User is not a member of the organization" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Create a new hackathon draft for an organization", + "tags": ["Organization Hackathons - Drafts"] + } + }, + "/api/organizations/{organizationId}/hackathons/drafts": { + "get": { + "description": "Retrieves all draft hackathons for an organization that the user has access to", + "operationId": "OrganizationHackathonsDraftsController_getOrganizationDrafts", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Drafts retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HackathonDraftResponseDto" + } + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Get organization's hackathon drafts", + "tags": ["Organization Hackathons - Drafts"] + } + }, + "/api/organizations/{organizationId}/hackathons/draft/{id}/publish": { + "put": { + "description": "Validates and publishes a complete hackathon draft, making it publicly visible", + "operationId": "OrganizationHackathonsDraftsController_publishDraft", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon draft ID to publish", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/PublishDraftDto" } + } + } + }, + "responses": { + "200": { + "description": "Hackathon published successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublishHackathonResponseDto" + } + } + } + }, + "400": { "description": "Validation failed - draft incomplete" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Publish hackathon draft", + "tags": ["Organization Hackathons - Drafts"] + } + }, + "/api/organizations/{organizationId}/hackathons/hackathons/{id}/announcement-preview": { + "get": { + "description": "Returns the number of recipients that would receive the launch announcement email if the hackathon were published right now. Useful for the publish UI.", + "operationId": "OrganizationHackathonsDraftsController_previewAnnouncementAudience", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon (or draft) ID", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Audience size preview" } }, + "security": [{ "bearer": [] }], + "summary": "Preview the marketing announcement audience size", + "tags": ["Organization Hackathons - Drafts"] + } + }, + "/api/organizations/{organizationId}/hackathons/draft/{id}/escrow/retry-funding": { + "post": { + "description": "Retries funding for a deployed escrow using stored escrow details", + "operationId": "OrganizationHackathonsDraftsController_retryEscrowFunding", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon draft ID to retry funding", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Escrow funding retried successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Escrow funded successfully" + }, + "escrowStatus": { "type": "string", "example": "funded" }, + "escrowAddress": { + "type": "string", + "example": "ESCROW_CONTRACT_ID" + }, + "transactionHash": { + "type": "string", + "example": "TX_HASH" + } + } + } + } + } + }, + "400": { + "description": "Escrow not ready, missing details, or insufficient balance" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Retry hackathon escrow funding", + "tags": ["Organization Hackathons - Drafts"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/visibility": { + "patch": { + "description": "Allows organizers to change who can view submissions and which statuses are visible.", + "operationId": "OrganizationHackathonsSubmissionsController_updateVisibilitySettings", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateVisibilitySettingsDto" + } + } + } + }, + "responses": { + "200": { + "description": "Visibility settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonDraftResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Update hackathon submission visibility settings", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/review": { + "patch": { + "description": "Update submission status (shortlist or move back to submitted). Organizer only.", + "operationId": "OrganizationHackathonsSubmissionsController_reviewSubmission", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "example": "sub_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ReviewSubmissionDto" } + } + } + }, + "responses": { + "200": { + "description": "Submission reviewed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Submission reviewed successfully" + }, + "submission": { "type": "object" } + } + } + } + } + }, + "400": { + "description": "Invalid status or submission does not belong to hackathon" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Review a submission", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/participants": { + "get": { + "description": "Returns detailed participant data for organizers, including submission details.", + "operationId": "OrganizationHackathonsSubmissionsController_getOrganizationHackathonParticipants", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-based)", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 12, "type": "number" } + }, + { + "name": "search", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "status", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "type", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Participants retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationHackathonParticipantsResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get hackathon participants (organization)", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/score-override": { + "post": { + "description": "Organizer directly assigns criterion-based scores to a submission. Validates rubric compliance but bypasses judge assignment and conflict-of-interest checks. Use when correcting judge scores or assigning administrative evaluations. Organizer only.", + "operationId": "OrganizationHackathonsSubmissionsController_scoreSubmissionOverride", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "example": "sub_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "judgeId": { + "type": "string", + "description": "Judge ID to credit with these scores (optional, defaults to organizer)", + "example": "user_1234567890" + }, + "criteriaScores": { + "type": "array", + "description": "Scores for each criterion" + } + }, + "required": ["criteriaScores"] + } + } + } + }, + "responses": { + "200": { + "description": "Submission score override applied successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Submission scored successfully (organizer override)" + }, + "judgingScore": { "type": "object" }, + "complianceChecks": { + "type": "object", + "properties": { + "rubricValid": { "type": "boolean" }, + "isOrganizerOverride": { "type": "boolean" } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid criteria scores or rubric validation failed" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Organizer: Override submission scoring", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/disqualify": { + "post": { + "description": "Mark a submission as disqualified with a reason. Organizer only.", + "operationId": "OrganizationHackathonsSubmissionsController_disqualifySubmission", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "example": "sub_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisqualifySubmissionDto" + } + } + } + }, + "responses": { + "200": { + "description": "Submission disqualified successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Submission disqualified successfully" + }, + "submission": { "type": "object" } + } + } + } + } + }, + "400": { "description": "Submission does not belong to hackathon" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Disqualify a submission", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/bulk-action": { + "post": { + "description": "Update status of multiple submissions at once (shortlist, approve, disqualify). Organizer only.", + "operationId": "OrganizationHackathonsSubmissionsController_bulkSubmissionAction", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkSubmissionActionDto" + } + } + } + }, + "responses": { + "200": { + "description": "Bulk action completed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Successfully updated 5 submission(s)" + }, + "count": { "type": "number", "example": 5 }, + "action": { "type": "string", "example": "SHORTLISTED" } + } + } + } + } + }, + "400": { "description": "Invalid action or missing required fields" } + }, + "security": [{ "bearer": [] }], + "summary": "Perform bulk action on submissions", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/submissions/{submissionId}/rank": { + "patch": { + "description": "Assign a rank to a submission for leaderboard positioning. Organizer only.", + "operationId": "OrganizationHackathonsSubmissionsController_setSubmissionRank", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "example": "sub_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "rank": { "type": "number", "example": 1, "minimum": 1 } + }, + "required": ["rank"] + } + } + } + }, + "responses": { + "200": { + "description": "Submission rank updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Submission rank updated successfully" + }, + "submission": { "type": "object" } + } + } + } + } + }, + "400": { + "description": "Invalid rank or submission does not belong to hackathon" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Set submission rank", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/analytics": { + "get": { + "description": "Retrieves summary metrics, trend data, and timeline for a hackathon. Organizer only.", + "operationId": "OrganizationHackathonsSubmissionsController_getAnalytics", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "Analytics retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonAnalyticsResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "403": { "description": "Forbidden - only organizers can access" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get hackathon analytics", + "tags": ["Organization Hackathons - Submissions"] + } + }, + "/api/hackathons/{idOrSlug}/announcements": { + "get": { + "description": "Retrieves all announcements for a hackathon. Drafts are only visible to organizers.", + "operationId": "HackathonsAnnouncementsController_getAnnouncements", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-based)", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + } + ], + "responses": { + "200": { + "description": "Announcements retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AnnouncementResponseDto" + } + } + } + } + } + }, + "summary": "Get hackathon announcements", + "tags": ["Hackathons - Announcements"] + } + }, + "/api/hackathons/announcements/{announcementId}": { + "get": { + "description": "Retrieves details of a specific announcement", + "operationId": "HackathonsAnnouncementsController_getAnnouncement", + "parameters": [ + { + "name": "announcementId", + "required": true, + "in": "path", + "description": "Announcement ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Announcement retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnnouncementResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get announcement details", + "tags": ["Hackathons - Announcements"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/announcements": { + "post": { + "description": "Creates a new announcement for an organization hackathon", + "operationId": "OrganizationHackathonsAnnouncementsController_createAnnouncement", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateAnnouncementDto" } + } + } + }, + "responses": { + "201": { + "description": "Announcement created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnnouncementResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Create a hackathon announcement", + "tags": ["Organization Hackathons - Announcements"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/announcements/{announcementId}": { + "patch": { + "description": "Updates an existing announcement for an organization hackathon", + "operationId": "OrganizationHackathonsAnnouncementsController_updateAnnouncement", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "announcementId", + "required": true, + "in": "path", + "description": "Announcement ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateAnnouncementDto" } + } + } + }, + "responses": { + "200": { + "description": "Announcement updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnnouncementResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update a hackathon announcement", + "tags": ["Organization Hackathons - Announcements"] + }, + "delete": { + "description": "Deletes an announcement for an organization hackathon", + "operationId": "OrganizationHackathonsAnnouncementsController_deleteAnnouncement", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "announcementId", + "required": true, + "in": "path", + "description": "Announcement ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Announcement deleted successfully" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Delete a hackathon announcement", + "tags": ["Organization Hackathons - Announcements"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/announcements/{announcementId}/publish": { + "post": { + "description": "Publishes a draft announcement for an organization hackathon", + "operationId": "OrganizationHackathonsAnnouncementsController_publishAnnouncement", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "announcementId", + "required": true, + "in": "path", + "description": "Announcement ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Announcement published successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnnouncementResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Publish a draft announcement", + "tags": ["Organization Hackathons - Announcements"] + } + }, + "/api/hackathons/{idOrSlug}/judging/criteria": { + "get": { + "description": "Retrieves the criteria used for judging this hackathon", + "operationId": "HackathonsJudgingController_getCriteria", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or Slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Criteria retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/CriterionDto" } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "Get hackathon judging criteria", + "tags": ["Hackathons - Judging"] + } + }, + "/api/hackathons/judging/score": { + "post": { + "description": "Allows an assigned judge to submit criterion-based scores for a submission. Enforces: (1) judge assignment verification, (2) conflict-of-interest checks, (3) rubric compliance validation.", + "operationId": "HackathonsJudgingController_submitScore", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ScoreSubmissionDto" } + } + } + }, + "responses": { + "201": { + "description": "Score submitted successfully with compliance verification", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" }, + "judgingScore": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "totalScore": { "type": "number" }, + "criteriaScores": { "type": "array" } + } + }, + "complianceChecks": { + "type": "object", + "properties": { + "judgeAssigned": { "type": "boolean" }, + "noConflictOfInterest": { "type": "boolean" }, + "rubricValid": { "type": "boolean" } + } + } + } + } + } + } + }, + "400": { + "description": "Judge not assigned, conflict of interest detected, or invalid scores" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Judge: Submit criterion-based scores", + "tags": ["Hackathons - Judging"] + } + }, + "/api/hackathons/{idOrSlug}/judging/submissions": { + "get": { + "description": "Retrieves shortlisted submissions with the current judge's scores and criteria", + "operationId": "HackathonsJudgingController_getJudgingSubmissions", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or Slug", + "schema": { "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-indexed)", + "schema": { "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of items per page", + "schema": { "maximum": 100, "default": 10, "type": "number" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search term for project name, description, participant name or username", + "schema": { "type": "string" } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort field", + "schema": { + "default": "date", + "type": "string", + "enum": ["date", "name", "score", "rank"] + } + }, + { + "name": "order", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { + "default": "desc", + "type": "string", + "enum": ["asc", "desc"] + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JudgingSubmissionsResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get submissions for judging", + "tags": ["Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/judges": { + "post": { + "description": "Assigns a user as a judge for the hackathon", + "operationId": "OrganizationHackathonsJudgingController_addJudge", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AddJudgeDto" } + } + } + }, + "responses": { + "201": { + "description": "Judge added successfully", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/JudgeResponseDto" } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Add a judge to a hackathon", + "tags": ["Organization Hackathons - Judging"] + }, + "get": { + "description": "Retrieves the list of judges assigned to the hackathon", + "operationId": "OrganizationHackathonsJudgingController_getJudges", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Judges retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/JudgeResponseDto" } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get hackathon judges", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/judges/{userId}": { + "delete": { + "description": "Removes a user from the judging panel", + "operationId": "OrganizationHackathonsJudgingController_removeJudge", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "userId", + "required": true, + "in": "path", + "description": "User ID of the judge", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Judge removed successfully" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Remove a judge from a hackathon", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/results": { + "get": { + "description": "Retrieves the ranked results for the hackathon based on judging scores", + "operationId": "OrganizationHackathonsJudgingController_getResults", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-indexed)", + "schema": { "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of items per page", + "schema": { "default": 50, "type": "number" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search term for project name, participant name or username", + "schema": { "type": "string" } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort field", + "schema": { + "default": "score", + "type": "string", + "enum": ["score", "name", "rank", "date"] + } + }, + { + "name": "order", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { + "default": "desc", + "type": "string", + "enum": ["asc", "desc"] + } + }, + { + "name": "onlyWinners", + "required": false, + "in": "query", + "description": "If true, only returns submissions that have been assigned a rank", + "schema": { "default": false, "type": "boolean" } + } + ], + "responses": { + "200": { + "description": "Results retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JudgingResultsResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get aggregated judging results", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/submissions/{submissionId}/scores": { + "get": { + "description": "Retrieves all judge scores and comments for a project", + "operationId": "OrganizationHackathonsJudgingController_getIndividualScores", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "ID of the submission", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndividualJudgingResultDto" + } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get individual judge scores for a submission", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/winners": { + "get": { + "description": "Retrieves the ranked results sorted by average score", + "operationId": "OrganizationHackathonsJudgingController_getWinnerRanking", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-indexed)", + "schema": { "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of items per page", + "schema": { "default": 50, "type": "number" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search term for project name, participant name or username", + "schema": { "type": "string" } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort field", + "schema": { + "default": "score", + "type": "string", + "enum": ["score", "name", "rank", "date"] + } + }, + { + "name": "order", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { + "default": "desc", + "type": "string", + "enum": ["asc", "desc"] + } + }, + { + "name": "onlyWinners", + "required": false, + "in": "query", + "description": "If true, only returns submissions that have been assigned a rank", + "schema": { "default": false, "type": "boolean" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AggregatedJudgingResultDto" + } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get winner ranking", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/coverage": { + "get": { + "description": "Returns every shortlisted submission with the set of active judges who scored it, plus per-judge totals. Used by the organizer dashboard to render a heatmap that surfaces idle judges (columns of mostly empty cells) and orphan submissions (rows with 0-1 scores) at a glance — both block a defensible publish. The view-only `/completeness` endpoint stays unchanged for the publish-confirmation flow.", + "operationId": "OrganizationHackathonsJudgingController_judgingCoverage", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Full judges × submissions coverage matrix", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/preview-allocation": { + "get": { + "description": "Read-only dry run of the publish-results allocator. Returns the overall placements + per-track winners that would be stamped on publish, including EXCLUSIVE stacking effects (a track leader losing because they already claimed an overall placement). Also surfaces the publish gates (deadline, completeness, partner allocation) so the UI can render a \"what is blocking publish?\" panel without trying to publish.", + "operationId": "OrganizationHackathonsJudgingController_previewAllocation", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Preview the allocator outcome before publishing", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/completeness": { + "get": { + "description": "Returns which submissions are short any active judge, and which judges still have outstanding work. The frontend uses this to render the publish-results confirmation dialog before the organizer commits.", + "operationId": "OrganizationHackathonsJudgingController_judgingCompleteness", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Preview judging completeness", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/publish-results": { + "post": { + "description": "Finalizes the ranks and marks results as public. Rejects (400) if any active judge has not scored every shortlisted submission, unless the request body includes `acceptPartial: true`.", + "operationId": "OrganizationHackathonsJudgingController_publishResults", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "200": { "description": "Results published successfully" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Publish results", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/invitations": { + "post": { + "description": "Sends an email-based invitation. The recipient is NOT added to the organization; on acceptance they become a hackathon-scoped judge only.", + "operationId": "OrganizationHackathonsJudgingController_inviteJudge", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/InviteJudgeDto" } + } + } + }, + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Invite a judge by email", + "tags": ["Organization Hackathons - Judging"] + }, + "get": { + "operationId": "OrganizationHackathonsJudgingController_listInvitations", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "List judge invitations for this hackathon", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/invitations/{invitationId}": { + "delete": { + "operationId": "OrganizationHackathonsJudgingController_cancelInvitation", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "invitationId", + "required": true, + "in": "path", + "description": "Invitation ID", + "schema": { "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Cancel (revoke) a pending judge invitation", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/organizations/{organizationId}/hackathons/{idOrSlug}/judging/invitations/{invitationId}/resend": { + "post": { + "description": "Rotates the invitation token so any previously-leaked link is invalidated, then re-emails the recipient.", + "operationId": "OrganizationHackathonsJudgingController_resendInvitation", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890", "type": "string" } + }, + { + "name": "invitationId", + "required": true, + "in": "path", + "description": "Invitation ID", + "schema": { "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Resend a pending judge invitation", + "tags": ["Organization Hackathons - Judging"] + } + }, + "/api/judge/invitations": { + "get": { + "description": "Returns pending, non-expired invitations sent to the authenticated user's email.", + "operationId": "JudgeController_myInvitations", + "parameters": [], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "List my pending judge invitations", + "tags": ["Judge"] + } + }, + "/api/judge/invitations/{token}": { + "get": { + "description": "Public endpoint so an invitee can see who invited them and which hackathon before signing in. Reveals only the invitation summary — never anything that requires auth.", + "operationId": "JudgeController_previewInvitation", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Opaque invitation token", + "schema": { "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Preview an invitation by token", + "tags": ["Judge"] + } + }, + "/api/judge/invitations/{token}/accept": { + "post": { + "description": "Creates the HackathonJudge assignment. The authenticated user is NOT added to the hosting organization — judge access is hackathon-scoped only.", + "operationId": "JudgeController_acceptInvitation", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Opaque invitation token", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcceptJudgeInvitationDto" + } + } + } + }, + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Accept a judge invitation", + "tags": ["Judge"] + } + }, + "/api/judge/invitations/{token}/decline": { + "post": { + "operationId": "JudgeController_declineInvitation", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Opaque invitation token", + "schema": { "type": "string" } + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Decline a judge invitation", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons": { + "get": { + "description": "Returns all hackathons where the authenticated user has an active judge assignment.", + "operationId": "JudgeController_myHackathons", + "parameters": [], + "responses": { + "200": { "description": "Assigned hackathons" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "List hackathons I'm assigned to judge", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons/{hackathonId}": { + "get": { + "description": "Returns hackathon overview tailored to a judge: dates, criteria, my progress. Never includes peer signals or organization-management data.", + "operationId": "JudgeController_overview", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": {} + } + ], + "responses": { + "200": { "description": "Hackathon overview" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get judge-scoped hackathon overview", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons/{hackathonId}/submissions": { + "get": { + "description": "Returns shortlisted submissions with only the calling judge's own scores. Peer-derived signals (averageScore, judgeCount) are intentionally omitted to preserve blind scoring.", + "operationId": "JudgeController_submissions", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-indexed)", + "schema": { "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of items per page", + "schema": { "maximum": 100, "default": 10, "type": "number" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search term for project name, description, participant name or username", + "schema": { "type": "string" } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort field", + "schema": { + "default": "date", + "type": "string", + "enum": ["date", "name", "score", "rank"] + } + }, + { + "name": "order", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { + "default": "desc", + "type": "string", + "enum": ["asc", "desc"] + } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": {} + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JudgingSubmissionsResponseDto" + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "List submissions for scoring", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons/{hackathonId}/submissions/{submissionId}": { + "get": { + "description": "Returns a single submission plus the calling judge's own score (if any). Peer scores remain hidden until results are published.", + "operationId": "JudgeController_submission", + "parameters": [ + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": {} + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get one submission with my score", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons/{hackathonId}/submissions/{submissionId}/neighbors": { + "get": { + "description": "Returns the previous and next submissions in the canonical queue, plus the next unscored one (wrapping to the start if needed), plus totals. Single round trip so the scoring page can render \"X of N\" and auto-advance without fetching the full queue.", + "operationId": "JudgeController_neighbors", + "parameters": [ + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": {} + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Queue neighbors for the scoring page", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons/{hackathonId}/criteria": { + "get": { + "operationId": "JudgeController_criteria", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": {} + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get judging criteria for this hackathon", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons/{hackathonId}/results": { + "get": { + "description": "Returns the published ranking. Returns `{ resultsPublished: false, results: [] }` until the organizer publishes — never leaks scores prematurely.", + "operationId": "JudgeController_results", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": {} + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Final results for this hackathon", + "tags": ["Judge"] + } + }, + "/api/judge/hackathons/{hackathonId}/submissions/{submissionId}/score": { + "post": { + "description": "Upserts the calling judge's scores for the given submission. Rubric validation and the judging window are enforced by the underlying service.", + "operationId": "JudgeController_score", + "parameters": [ + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "Submission ID", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": {} + } + ], + "responses": { + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Submit (or update) my scores for a submission", + "tags": ["Judge"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/statistics": { + "get": { + "description": "Retrieves participation and engagement statistics for a hackathon. Only organizers of the hackathon can access this.", + "operationId": "OrganizationHackathonsUpdatesController_getHackathonStatistics", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "responses": { + "200": { + "description": "Statistics retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "totalSubmissions": { "type": "number", "example": 45 }, + "activeParticipants": { "type": "number", "example": 120 }, + "totalFollowers": { "type": "number", "example": 340 }, + "prizePool": { "type": "number", "example": 50000 }, + "categories": { + "type": "array", + "items": { "type": "string" } + }, + "status": { "type": "string", "example": "active" } + } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get hackathon statistics (organizers only)", + "tags": ["Organization Hackathons - Updates"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/content": { + "patch": { + "description": "Updates published hackathon information and/or collaboration data.", + "operationId": "OrganizationHackathonsUpdatesController_updatePublishedContent", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePublishedHackathonContentDto" + } + } + } + }, + "responses": { + "200": { + "description": "Published hackathon content updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonResponseDto" + } + } + } + }, + "400": { "description": "Invalid payload or hackathon state" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update published hackathon content", + "tags": ["Organization Hackathons - Updates"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/schedule": { + "patch": { + "description": "Updates published hackathon timeline and/or participation settings.", + "operationId": "OrganizationHackathonsUpdatesController_updatePublishedSchedule", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePublishedHackathonScheduleDto" + } + } + } + }, + "responses": { + "200": { + "description": "Published hackathon schedule updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonResponseDto" + } + } + } + }, + "400": { + "description": "Invalid payload or schedule changes are no longer allowed" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update published hackathon schedule", + "tags": ["Organization Hackathons - Updates"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/financial": { + "patch": { + "description": "Updates published hackathon rewards data with escrow safety checks.", + "operationId": "OrganizationHackathonsUpdatesController_updatePublishedFinancial", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePublishedHackathonFinancialDto" + } + } + } + }, + "responses": { + "200": { + "description": "Published hackathon financial settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonResponseDto" + } + } + } + }, + "400": { + "description": "Invalid payload or escrow-restricted financial change" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update published hackathon financial settings", + "tags": ["Organization Hackathons - Updates"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/financial/preview": { + "post": { + "description": "Calculates the exact USDC cost of a proposed reward update without\nmaking any changes to escrow state or the wallet.\n\nReturns a per-tier breakdown plus the total additional funding required,\nthe current wallet balance, and whether the balance is sufficient.\n\nCall this **before** `PATCH /financial` to power a confirmation step in\nthe UI and avoid surprising the organizer with an insufficient-balance error.", + "operationId": "OrganizationHackathonsUpdatesController_previewPublishedFinancial", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePublishedHackathonFinancialDto" + } + } + } + }, + "responses": { + "200": { + "description": "Cost preview computed successfully (no changes made)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "currentPrizePool": { "type": "number", "example": 180 }, + "newPrizePool": { "type": "number", "example": 250 }, + "currentPlatformFee": { "type": "number", "example": 8.5 }, + "newPlatformFee": { "type": "number", "example": 11.8 }, + "currentTotalRequired": { + "type": "number", + "example": 188.5 + }, + "newTotalRequired": { "type": "number", "example": 261.8 }, + "additionalFundingRequired": { + "type": "number", + "example": 73.3 + }, + "walletBalance": { + "type": "number", + "nullable": true, + "example": 78.8 + }, + "sufficient": { "type": "boolean", "example": true }, + "shortfall": { "type": "number", "example": 0 }, + "escrowStatus": { + "type": "string", + "nullable": true, + "example": "funded" + }, + "breakdown": { + "type": "array", + "items": { + "type": "object", + "properties": { + "place": { "type": "string", "example": "1st Place" }, + "amount": { "type": "number", "example": 50 }, + "fee": { "type": "number", "example": 2.25 }, + "total": { "type": "number", "example": 52.25 } + } + } + } + } + } + } + } + }, + "400": { "description": "Invalid payload or hackathon state" }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Preview financial update cost (dry-run)", + "tags": ["Organization Hackathons - Updates"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/advanced-settings": { + "patch": { + "description": "Updates published hackathon advanced settings in metadata for frontend behavior controls.", + "operationId": "OrganizationHackathonsUpdatesController_updatePublishedAdvancedSettings", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "example": "hack_1234567890" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePublishedHackathonAdvancedSettingsDto" + } + } + } + }, + "responses": { + "200": { + "description": "Published hackathon advanced settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonResponseDto" + } + } + } + }, + "400": { + "description": "Invalid payload or unsupported hackathon state" + }, + "404": { "description": "Resource not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update published hackathon advanced settings", + "tags": ["Organization Hackathons - Updates"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/rewards/trigger": { + "post": { + "description": "\n Start a new reward distribution workflow. Requirements:\n - Hackathon results must be published\n - You must be the hackathon organizer\n - Idempotency key prevents duplicate processing (same key = same distribution returned)\n \n Milestone A: Creates immutable snapshot of winners + totals, moves to PENDING_ADMIN_REVIEW.\n Milestone B will add execution/release phase.\n ", + "operationId": "OrganizationHackathonsRewardsController_triggerRewardDistribution", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "UUID of your organization", + "schema": { + "example": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5", + "type": "string" + } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "UUID or slug of the hackathon", + "schema": { "example": "my-hackatho-2024", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRewardDistributionDto" + } + } + } + }, + "responses": { + "201": { + "description": "Distribution triggered successfully (or returned existing)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RewardDistributionResponseDto" + } + } + } + }, + "400": { + "description": "Results not published, wrong currency, no prize tiers, no winners" + }, + "403": { + "description": "Not authorized as organization member/organizer" + }, + "404": { "description": "Hackathon not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Trigger reward distribution (organizer)", + "tags": ["Hackathons - Organizer Rewards"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/rewards/status": { + "get": { + "description": "\n Fetch the current status of the active reward distribution.\n Returns latest PENDING_ADMIN_REVIEW, APPROVED, REJECTED, or EXECUTING state.\n ", + "operationId": "OrganizationHackathonsRewardsController_getRewardDistributionStatus", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "UUID of your organization", + "schema": { + "example": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5", + "type": "string" + } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "UUID or slug of the hackathon", + "schema": { "example": "my-hackatho-2024", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Current distribution status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RewardDistributionResponseDto" + } + } + } + }, + "403": { "description": "Not authorized as organizer" }, + "404": { + "description": "Hackathon not found or no active distribution" + } + }, + "security": [{ "bearer": [] }], + "summary": "Get reward distribution status (organizer)", + "tags": ["Hackathons - Organizer Rewards"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/rewards/escrow": { + "get": { + "description": "\n Fetches current balance and milestones for the hackathon escrow from the indexer.\n Requires organizer permissions.\n ", + "operationId": "OrganizationHackathonsRewardsController_getHackathonEscrow", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "UUID of your organization", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "UUID or slug of the hackathon", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Escrow details retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowResponseDto" + } + } + } + }, + "403": { "description": "Not authorized as organizer" }, + "404": { "description": "Hackathon not found or no escrow address" } + }, + "security": [{ "bearer": [] }], + "summary": "Get hackathon escrow details (organizer)", + "tags": ["Hackathons - Organizer Rewards"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/export": { + "get": { + "description": "Export hackathon data as a **CSV** or a **branded PDF**.\n\n**CSV** — A multi-section spreadsheet-compatible file with UTF-8 BOM for\nExcel compatibility. Sections: Overview, Prize Tiers, Participants, Submissions, Winners, Judging.\n\n**PDF** — A professionally branded Boundless report including cover header,\nkey-metric stat cards, and data tables. Dark brand palette with mint accent.\n\nUse the `dataset` param to limit which sections are included.\n\n> Only hackathon organizers (organization managers) can use this endpoint.", + "operationId": "OrganizationHackathonsExportController_exportHackathon", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "ID of the organization that owns the hackathon", + "schema": { + "example": "80rqXbamjejCavjlmAPdETWEHCxMAV4o", + "type": "string" + } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "ID or slug of the hackathon", + "schema": { + "example": "cmmex7d27000f01qpjhpnw1sd", + "type": "string" + } + }, + { + "name": "format", + "required": true, + "in": "query", + "description": "Output format", + "schema": { "enum": ["csv", "pdf"], "type": "string" } + }, + { + "name": "dataset", + "required": false, + "in": "query", + "description": "Dataset scope. Defaults to \"full\" (all sections).", + "schema": { + "enum": [ + "overview", + "participants", + "submissions", + "prize_tiers", + "winners", + "judging", + "full" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Binary file stream (CSV or PDF)", + "content": { + "text/csv": { + "schema": { "type": "string", "format": "binary" } + }, + "application/pdf": { + "schema": { "type": "string", "format": "binary" } + } + } + }, + "400": { "description": "Unsupported format or dataset" }, + "403": { "description": "Not an organizer of this hackathon" }, + "404": { "description": "Hackathon not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Export hackathon data (organizer only)", + "tags": ["Organization Hackathons - Export"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/invite": { + "post": { + "operationId": "OrganizationHackathonsPartnersController_invite", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/InvitePartnerDto" } + } + } + }, + "responses": { + "201": { "description": "Invitation created and email sent" } + }, + "security": [{ "bearer": [] }], + "summary": "Invite a partner to contribute to the hackathon prize pool", + "tags": ["Hackathons - Organizer Partners"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions": { + "get": { + "operationId": "OrganizationHackathonsPartnersController_list", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID", + "schema": { "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "schema": { + "type": "string", + "enum": [ + "PENDING", + "CONFIRMED", + "FAILED", + "REFUNDED", + "CANCELLED" + ] + } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "default": 50, "type": "number" } + } + ], + "responses": { "200": { "description": "Contributions retrieved" } }, + "security": [{ "bearer": [] }], + "summary": "List partner contributions for a hackathon", + "tags": ["Hackathons - Organizer Partners"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions/{contributionId}": { + "delete": { + "operationId": "OrganizationHackathonsPartnersController_cancel", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "Hackathon ID", + "schema": { "type": "string" } + }, + { + "name": "contributionId", + "required": true, + "in": "path", + "description": "Contribution ID", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Invitation cancelled" } }, + "security": [{ "bearer": [] }], + "summary": "Cancel a pending partner invitation", + "tags": ["Hackathons - Organizer Partners"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions/{contributionId}/allocations": { + "get": { + "description": "Returns the pledged amount, allocatable (after Trustless Work fee), already allocated, remaining unallocated, and the list of individual allocations.", + "operationId": "OrganizationHackathonsPartnersController_getAllocations", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "contributionId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Allocation summary" } }, + "security": [{ "bearer": [] }], + "summary": "Get allocation summary for a contribution", + "tags": ["Hackathons - Organizer Partners"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/contributions/{contributionId}/allocate": { + "post": { + "description": "Distributes the contribution amount into one or more prize tiers — either inflating existing tiers or creating new ones. The sum of allocations cannot exceed the remaining allocatable amount.", + "operationId": "OrganizationHackathonsPartnersController_allocate", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "contributionId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllocateContributionDto" + } + } + } + }, + "responses": { "200": { "description": "Contribution allocated" } }, + "security": [{ "bearer": [] }], + "summary": "Allocate a partner contribution into prize tiers", + "tags": ["Hackathons - Organizer Partners"] + } + }, + "/api/organizations/{organizationId}/hackathons/{hackathonId}/partners/allocations/{allocationId}": { + "delete": { + "description": "Reverses an allocation, decrementing the prize tier amount and removing the tier if it was created by the allocation and no longer has any remaining amount.", + "operationId": "OrganizationHackathonsPartnersController_undoAllocation", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "allocationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Allocation undone" } }, + "security": [{ "bearer": [] }], + "summary": "Undo a single allocation", + "tags": ["Hackathons - Organizer Partners"] + } + }, + "/api/partners/contribute/{token}": { + "get": { + "operationId": "PartnersContributeController_getByToken", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Hex-encoded invite token", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Invitation details" } }, + "summary": "Get partner invitation details by token (public, tokenized)", + "tags": ["Partner Contributions"] + } + }, + "/api/partners/contribute/{token}/prepare-fund-tx": { + "post": { + "description": "Validates the contribution window, calls Trustless Work, and returns an unsigned XDR for the partner wallet to sign locally. The Trustless Work API key never leaves the backend.", + "operationId": "PartnersContributeController_prepareFundTx", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Hex-encoded invite token", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrepareFundTransactionDto" + } + } + } + }, + "responses": { + "200": { "description": "Unsigned transaction prepared" } + }, + "summary": "Build an unsigned Trustless Work fund-escrow transaction", + "tags": ["Partner Contributions"] + } + }, + "/api/partners/contribute/{token}/submit-tx": { + "post": { + "description": "Forwards the signed XDR to Trustless Work, then marks the contribution confirmed using the Stellar transaction hash returned.", + "operationId": "PartnersContributeController_submitTx", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Hex-encoded invite token", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitSignedTransactionDto" + } + } + } + }, + "responses": { "200": { "description": "Contribution confirmed" } }, + "summary": "Submit a partner-signed transaction and confirm the contribution", + "tags": ["Partner Contributions"] + } + }, + "/api/hackathons/{idOrSlug}/tracks": { + "get": { + "description": "Returns the public list of tracks for a hackathon. Archived tracks are hidden by default; pass includeArchived=true to see them (useful for organizer dashboards).", + "operationId": "HackathonsTracksController_listTracks", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "type": "string" } + }, + { + "name": "includeArchived", + "required": false, + "in": "query", + "description": "Set true to include archived tracks.", + "schema": { "type": "boolean" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackResponseDto" } + } + } + } + }, + "400": { "description": "Invalid request" }, + "404": { "description": "Resource not found" } + }, + "summary": "List hackathon tracks", + "tags": ["Hackathons - Tracks"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/tracks": { + "get": { + "description": "Returns the full set of tracks for this hackathon, including archived ones by default. Use ?includeArchived=false to hide them.", + "operationId": "OrganizationHackathonsTracksController_list", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon ID or slug", + "schema": { "type": "string" } + }, + { + "name": "includeArchived", + "required": false, + "in": "query", + "schema": { "type": "boolean" } + }, + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": {} + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackResponseDto" } + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "List tracks (organizer view)", + "tags": ["Hackathons - Organizer Tracks"] + }, + "post": { + "operationId": "OrganizationHackathonsTracksController_create", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateTrackDto" } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TrackResponseDto" } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Create a track", + "tags": ["Hackathons - Organizer Tracks"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/tracks/{trackId}": { + "patch": { + "operationId": "OrganizationHackathonsTracksController_update", + "parameters": [ + { + "name": "trackId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateTrackDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TrackResponseDto" } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Update a track", + "tags": ["Hackathons - Organizer Tracks"] + }, + "delete": { + "description": "Hard-deletes the track if no submissions are entered. If submissions have already opted in, archives the track instead (preserves history).", + "operationId": "OrganizationHackathonsTracksController_remove", + "parameters": [ + { + "name": "trackId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "204": { "description": "Deleted or archived" } }, + "security": [{ "bearer": [] }], + "summary": "Delete a track", + "tags": ["Hackathons - Organizer Tracks"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/tracks/{trackId}/bulk-opt-in": { + "post": { + "description": "Retrofit tool for hackathons where tracks were added after submissions exist. Inserts a SubmissionTrackEntry for every non-disqualified submission. Idempotent. Auto-bumps `tracksMaxPerSubmission` if needed so submitters can still edit their submissions afterwards.", + "operationId": "OrganizationHackathonsTracksController_bulkOptIn", + "parameters": [ + { + "name": "trackId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Bulk opt-in complete; returns counts.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "trackName": { "type": "string" }, + "added": { "type": "number" }, + "alreadyOptedIn": { "type": "number" }, + "skippedDisqualified": { "type": "number" }, + "totalSubmissions": { "type": "number" }, + "newCap": { "type": "number", "nullable": true } + } + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Opt in every existing submission into this track", + "tags": ["Hackathons - Organizer Tracks"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/funding-otp/request": { + "post": { + "description": "Emails a one-time code the organizer must verify before funding. Reports required=false when step-up is disabled, or alreadyVerified=true when a recent verification still authorizes funding.", + "operationId": "OrganizationHackathonsEscrowController_requestFundingOtp", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestFundingOtpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Request a funding step-up code", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/funding-otp/verify": { + "post": { + "description": "Verifies the emailed code and authorizes funding for a short window. Wrong or expired codes return 400; attempts are capped.", + "operationId": "OrganizationHackathonsEscrowController_verifyFundingOtp", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/VerifyFundingOtpDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyFundingOtpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Verify a funding step-up code", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/publish": { + "post": { + "description": "Validates the draft, transitions it to DRAFT_AWAITING_FUNDING, and returns an unsigned XDR transaction for the organizer to sign. After signing, post the result back to /escrow/ops/:opRowId/submit-signed. Requires a verified funding step-up when FUNDING_OTP_ENABLED is on.", + "operationId": "OrganizationHackathonsEscrowController_publish", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon draft id", + "schema": { "example": "hack_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublishHackathonEscrowDto" + } + } + } + }, + "responses": { + "200": { + "description": "Escrow op created; unsigned XDR ready for wallet signing. Hackathon transitioned to DRAFT_AWAITING_FUNDING.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + }, + "400": { + "description": "Validation error or hackathon not in DRAFT status" + } + }, + "security": [{ "bearer": [] }], + "summary": "Publish a hackathon draft to the events contract", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/cancel": { + "post": { + "description": "Builds a cancel_event contract op. The contract refunds partner contributions first then the owner residual. On settle, the subscriber transitions the hackathon to CANCELLED and stamps the cancel audit columns.", + "operationId": "OrganizationHackathonsEscrowController_cancel", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelHackathonEscrowDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Cancel an active hackathon", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/select-winners": { + "post": { + "description": "Builds a select_winners contract op that pays out per the on-chain winner_distribution and bumps each winner's profile credits / reputation / earnings. On settle, the subscriber moves the hackathon to COMPLETED and sets rank on the winning HackathonSubmission rows.", + "operationId": "OrganizationHackathonsEscrowController_selectWinners", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SelectHackathonWinnersDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Select winners for a hackathon", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/ops/{opRowId}/submit-signed": { + "post": { + "description": "Accepts the signed XDR returned by the wallet and posts it to Soroban RPC. Returns the op in PENDING_CONFIRM; the reconciliation worker drives the final transition to COMPLETED or FAILED.", + "operationId": "OrganizationHackathonsEscrowController_submitSigned", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid returned by the publish call", + "schema": { + "example": "cmpwiox7u0000yy4404ojbk9t", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonSubmitSignedXdrDto" + } + } + } + }, + "responses": { + "200": { + "description": "Signed XDR submitted; op is now PENDING_CONFIRM.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Submit signed XDR for a previously-built escrow op", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/ops/{opRowId}": { + "get": { + "description": "Polled by the webapp while waiting for the reconciliation worker to mark the op COMPLETED or FAILED.", + "operationId": "OrganizationHackathonsEscrowController_getOp", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Read the current state of an escrow op", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/hackathons/{id}/escrow/reset-to-draft": { + "post": { + "description": "Recovers a hackathon stuck in DRAFT_AWAITING_FUNDING (e.g. a failed managed sign/submit) back to DRAFT so the organizer can fix the cause and republish. Refuses while the publish op may still settle on-chain.", + "operationId": "OrganizationHackathonsEscrowController_resetToDraft", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Hackathon reset to DRAFT." } }, + "security": [{ "bearer": [] }], + "summary": "Reset a stranded hackathon back to DRAFT", + "tags": ["Organization Hackathons - Escrow (v2)"] + } + }, + "/api/hackathons/{id}/escrow/submissions/{submissionId}/submit": { + "post": { + "description": "Builds the contract's submit op for an existing HackathonSubmission row. Hackathon has no prior-apply requirement; the contract simply stores the submission anchor with content_uri + submitted_at.", + "operationId": "HackathonParticipantEscrowController_submit", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + }, + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "HackathonSubmission cuid", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SubmitHackathonDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Anchor a hackathon submission on chain", + "tags": ["Hackathons - Participant Escrow (v2)"] + } + }, + "/api/hackathons/{id}/escrow/submissions/{submissionId}/withdraw": { + "post": { + "operationId": "HackathonParticipantEscrowController_withdrawSubmission", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + }, + { + "name": "submissionId", + "required": true, + "in": "path", + "description": "HackathonSubmission cuid", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WithdrawHackathonSubmissionDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Withdraw a hackathon submission anchor", + "tags": ["Hackathons - Participant Escrow (v2)"] + } + }, + "/api/hackathons/{id}/escrow/contribute": { + "post": { + "description": "Builds an add_funds contract op signed by the caller. Contract enforces a 10 USDC minimum. Anyone authenticated can contribute; multiple top-ups from the same wallet are allowed (one row per attempt).", + "operationId": "HackathonParticipantEscrowController_contribute", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributeHackathonDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Contribute funds to a hackathon pool", + "tags": ["Hackathons - Participant Escrow (v2)"] + } + }, + "/api/hackathons/{id}/escrow/ops/{opRowId}/submit-signed": { + "post": { + "operationId": "HackathonParticipantEscrowController_submitSigned", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonSubmitSignedXdrDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Submit signed XDR for a participant op", + "tags": ["Hackathons - Participant Escrow (v2)"] + } + }, + "/api/hackathons/{id}/escrow/ops/{opRowId}": { + "get": { + "operationId": "HackathonParticipantEscrowController_getOp", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Hackathon id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HackathonEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Read the state of a participant op", + "tags": ["Hackathons - Participant Escrow (v2)"] + } + }, + "/api/organizations": { + "post": { + "operationId": "OrganizationsController_createOrganization", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateOrganizationDto" } + } + } + }, + "responses": { "201": { "description": "" } }, + "tags": ["Organization"] + }, + "get": { + "operationId": "OrganizationsController_getOrganizations", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Organization"] + } + }, + "/api/organizations/my": { + "get": { + "operationId": "OrganizationsController_getMyOrganizations", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Organization"] + } + }, + "/api/organizations/profile/{idOrSlug}": { + "get": { + "description": "Returns public profile for the organization page: name, logo, description, and key stats. Resolve by organization ID or slug.", + "operationId": "OrganizationsController_getOrganizationProfile", + "parameters": [ + { + "name": "idOrSlug", + "required": true, + "in": "path", + "description": "Organization ID or slug", + "schema": { "example": "boundless-dao", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Organization profile retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationProfileDto" + } + } + } + }, + "404": { "description": "Organization not found" } + }, + "summary": "Get organization profile (public)", + "tags": ["Organization"] + } + }, + "/api/organizations/search": { + "get": { + "operationId": "OrganizationsController_searchOrganizations", + "parameters": [ + { + "name": "q", + "required": false, + "in": "query", + "description": "Search term (name, slug, tagline)", + "schema": { "type": "string" } + }, + { + "name": "isProfileComplete", + "required": false, + "in": "query", + "schema": { "enum": ["true", "false"], "type": "string" } + }, + { + "name": "hasHackathons", + "required": false, + "in": "query", + "schema": { "enum": ["true", "false"], "type": "string" } + }, + { + "name": "hasGrants", + "required": false, + "in": "query", + "schema": { "enum": ["true", "false"], "type": "string" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Max results (default 10)", + "schema": { "type": "number" } + } + ], + "responses": { "200": { "description": "Paginated organizations" } }, + "summary": "Search organizations", + "tags": ["Organization"] + } + }, + "/api/organizations/{id}": { + "get": { + "description": "Retrieve detailed information about a specific organization", + "operationId": "OrganizationsController_getOrganization", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Organization retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string", "example": "org_1234567890" }, + "name": { "type": "string", "example": "Tech Innovators" }, + "logo": { + "type": "string", + "example": "https://example.com/logo.png" + }, + "tagline": { + "type": "string", + "example": "Building the future of technology" + }, + "about": { + "type": "string", + "example": "We are a community of developers..." + }, + "links": { + "type": "object", + "properties": { + "website": { + "type": "string", + "example": "https://techinnovators.com" + }, + "x": { + "type": "string", + "example": "https://twitter.com/techinnovators" + }, + "github": { + "type": "string", + "example": "https://github.com/techinnovators" + }, + "others": { + "type": "string", + "example": "https://linkedin.com/company/techinnovators" + } + } + }, + "members": { + "type": "array", + "items": { "type": "string" }, + "example": ["user_123", "user_456"] + }, + "admins": { + "type": "array", + "items": { "type": "string" }, + "example": ["user_123"] + }, + "owner": { "type": "string", "example": "user_123" }, + "hackathons": { + "type": "array", + "items": { "type": "string" }, + "example": [] + }, + "grants": { + "type": "array", + "items": { "type": "string" }, + "example": [] + }, + "isProfileComplete": { "type": "boolean", "example": true }, + "pendingInvites": { + "type": "array", + "items": { "type": "string" }, + "example": ["invite_123"] + }, + "betterAuthOrgId": { + "type": "string", + "example": "better_auth_org_123" + }, + "isArchived": { "type": "boolean", "example": false }, + "archivedBy": { "type": "string", "example": null }, + "archivedAt": { "type": "string", "example": null }, + "createdAt": { + "type": "string", + "example": "2024-01-15T10:30:00.000Z" + }, + "updatedAt": { + "type": "string", + "example": "2024-01-15T10:30:00.000Z" + }, + "analytics": { + "type": "object", + "properties": { + "trends": { + "type": "object", + "properties": { + "members": { + "type": "object", + "properties": { + "current": { "type": "number", "example": 25 }, + "previous": { "type": "number", "example": 22 }, + "change": { "type": "number", "example": 3 }, + "changePercentage": { + "type": "number", + "example": 13.64 + }, + "isPositive": { + "type": "boolean", + "example": true + } + } + }, + "hackathons": { + "type": "object", + "properties": { + "current": { "type": "number", "example": 5 }, + "previous": { "type": "number", "example": 4 }, + "change": { "type": "number", "example": 1 }, + "changePercentage": { + "type": "number", + "example": 25 + }, + "isPositive": { + "type": "boolean", + "example": true + } + } + }, + "grants": { + "type": "object", + "properties": { + "current": { "type": "number", "example": 0 }, + "previous": { "type": "number", "example": 0 }, + "change": { "type": "number", "example": 0 }, + "changePercentage": { + "type": "number", + "example": 0 + }, + "isPositive": { + "type": "boolean", + "example": true + } + } + } + } + }, + "timeSeries": { + "type": "object", + "properties": { + "hackathons": { + "type": "array", + "items": { + "type": "object", + "properties": { + "month": { + "type": "string", + "example": "January" + }, + "year": { "type": "number", "example": 2024 }, + "count": { "type": "number", "example": 2 }, + "timestamp": { + "type": "string", + "example": "2024-01-01T00:00:00.000Z" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "404": { "description": "Organization not found" } + }, + "summary": "Get organization by ID", + "tags": ["Organization"] + }, + "put": { + "operationId": "OrganizationsController_updateOrganization", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateOrganizationDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "tags": ["Organization"] + }, + "delete": { + "operationId": "OrganizationsController_deleteOrganization", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Organization"] + } + }, + "/api/organizations/{id}/members": { + "get": { + "operationId": "OrganizationsController_getOrganizationMembers", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Organization"] + } + }, + "/api/organizations/{id}/stats": { + "get": { + "operationId": "OrganizationsController_getOrganizationStats", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Organization"] + } + }, + "/api/organizations/{organizationId}/members": { + "get": { + "operationId": "MembersController_getMembers", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Members"] + } + }, + "/api/organizations/{organizationId}/members/{userId}": { + "post": { + "operationId": "MembersController_addMember", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Members"] + }, + "delete": { + "operationId": "MembersController_removeMember", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Members"] + } + }, + "/api/organizations/{organizationId}/members/{userId}/role": { + "put": { + "operationId": "MembersController_updateMemberRole", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateMemberRoleDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "tags": ["Members"] + } + }, + "/api/organizations/{organizationId}/members/me": { + "get": { + "operationId": "MembersController_getMyMembership", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Members"] + } + }, + "/api/organizations/{organizationId}/invitations": { + "post": { + "operationId": "InvitationsController_inviteMember", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/InviteMemberDto" } + } + } + }, + "responses": { "201": { "description": "" } }, + "tags": ["Invitations"] + }, + "get": { + "operationId": "InvitationsController_getInvitations", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Invitations"] + } + }, + "/api/organizations/{organizationId}/invitations/{invitationId}/accept": { + "post": { + "operationId": "InvitationsController_acceptInvitation", + "parameters": [ + { + "name": "invitationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Invitations"] + } + }, + "/api/organizations/{organizationId}/invitations/{invitationId}/reject": { + "post": { + "operationId": "InvitationsController_rejectInvitation", + "parameters": [ + { + "name": "invitationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Invitations"] + } + }, + "/api/organizations/{organizationId}/invitations/{invitationId}": { + "delete": { + "operationId": "InvitationsController_cancelInvitation", + "parameters": [ + { + "name": "invitationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Invitations"] + } + }, + "/api/organizations/{organizationId}/invitations/my": { + "get": { + "operationId": "InvitationsController_getMyInvitations", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["Invitations"] + } + }, + "/api/organizations/{organizationId}/treasury/wallets": { + "get": { + "operationId": "OrganizationTreasuryController_listWallets", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TreasuryWalletResponseDto" + } + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "List treasury wallets", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/default-wallet": { + "get": { + "description": "Returns the org canonical managed wallet, provisioning one if none exists. Owner/admin only (may create). Use this as the funding + contract-auth identity for organization events.", + "operationId": "OrganizationTreasuryController_getDefaultWallet", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryWalletResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Get (or create) the organization default wallet", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/wallets/managed": { + "post": { + "description": "Provisions a platform-custodial Stellar account (sponsored activation + USDC trustline) owned by the organization. Owner/admin only.", + "operationId": "OrganizationTreasuryController_createManagedWallet", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateManagedWalletDto" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryWalletResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Create a Tier 1 managed treasury wallet", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/wallets/connected": { + "post": { + "description": "Verifies the external account exists + holds a USDC trustline, snapshots its multisig signer set, and records it. Owner/admin only.", + "operationId": "OrganizationTreasuryController_registerConnectedWallet", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterConnectedWalletDto" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryWalletResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Register a connected (Tier 2/3) wallet", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/wallets/{walletId}/refresh-signers": { + "post": { + "operationId": "OrganizationTreasuryController_refreshSigners", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "walletId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryWalletResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Re-fetch a connected wallet signer set from Horizon", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/wallets/{walletId}": { + "patch": { + "operationId": "OrganizationTreasuryController_updateWallet", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "walletId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTreasuryWalletDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryWalletResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Update a wallet label / default flag", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/wallets/{walletId}/archive": { + "post": { + "operationId": "OrganizationTreasuryController_archiveWallet", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "walletId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryWalletResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Archive a treasury wallet", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/wallets/{walletId}/balance": { + "get": { + "operationId": "OrganizationTreasuryController_walletBalance", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "walletId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WalletBalanceResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Live USDC + XLM balance for a wallet", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/policy": { + "get": { + "operationId": "OrganizationTreasuryController_getPolicy", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryPolicyResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Get the treasury spend policy (defaults if unset)", + "tags": ["Organization Treasury"] + }, + "put": { + "operationId": "OrganizationTreasuryController_updatePolicy", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTreasuryPolicyDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryPolicyResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Update the treasury spend policy (owner only)", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend": { + "post": { + "operationId": "OrganizationTreasuryController_initiateSpend", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/InitiateSpendDto" } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Initiate a spend request", + "tags": ["Organization Treasury"] + }, + "get": { + "operationId": "OrganizationTreasuryController_listSpend", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "List spend requests", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend/{requestId}": { + "get": { + "operationId": "OrganizationTreasuryController_getSpend", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "requestId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Get a spend request", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend/{requestId}/approve": { + "post": { + "operationId": "OrganizationTreasuryController_approveSpend", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "requestId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SpendDecisionDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Approve a spend request (owner/admin)", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend/{requestId}/reject": { + "post": { + "operationId": "OrganizationTreasuryController_rejectSpend", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "requestId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SpendDecisionDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Reject a spend request (owner/admin)", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend/{requestId}/cancel": { + "post": { + "operationId": "OrganizationTreasuryController_cancelSpend", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "requestId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Cancel a spend request (initiator or owner)", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend/{requestId}/execute": { + "post": { + "description": "For a managed source wallet, signs + submits a USDC payment to the destination server-side. Owner/admin only.", + "operationId": "OrganizationTreasuryController_executeSpend", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "requestId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Execute an approved spend on-chain (managed wallets)", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend/{requestId}/build-xdr": { + "post": { + "description": "For an approved connected (Tier 2/3) spend, returns the unsigned USDC payment XDR to sign in-browser and moves it to awaiting_signatures.", + "operationId": "OrganizationTreasuryController_buildSpendXdr", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "requestId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BuildSpendXdrResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Build the unsigned XDR for a connected-wallet spend", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/spend/{requestId}/submit-signed-xdr": { + "post": { + "operationId": "OrganizationTreasuryController_submitSpendSignedXdr", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "requestId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitSpendSignedXdrDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpendRequestResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Submit a browser-signed spend XDR (connected wallets)", + "tags": ["Organization Treasury"] + } + }, + "/api/organizations/{organizationId}/treasury/audit-log": { + "get": { + "operationId": "OrganizationTreasuryController_auditLog", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TreasuryAuditLogResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Paginated treasury audit log", + "tags": ["Organization Treasury"] + } + }, + "/api/votes": { + "post": { + "operationId": "VotesController_createVote", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateVoteDto" } + } + } + }, + "responses": { "201": { "description": "" } }, + "tags": ["Votes"] + }, + "get": { + "operationId": "VotesController_getVotes", + "parameters": [ + { + "name": "projectId", + "required": false, + "in": "query", + "description": "Project ID", + "schema": { "example": "123", "type": "string" } + }, + { + "name": "entityType", + "required": false, + "in": "query", + "description": "Entity Type", + "schema": { "example": "PROJECT", "type": "string" } + }, + { + "name": "voteType", + "required": true, + "in": "query", + "description": "Vote Type", + "schema": { "example": "UPVOTE", "type": "string" } + }, + { + "name": "userId", + "required": true, + "in": "query", + "description": "User ID", + "schema": { "example": "123", "type": "string" } + }, + { + "name": "limit", + "required": true, + "in": "query", + "description": "Limit", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "offset", + "required": true, + "in": "query", + "description": "Offset", + "schema": { "example": 0, "type": "number" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Votes"] + } + }, + "/api/votes/{projectId}/{entityType}": { + "delete": { + "operationId": "VotesController_removeVote", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityType", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Votes"] + } + }, + "/api/votes/count/{projectId}/{entityType}": { + "get": { + "operationId": "VotesController_getVoteCounts", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityType", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Votes"] + } + }, + "/api/votes/my-vote/{projectId}/{entityType}": { + "get": { + "operationId": "VotesController_getUserVote", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityType", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Votes"] + } + }, + "/api/votes/project/{projectId}": { + "get": { + "description": "Get project votes. Use includeVoters=true for comprehensive data including voter list and vote counts.", + "operationId": "VotesController_getProjectVotes", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "entityType", + "required": false, + "in": "query", + "schema": { + "enum": [ + "PROJECT", + "CROWDFUNDING_CAMPAIGN", + "HACKATHON_SUBMISSION", + "GRANT" + ], + "type": "string" + } + }, + { + "name": "voteType", + "required": false, + "in": "query", + "schema": { "enum": ["UPVOTE", "DOWNVOTE"], "type": "string" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "offset", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "includeVoters", + "required": false, + "in": "query", + "description": "Include voter list and vote counts in response", + "schema": { "type": "boolean" } + } + ], + "responses": { "200": { "description": "" } }, + "summary": "Get project votes", + "tags": ["Votes"] + } + }, + "/api/leaderboard": { + "get": { + "operationId": "LeaderboardController_getLeaderboard", + "parameters": [ + { + "name": "tier", + "required": false, + "in": "query", + "description": "Filter by reputation tier", + "schema": { + "enum": [ + "NEWCOMER", + "CONTRIBUTOR", + "ESTABLISHED", + "EXPERT", + "LEGEND" + ], + "type": "string" + } + }, + { + "name": "timeframe", + "required": false, + "in": "query", + "description": "Time window for score aggregation", + "schema": { + "enum": ["ALL_TIME", "THIS_MONTH", "THIS_WEEK", "THIS_DAY"], + "type": "string" + } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page, max 50 (default: 20)", + "schema": { "type": "number" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { "description": "Leaderboard retrieved successfully" } + }, + "summary": "Get community leaderboard entries", + "tags": ["leaderboard"] + } + }, + "/api/blog-posts": { + "post": { + "operationId": "BlogPostsController_createBlogPost", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateBlogPostDto" } + } + } + }, + "responses": { + "201": { "description": "Blog post created successfully" }, + "400": { "description": "Invalid input" }, + "403": { "description": "Forbidden" }, + "429": { "description": "Rate limit exceeded" } + }, + "security": [{ "bearer": [] }], + "summary": "Create a new blog post", + "tags": ["blog-posts"] + }, + "get": { + "operationId": "BlogPostsController_listBlogPosts", + "parameters": [ + { + "name": "authorId", + "required": false, + "in": "query", + "description": "Author ID to filter posts", + "schema": { "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Post status to filter", + "schema": { + "type": "string", + "enum": ["DRAFT", "PUBLISHED", "ARCHIVED", "SCHEDULED"] + } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search query for post title/content", + "schema": { "type": "string" } + }, + { + "name": "tags", + "required": false, + "in": "query", + "description": "Filter by tags (comma-separated)", + "schema": { "example": "smart-contracts,soroban", "type": "string" } + }, + { + "name": "categories", + "required": false, + "in": "query", + "description": "Filter by categories (comma-separated)", + "schema": { "example": "tutorials,development", "type": "string" } + }, + { + "name": "isFeatured", + "required": false, + "in": "query", + "description": "Include only featured posts", + "schema": { "default": false, "type": "boolean" } + }, + { + "name": "includePinned", + "required": false, + "in": "query", + "description": "Include pinned posts first", + "schema": { "default": true, "type": "boolean" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "minimum": 1, "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of items per page", + "schema": { + "minimum": 1, + "maximum": 100, + "default": 20, + "type": "number" + } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort field", + "schema": { + "default": "createdAt", + "type": "string", + "enum": [ + "createdAt", + "updatedAt", + "publishedAt", + "viewCount", + "title" + ] + } + }, + { + "name": "sortOrder", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { + "default": "desc", + "type": "string", + "enum": ["asc", "desc"] + } + } + ], + "responses": { + "200": { "description": "Blog posts retrieved successfully" } + }, + "summary": "List all blog posts with pagination and filters", + "tags": ["blog-posts"] + } + }, + "/api/blog-posts/id/{id}": { + "get": { + "operationId": "BlogPostsController_getBlogPostById", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Blog post retrieved successfully" }, + "403": { "description": "Post is not published" }, + "404": { "description": "Blog post not found" } + }, + "summary": "Get blog post by ID", + "tags": ["blog-posts"] + } + }, + "/api/blog-posts/slug/{slug}": { + "get": { + "operationId": "BlogPostsController_getBlogPostBySlug", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Blog post slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Blog post retrieved successfully" }, + "403": { "description": "Post is not published" }, + "404": { "description": "Blog post not found" } + }, + "summary": "Get blog post by slug", + "tags": ["blog-posts"] + } + }, + "/api/blog-posts/{id}/related": { + "get": { + "operationId": "BlogPostsController_getRelatedPosts", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + }, + { + "name": "limit", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Related posts retrieved successfully" }, + "404": { "description": "Blog post not found" } + }, + "summary": "Get related blog posts", + "tags": ["blog-posts"] + } + }, + "/api/blog-posts/{id}": { + "put": { + "operationId": "BlogPostsController_updateBlogPost", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateBlogPostDto" } + } + } + }, + "responses": { + "200": { "description": "Blog post updated successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Blog post not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Update a blog post", + "tags": ["blog-posts"] + }, + "delete": { + "operationId": "BlogPostsController_deleteBlogPost", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "responses": { + "204": { "description": "Blog post deleted successfully" }, + "403": { "description": "Forbidden" }, + "404": { "description": "Blog post not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Delete a blog post", + "tags": ["blog-posts"] + } + }, + "/api/admin/ai/generate-excerpt": { + "post": { + "operationId": "AiController_generateExcerpt", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "content": { "type": "string" } }, + "required": ["content"] + } + } + } + }, + "responses": { + "200": { "description": "Excerpt generated successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Generate excerpt from content", + "tags": ["Admin - AI"] + } + }, + "/api/admin/ai/generate-reading-time": { + "post": { + "operationId": "AiController_generateReadingTime", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "content": { "type": "string" } }, + "required": ["content"] + } + } + } + }, + "responses": { + "200": { "description": "Reading time generated successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Generate reading time estimate from content", + "tags": ["Admin - AI"] + } + }, + "/api/admin/ai/generate-seo": { + "post": { + "operationId": "AiController_generateSEO", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "content": { "type": "string" } }, + "required": ["content"] + } + } + } + }, + "responses": { + "200": { "description": "SEO settings generated successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Generate SEO settings from content", + "tags": ["Admin - AI"] + } + }, + "/api/admin/ai/generate-tags": { + "post": { + "operationId": "AiController_generateTags", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "content": { "type": "string" } }, + "required": ["content"] + } + } + } + }, + "responses": { + "200": { "description": "Tags generated successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Generate tags from content", + "tags": ["Admin - AI"] + } + }, + "/api/admin/ai/generate-category": { + "post": { + "operationId": "AiController_generateCategory", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "content": { "type": "string" } }, + "required": ["content"] + } + } + } + }, + "responses": { + "200": { "description": "Category generated successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Generate category from content", + "tags": ["Admin - AI"] + } + }, + "/api/admin/overview": { + "get": { + "description": "Retrieves comprehensive overview data including metrics and charts for the admin dashboard", + "operationId": "AdminController_getOverview", + "parameters": [ + { + "name": "timeRange", + "required": false, + "in": "query", + "description": "Time range for the overview data", + "schema": { "enum": ["7d", "30d", "90d"], "type": "string" } + } + ], + "responses": { + "200": { + "description": "Overview data retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminOverviewResponseDto" + } + } + } + }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" }, + "500": { "description": "Internal server error" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get admin overview data (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/users": { + "get": { + "description": "Retrieves a paginated list of all users with optional filtering", + "operationId": "AdminController_getUsers", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search by name, email, or username", + "schema": { "type": "string" } + }, + { + "name": "role", + "required": false, + "in": "query", + "description": "Filter by user role", + "schema": { "type": "string" } + }, + { + "name": "isActive", + "required": false, + "in": "query", + "description": "Filter by active status (not banned)", + "schema": { "type": "boolean" } + } + ], + "responses": { + "200": { "description": "Users retrieved successfully" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get all users (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/users/export": { + "get": { + "description": "Downloads a CSV file containing all platform users and newsletter-only subscribers", + "operationId": "AdminController_exportUsers", + "parameters": [], + "responses": { + "200": { "description": "CSV file download" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Export all users as CSV (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/users/{usernameOrId}": { + "get": { + "description": "Retrieves detailed information about a specific user by username or ID", + "operationId": "AdminController_getUserDetails", + "parameters": [ + { + "name": "usernameOrId", + "required": true, + "in": "path", + "description": "User username or ID", + "schema": { "example": "johndoe", "type": "string" } + } + ], + "responses": { + "200": { "description": "User details retrieved successfully" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user details (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/users/{usernameOrId}/stats": { + "get": { + "description": "Retrieves comprehensive statistics for a specific user", + "operationId": "AdminController_getUserStats", + "parameters": [ + { + "name": "usernameOrId", + "required": true, + "in": "path", + "description": "User username or ID", + "schema": { "example": "johndoe", "type": "string" } + } + ], + "responses": { + "200": { "description": "User statistics retrieved successfully" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user statistics (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/users/{usernameOrId}/activity": { + "get": { + "description": "Retrieves activity history for a specific user", + "operationId": "AdminController_getUserActivity", + "parameters": [ + { + "name": "usernameOrId", + "required": true, + "in": "path", + "description": "User username or ID", + "schema": { "example": "johndoe", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + } + ], + "responses": { + "200": { "description": "User activity retrieved successfully" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user activity (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/users/{usernameOrId}/projects": { + "get": { + "description": "Retrieves all projects created by a specific user", + "operationId": "AdminController_getUserProjects", + "parameters": [ + { + "name": "usernameOrId", + "required": true, + "in": "path", + "description": "User username or ID", + "schema": { "example": "johndoe", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by project status", + "schema": { "example": "ACTIVE", "type": "string" } + }, + { + "name": "category", + "required": false, + "in": "query", + "description": "Filter by project category", + "schema": { "example": "defi", "type": "string" } + } + ], + "responses": { + "200": { "description": "User projects retrieved successfully" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user projects (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/organizations": { + "get": { + "description": "Retrieves a paginated list of all organizations with member counts", + "operationId": "AdminController_getOrganizations", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search by organization name or slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Organizations retrieved successfully" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get all organizations (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/organizations/{orgId}": { + "get": { + "description": "Retrieves detailed information about an organization including members and hackathons", + "operationId": "AdminController_getOrganizationDetails", + "parameters": [ + { + "name": "orgId", + "required": true, + "in": "path", + "description": "Organization ID", + "schema": { "example": "clx1234567890", "type": "string" } + } + ], + "responses": { + "200": { + "description": "Organization details retrieved successfully" + }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "Organization not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get organization details (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/users/{usernameOrId}/organizations": { + "get": { + "description": "Retrieves all organizations a user is a member of", + "operationId": "AdminController_getUserOrganizations", + "parameters": [ + { + "name": "usernameOrId", + "required": true, + "in": "path", + "description": "User username or ID", + "schema": { "example": "johndoe", "type": "string" } + } + ], + "responses": { + "200": { "description": "User organizations retrieved successfully" }, + "401": { "description": "Unauthorized - Authentication required" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get user organizations (Admin only)", + "tags": ["Admin"] + } + }, + "/api/admin/blog-posts": { + "post": { + "operationId": "AdminBlogsController_createBlogPost", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateBlogPostDto" } + } + } + }, + "responses": { + "201": { "description": "Blog post created successfully" }, + "400": { "description": "Invalid input" }, + "403": { "description": "Forbidden - Admin access required" }, + "429": { "description": "Rate limit exceeded" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Create a new blog post (Admin only)", + "tags": ["Admin - Blog Posts"] + }, + "get": { + "operationId": "AdminBlogsController_listAllBlogPosts", + "parameters": [ + { + "name": "authorId", + "required": false, + "in": "query", + "description": "Author ID to filter posts", + "schema": { "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Post status to filter", + "schema": { + "type": "string", + "enum": ["DRAFT", "PUBLISHED", "ARCHIVED", "SCHEDULED"] + } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search query for post title/content", + "schema": { "type": "string" } + }, + { + "name": "tags", + "required": false, + "in": "query", + "description": "Filter by tags (comma-separated)", + "schema": { "example": "smart-contracts,soroban", "type": "string" } + }, + { + "name": "categories", + "required": false, + "in": "query", + "description": "Filter by categories (comma-separated)", + "schema": { "example": "tutorials,development", "type": "string" } + }, + { + "name": "isFeatured", + "required": false, + "in": "query", + "description": "Include only featured posts", + "schema": { "default": false, "type": "boolean" } + }, + { + "name": "includePinned", + "required": false, + "in": "query", + "description": "Include pinned posts first", + "schema": { "default": true, "type": "boolean" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "minimum": 1, "default": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Number of items per page", + "schema": { + "minimum": 1, + "maximum": 100, + "default": 20, + "type": "number" + } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort field", + "schema": { + "default": "createdAt", + "type": "string", + "enum": [ + "createdAt", + "updatedAt", + "publishedAt", + "viewCount", + "title" + ] + } + }, + { + "name": "sortOrder", + "required": false, + "in": "query", + "description": "Sort order", + "schema": { + "default": "desc", + "type": "string", + "enum": ["asc", "desc"] + } + } + ], + "responses": { + "200": { "description": "Blog posts retrieved successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "List all blog posts including drafts (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/blog-posts/{id}": { + "get": { + "operationId": "AdminBlogsController_getBlogPostById", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Blog post retrieved successfully" }, + "404": { "description": "Blog post not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get blog post by ID (Admin only)", + "tags": ["Admin - Blog Posts"] + }, + "put": { + "operationId": "AdminBlogsController_updateBlogPost", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdateBlogPostDto" } + } + } + }, + "responses": { + "200": { "description": "Blog post updated successfully" }, + "403": { "description": "Forbidden - Admin access required" }, + "404": { "description": "Blog post not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Update a blog post (Admin only)", + "tags": ["Admin - Blog Posts"] + }, + "delete": { + "description": "Marks the blog post as deleted without removing it from database", + "operationId": "AdminBlogsController_deleteBlogPost", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "responses": { + "204": { "description": "Blog post deleted successfully" }, + "404": { "description": "Blog post not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Soft delete a blog post (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/blog-posts/{id}/permanent": { + "delete": { + "description": "Permanently removes the blog post from database", + "operationId": "AdminBlogsController_permanentlyDeleteBlogPost", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "responses": { + "204": { + "description": "Blog post permanently deleted successfully" + }, + "404": { "description": "Blog post not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Permanently delete a blog post (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/blog-posts/{id}/restore": { + "post": { + "operationId": "AdminBlogsController_restoreBlogPost", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Blog post ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Blog post restored successfully" }, + "404": { "description": "Blog post not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Restore a soft-deleted blog post (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/blog-posts/tags/all": { + "get": { + "operationId": "AdminBlogsController_getAllTags", + "parameters": [ + { + "name": "limit", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Tags retrieved successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get all tags with post counts (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/blog-posts/tags/{slug}": { + "get": { + "operationId": "AdminBlogsController_getTagBySlug", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Tag slug", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Tag retrieved successfully" }, + "404": { "description": "Tag not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get tag by slug (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/blog-posts/tags/unused": { + "delete": { + "description": "Removes tags that are not associated with any blog posts", + "operationId": "AdminBlogsController_deleteUnusedTags", + "parameters": [], + "responses": { + "200": { "description": "Unused tags deleted successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Delete all unused tags (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/blog-posts/scheduled/publish": { + "post": { + "operationId": "AdminBlogsController_publishScheduledPosts", + "parameters": [], + "responses": { + "200": { "description": "Scheduled posts published successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Manually trigger publishing of scheduled posts (Admin only)", + "tags": ["Admin - Blog Posts"] + } + }, + "/api/admin/crowdfunding": { + "get": { + "operationId": "AdminCrowdfundingController_list", + "parameters": [ + { "name": "limit", "required": false, "in": "query", "schema": {} }, + { "name": "page", "required": false, "in": "query", "schema": {} } + ], + "responses": { "200": { "description": "List of campaigns" } }, + "security": [{ "JWT-auth": [] }], + "summary": "List crowdfunding campaigns", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/user/{usernameOrId}": { + "get": { + "operationId": "AdminCrowdfundingController_listByUser", + "parameters": [ + { + "name": "usernameOrId", + "required": true, + "in": "path", + "description": "Username or User ID", + "schema": { "type": "string" } + }, + { "name": "limit", "required": false, "in": "query", "schema": {} }, + { "name": "page", "required": false, "in": "query", "schema": {} } + ], + "responses": { + "200": { "description": "List of campaigns by user" }, + "404": { "description": "User not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "List crowdfunding campaigns by user", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/{campaignId}": { + "get": { + "operationId": "AdminCrowdfundingController_getCampaign", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "description": "Campaign ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Campaign details" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get crowdfunding campaign by ID", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/pending": { + "get": { + "operationId": "AdminCrowdfundingController_listPending", + "parameters": [ + { "name": "limit", "required": false, "in": "query", "schema": {} }, + { "name": "page", "required": false, "in": "query", "schema": {} } + ], + "responses": { "200": { "description": "List of pending campaigns" } }, + "security": [{ "JWT-auth": [] }], + "summary": "List crowdfunding campaigns pending admin review", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/{campaignId}/approve": { + "post": { + "operationId": "AdminCrowdfundingController_approve", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "Campaign approved" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Approve a crowdfunding campaign", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/{campaignId}/reject": { + "post": { + "operationId": "AdminCrowdfundingController_reject", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminCrowdfundingRejectDto" + } + } + } + }, + "responses": { "200": { "description": "Campaign rejected" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Reject a crowdfunding campaign", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/{campaignId}/request-revision": { + "post": { + "operationId": "AdminCrowdfundingController_requestRevision", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminCrowdfundingRequestRevisionDto" + } + } + } + }, + "responses": { + "200": { "description": "Revision request created" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Request revisions for a crowdfunding campaign", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/{campaignId}/review-note": { + "post": { + "operationId": "AdminCrowdfundingController_addReviewNote", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminCrowdfundingNoteDto" + } + } + } + }, + "responses": { + "200": { "description": "Review note added" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Add an admin review note for a campaign", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/crowdfunding/{campaignId}/assign-reviewer": { + "post": { + "operationId": "AdminCrowdfundingController_assignReviewer", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminCrowdfundingAssignDto" + } + } + } + }, + "responses": { + "200": { "description": "Reviewer assigned" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Assign a reviewer to a campaign", + "tags": ["Admin - Crowdfunding"] + } + }, + "/api/admin/milestones": { + "get": { + "description": "Retrieves all milestones organized by their campaigns with pagination", + "operationId": "AdminMilestonesController_listAllMilestonesByCampaign", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by review status", + "schema": { + "example": "PENDING", + "type": "string", + "enum": [ + "PENDING", + "SUBMITTED", + "UNDER_REVIEW", + "APPROVED", + "REJECTED", + "RESUBMISSION_REQUIRED" + ] + } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort by field", + "schema": { + "example": "submittedAt", + "type": "string", + "enum": [ + "submittedAt", + "campaignSize", + "creatorReputation", + "createdAt" + ] + } + }, + { + "name": "campaignId", + "required": false, + "in": "query", + "description": "Filter by campaign ID", + "schema": { + "example": "550e8400-e29b-41d4-a716-446655440000", + "type": "string" + } + } + ], + "responses": { + "200": { "description": "List of campaigns with their milestones" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "List all milestones grouped by campaign", + "tags": ["Admin"] + } + }, + "/api/admin/milestones/pending": { + "get": { + "operationId": "AdminMilestonesController_listPendingMilestones", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by review status", + "schema": { + "example": "PENDING", + "type": "string", + "enum": [ + "PENDING", + "SUBMITTED", + "UNDER_REVIEW", + "APPROVED", + "REJECTED", + "RESUBMISSION_REQUIRED" + ] + } + }, + { + "name": "sortBy", + "required": false, + "in": "query", + "description": "Sort by field", + "schema": { + "example": "submittedAt", + "type": "string", + "enum": [ + "submittedAt", + "campaignSize", + "creatorReputation", + "createdAt" + ] + } + }, + { + "name": "campaignId", + "required": false, + "in": "query", + "description": "Filter by campaign ID", + "schema": { + "example": "550e8400-e29b-41d4-a716-446655440000", + "type": "string" + } + } + ], + "responses": { "200": { "description": "List of pending milestones" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Get pending milestone review queue", + "tags": ["Admin"] + } + }, + "/api/admin/milestones/{milestoneId}": { + "get": { + "operationId": "AdminMilestonesController_getMilestoneForReview", + "parameters": [ + { + "name": "milestoneId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Milestone details" }, + "404": { "description": "Milestone not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get milestone detail for review", + "tags": ["Admin"] + } + }, + "/api/admin/milestones/{milestoneId}/approve": { + "post": { + "operationId": "AdminMilestonesController_approveMilestone", + "parameters": [ + { + "name": "milestoneId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ApproveMilestoneDto" } + } + } + }, + "responses": { + "200": { "description": "Milestone approved" }, + "404": { "description": "Milestone not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Approve a milestone submission", + "tags": ["Admin"] + } + }, + "/api/admin/milestones/{milestoneId}/reject": { + "post": { + "operationId": "AdminMilestonesController_rejectMilestone", + "parameters": [ + { + "name": "milestoneId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/RejectMilestoneDto" } + } + } + }, + "responses": { + "200": { "description": "Milestone rejected" }, + "404": { "description": "Milestone not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Reject a milestone submission", + "tags": ["Admin"] + } + }, + "/api/admin/milestones/{milestoneId}/request-resubmission": { + "post": { + "operationId": "AdminMilestonesController_requestResubmission", + "parameters": [ + { + "name": "milestoneId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestMilestoneResubmissionDto" + } + } + } + }, + "responses": { + "200": { "description": "Resubmission requested" }, + "404": { "description": "Milestone not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Request milestone resubmission with changes", + "tags": ["Admin"] + } + }, + "/api/admin/milestones/{milestoneId}/review-note": { + "post": { + "operationId": "AdminMilestonesController_addReviewNote", + "parameters": [ + { + "name": "milestoneId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddMilestoneReviewNoteDto" + } + } + } + }, + "responses": { + "201": { "description": "Review note added" }, + "404": { "description": "Milestone not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Add a review note to milestone", + "tags": ["Admin"] + } + }, + "/api/admin/escrow/{campaignId}": { + "get": { + "operationId": "AdminEscrowController_getEscrowInfo", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Escrow information" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get escrow information and transaction history for campaign", + "tags": ["Admin"] + } + }, + "/api/admin/escrow/{campaignId}/action": { + "post": { + "description": "Manually trigger escrow actions like release, refund, pause, or resume. This is intended for testnet use only.", + "operationId": "AdminEscrowController_executeEscrowAction", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ManualEscrowActionDto" } + } + } + }, + "responses": { + "200": { "description": "Escrow action executed" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Execute manual escrow action (testnet only)", + "tags": ["Admin"] + } + }, + "/api/admin/disputes": { + "get": { + "operationId": "AdminDisputesController_listDisputes", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page", + "schema": { "example": 20, "type": "number" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by dispute status", + "schema": { + "example": "OPEN", + "type": "string", + "enum": [ + "OPEN", + "UNDER_REVIEW", + "AWAITING_RESPONSE", + "RESOLVED", + "ESCALATED", + "CLOSED" + ] + } + }, + { + "name": "campaignId", + "required": false, + "in": "query", + "description": "Filter by campaign ID", + "schema": { + "example": "550e8400-e29b-41d4-a716-446655440000", + "type": "string" + } + } + ], + "responses": { "200": { "description": "List of disputes" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Get dispute dashboard with filtering", + "tags": ["Admin"] + } + }, + "/api/admin/disputes/{disputeId}": { + "get": { + "operationId": "AdminDisputesController_getDisputeDetail", + "parameters": [ + { + "name": "disputeId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Dispute details" }, + "404": { "description": "Dispute not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get detailed dispute information", + "tags": ["Admin"] + } + }, + "/api/admin/disputes/{disputeId}/assign": { + "post": { + "operationId": "AdminDisputesController_assignDispute", + "parameters": [ + { + "name": "disputeId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AssignDisputeDto" } + } + } + }, + "responses": { + "200": { "description": "Dispute assigned" }, + "404": { "description": "Dispute not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Assign dispute to an admin", + "tags": ["Admin"] + } + }, + "/api/admin/disputes/{disputeId}/note": { + "post": { + "description": "Add a communication to the dispute. Can be internal (admin only) or external (visible to parties).", + "operationId": "AdminDisputesController_addDisputeNote", + "parameters": [ + { + "name": "disputeId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AddDisputeNoteDto" } + } + } + }, + "responses": { + "201": { "description": "Note added" }, + "404": { "description": "Dispute not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Add note or message to dispute", + "tags": ["Admin"] + } + }, + "/api/admin/disputes/{disputeId}/resolve": { + "post": { + "operationId": "AdminDisputesController_resolveDispute", + "parameters": [ + { + "name": "disputeId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ResolveDisputeDto" } + } + } + }, + "responses": { + "200": { "description": "Dispute resolved" }, + "404": { "description": "Dispute not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Resolve a dispute with a final decision", + "tags": ["Admin"] + } + }, + "/api/admin/disputes/{disputeId}/escalate": { + "post": { + "operationId": "AdminDisputesController_escalateDispute", + "parameters": [ + { + "name": "disputeId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/EscalateDisputeDto" } + } + } + }, + "responses": { + "200": { "description": "Dispute escalated" }, + "404": { "description": "Dispute not found" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Escalate dispute to arbitration", + "tags": ["Admin"] + } + }, + "/api/admin/hackathons/rewards/queue": { + "get": { + "description": "\n Fetch all reward distributions in queue, filterable by status.\n Pagination via limit/offset.\n Statuses: PENDING_ADMIN_REVIEW, APPROVED, REJECTED, EXECUTING, COMPLETED, FAILED, PARTIAL_SUCCESS\n ", + "operationId": "AdminHackathonsRewardsController_getRewardQueue", + "parameters": [ + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by status (e.g., PENDING_ADMIN_REVIEW)", + "schema": { "example": "PENDING_ADMIN_REVIEW", "type": "string" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Results per page", + "schema": { "example": 50, "type": "string" } + }, + { + "name": "offset", + "required": false, + "in": "query", + "description": "Pagination offset", + "schema": { "example": 0, "type": "string" } + } + ], + "responses": { + "200": { + "description": "Queue of reward distributions", + "content": { + "application/json": { + "schema": { + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminRewardQueueItemDto" + } + }, + "total": { "type": "number" }, + "limit": { "type": "number" }, + "offset": { "type": "number" } + } + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Get reward distribution queue (admin)", + "tags": ["Admin - Hackathon Rewards"] + } + }, + "/api/admin/hackathons/rewards/{hackathonId}/rewards/{distributionId}": { + "get": { + "description": "Fetch full details of a specific reward distribution", + "operationId": "AdminHackathonsRewardsController_getRewardDistributionDetail", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "UUID of the hackathon", + "schema": { + "example": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5", + "type": "string" + } + }, + { + "name": "distributionId", + "required": true, + "in": "path", + "description": "UUID of the reward distribution", + "schema": { + "example": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", + "type": "string" + } + } + ], + "responses": { + "200": { "description": "Distribution detail" }, + "404": { "description": "Hackathon or distribution not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get reward distribution detail (admin)", + "tags": ["Admin - Hackathon Rewards"] + } + }, + "/api/admin/hackathons/rewards/{hackathonId}/rewards/{distributionId}/approve": { + "post": { + "description": "\n Approve a pending reward distribution.\n Moves to APPROVED state, locks for Milestone B execution.\n Can include optional admin note.\n ", + "operationId": "AdminHackathonsRewardsController_approveRewardDistribution", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "UUID of the hackathon", + "schema": { + "example": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5", + "type": "string" + } + }, + { + "name": "distributionId", + "required": true, + "in": "path", + "description": "UUID of the reward distribution", + "schema": { + "example": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApproveRewardDistributionDto" + } + } + } + }, + "responses": { + "200": { "description": "Distribution approved" }, + "400": { + "description": "Distribution already approved/rejected or in wrong state" + }, + "404": { "description": "Hackathon or distribution not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Approve reward distribution (admin)", + "tags": ["Admin - Hackathon Rewards"] + } + }, + "/api/admin/hackathons/rewards/{hackathonId}/rewards/{distributionId}/reject": { + "post": { + "description": "\n Reject a pending reward distribution.\n Moves to REJECTED state; organizer sees reason and can re-trigger with fixes.\n Requires rejection reason (visible to organizer) and optional internal admin note.\n ", + "operationId": "AdminHackathonsRewardsController_rejectRewardDistribution", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "UUID of the hackathon", + "schema": { + "example": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5", + "type": "string" + } + }, + { + "name": "distributionId", + "required": true, + "in": "path", + "description": "UUID of the reward distribution", + "schema": { + "example": "b2c3d4e5-f6g7-4h8i-9j0k-l1m2n3o4p5q6", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectRewardDistributionDto" + } + } + } + }, + "responses": { + "200": { "description": "Distribution rejected" }, + "400": { + "description": "Distribution already approved/rejected or in wrong state" + }, + "404": { "description": "Hackathon or distribution not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Reject reward distribution (admin)", + "tags": ["Admin - Hackathon Rewards"] + } + }, + "/api/admin/hackathons/rewards/{hackathonId}/rewards/{distributionId}/sync": { + "post": { + "description": "Manually trigger indexer sync for this distribution. Updates executionRecords from escrow released flags.", + "operationId": "AdminHackathonsRewardsController_syncRewardDistribution", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "description": "UUID of the hackathon", + "schema": { "type": "string" } + }, + { + "name": "distributionId", + "required": true, + "in": "path", + "description": "UUID of the reward distribution", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Sync completed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "updated": { "type": "boolean" } } + } + } + } + }, + "404": { "description": "Hackathon or distribution not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Sync reward distribution with on-chain (admin)", + "tags": ["Admin - Hackathon Rewards"] + } + }, + "/api/admin/manual-projects/pending": { + "get": { + "operationId": "AdminManualProjectsController_listPendingManualProjects", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "example": 20, "type": "number" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "List pending manual project submissions", + "tags": ["Admin Manual Projects"] + } + }, + "/api/admin/manual-projects/{projectId}/approve": { + "post": { + "operationId": "AdminManualProjectsController_approveManualProject", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "description": "Project ID", + "schema": { "type": "string" } + } + ], + "responses": { "201": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Approve a pending manual project", + "tags": ["Admin Manual Projects"] + } + }, + "/api/admin/manual-projects/{projectId}/reject": { + "post": { + "operationId": "AdminManualProjectsController_rejectManualProject", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "description": "Project ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectManualProjectDto" + } + } + } + }, + "responses": { "201": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Reject a pending manual project", + "tags": ["Admin Manual Projects"] + } + }, + "/api/admin/manual-projects/{projectId}/request-changes": { + "post": { + "operationId": "AdminManualProjectsController_requestChanges", + "parameters": [ + { + "name": "projectId", + "required": true, + "in": "path", + "description": "Project ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestManualProjectChangesDto" + } + } + } + }, + "responses": { "201": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Request changes for a pending manual project", + "tags": ["Admin Manual Projects"] + } + }, + "/api/admin/project-edits/pending": { + "get": { + "operationId": "AdminProjectEditsController_listPendingProjectEdits", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "schema": { "example": 1, "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "example": 20, "type": "number" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "List pending major project edits", + "tags": ["Admin Project Edits"] + } + }, + "/api/admin/project-edits/{editId}/approve": { + "post": { + "operationId": "AdminProjectEditsController_approveProjectEdit", + "parameters": [ + { + "name": "editId", + "required": true, + "in": "path", + "description": "ProjectEdit ID", + "schema": { "type": "string" } + } + ], + "responses": { "201": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Approve a pending major project edit", + "tags": ["Admin Project Edits"] + } + }, + "/api/admin/project-edits/{editId}/reject": { + "post": { + "operationId": "AdminProjectEditsController_rejectProjectEdit", + "parameters": [ + { + "name": "editId", + "required": true, + "in": "path", + "description": "ProjectEdit ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/RejectProjectEditDto" } + } + } + }, + "responses": { "201": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Reject a pending major project edit", + "tags": ["Admin Project Edits"] + } + }, + "/api/admin/wallets/stats": { + "get": { + "operationId": "AdminWalletsController_getStats", + "parameters": [ + { + "name": "timeRange", + "required": false, + "in": "query", + "schema": { "enum": ["7d", "30d", "90d"], "type": "string" } + } + ], + "responses": { + "default": { + "description": "", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AdminWalletStatsDto" } + } + } + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get wallet statistics", + "tags": ["Admin Wallets"] + } + }, + "/api/admin/wallets": { + "get": { + "operationId": "AdminWalletsController_listWallets", + "parameters": [ + { + "name": "search", + "required": false, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { "type": "number" } + } + ], + "responses": { + "default": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminWalletListResponseDto" + } + } + } + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "List user wallets", + "tags": ["Admin Wallets"] + } + }, + "/api/admin/wallets/user/{userId}": { + "get": { + "operationId": "AdminWalletsController_getByUserId", + "parameters": [ + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "default": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminWalletListItemDto" + } + } + } + } + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get wallets for a specific user", + "tags": ["Admin Wallets"] + } + }, + "/api/admin/wallets/{id}": { + "get": { + "operationId": "AdminWalletsController_getDetails", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "default": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminWalletDetailsDto" + } + } + } + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Get detailed wallet info", + "tags": ["Admin Wallets"] + } + }, + "/api/admin/wallets/{id}/activate": { + "post": { + "description": "All XLM reserves paid by the platform sponsor account. Idempotent: re-running on an already-activated wallet returns success without submitting. Used by the admin dashboard \"Activate\" button.", + "operationId": "AdminWalletsController_activateWallet", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Wallet activated successfully" } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Sponsor-activate a wallet by ID (creates account + configured trustlines, default USDC)", + "tags": ["Admin Wallets"] + } + }, + "/api/admin/wallets/users/{userId}/sponsor-activate": { + "post": { + "description": "Uses the sponsor account to create the on-chain account and add the configured trustlines (default USDC). User pays no XLM. Idempotent: safe to retry. Use this for hackathon participants who need to receive USDC payouts.", + "operationId": "AdminWalletsController_sponsorActivateUser", + "parameters": [ + { + "name": "userId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "201": { + "description": "Returns activation result for the user (activated, alreadyActivated, addedTrustlines, hash)." + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Sponsor-activate a single user (account + USDC trustline)", + "tags": ["Admin Wallets"] + } + }, + "/api/admin/wallets/hackathons/{hackathonId}/sponsor-activate": { + "post": { + "description": "Aggregates all distinct user IDs from HackathonSubmission.participantId and teamMembers[], then enqueues a BullMQ job that activates each wallet (account + USDC trustline). Returns immediately with a job ID. Poll the status URL for progress; idempotent re-runs are safe.", + "operationId": "AdminWalletsController_sponsorActivateHackathon", + "parameters": [ + { + "name": "hackathonId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "201": { + "description": "Job enqueued. Returns { jobId, hackathonId, estimatedParticipants, statusUrl }." + } + }, + "security": [{ "JWT-auth": [] }], + "summary": "Enqueue sponsor activation for every participant of a hackathon", + "tags": ["Admin Wallets"] + } + }, + "/api/admin/wallets/jobs/sponsor-activation/{jobId}": { + "get": { + "description": "Returns BullMQ job state (waiting | active | completed | failed | delayed | paused), progress {processed, total, activated, alreadyActivated, failed}, returnvalue (full summary when complete), and failedReason.", + "operationId": "AdminWalletsController_getSponsorActivationJobStatus", + "parameters": [ + { + "name": "jobId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Get status of a sponsor-activation job", + "tags": ["Admin Wallets"] + } + }, + "/healthz": { + "get": { + "description": "Returns 200 if the process is alive. No downstream checks. Use for orchestrator restart decisions.", + "operationId": "HealthController_liveness", + "parameters": [], + "responses": { "200": { "description": "" } }, + "summary": "Liveness probe", + "tags": ["Health"] + } + }, + "/readyz": { + "get": { + "description": "Returns 200 only when Postgres and Redis are reachable. Use for orchestrator traffic-drain decisions, not for restart.", + "operationId": "HealthController_readiness", + "parameters": [], + "responses": { + "200": { + "description": "The Health Check is successful", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { "type": "string", "example": "ok" }, + "info": { + "type": "object", + "example": { "database": { "status": "up" } }, + "additionalProperties": { + "type": "object", + "required": ["status"], + "properties": { "status": { "type": "string" } }, + "additionalProperties": true + }, + "nullable": true + }, + "error": { + "type": "object", + "example": {}, + "additionalProperties": { + "type": "object", + "required": ["status"], + "properties": { "status": { "type": "string" } }, + "additionalProperties": true + }, + "nullable": true + }, + "details": { + "type": "object", + "example": { "database": { "status": "up" } }, + "additionalProperties": { + "type": "object", + "required": ["status"], + "properties": { "status": { "type": "string" } }, + "additionalProperties": true + } + } + } + } + } + } + }, + "503": { + "description": "The Health Check is not successful", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { "type": "string", "example": "error" }, + "info": { + "type": "object", + "example": { "database": { "status": "up" } }, + "additionalProperties": { + "type": "object", + "required": ["status"], + "properties": { "status": { "type": "string" } }, + "additionalProperties": true + }, + "nullable": true + }, + "error": { + "type": "object", + "example": { + "redis": { + "status": "down", + "message": "Could not connect" + } + }, + "additionalProperties": { + "type": "object", + "required": ["status"], + "properties": { "status": { "type": "string" } }, + "additionalProperties": true + }, + "nullable": true + }, + "details": { + "type": "object", + "example": { + "database": { "status": "up" }, + "redis": { + "status": "down", + "message": "Could not connect" + } + }, + "additionalProperties": { + "type": "object", + "required": ["status"], + "properties": { "status": { "type": "string" } }, + "additionalProperties": true + } + } + } + } + } + } + } + }, + "summary": "Readiness probe", + "tags": ["Health"] + } + }, + "/api/didit/status": { + "get": { + "description": "Returns a normalized verification state the frontend uses to decide what to render: the verify button is shown only when `canStartNew` is true (states: not_started, declined, abandoned, expired). For `in_review` the response includes a `reviewWindow` with the SLA in business days.", + "operationId": "DiditController_getStatus", + "parameters": [], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerificationStatusDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Get current verification state for the authenticated user", + "tags": ["Didit Identity Verification"] + } + }, + "/api/didit/callback": { + "get": { + "description": "Didit redirects the user here after the hosted KYC flow. We resolve authoritative status from the DB (the query string from Didit is not trusted) and 302 to the frontend with `?state=...`. State maps directly to the values returned by GET /didit/status.", + "operationId": "DiditController_callback", + "parameters": [], + "responses": { "200": { "description": "" } }, + "summary": "Didit redirect target (post-verification)", + "tags": ["Didit Identity Verification"] + } + }, + "/api/didit/create-session": { + "post": { + "description": "Creates a Didit verification session. Returns session_token and verification_url for the frontend SDK. Authenticated user id is sent as vendor_data unless user_id is provided.", + "operationId": "DiditController_createSession", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateDiditSessionDto" } + } + } + }, + "responses": { + "200": { + "description": "Session created", + "content": { + "application/json": { + "schema": { + "example": { + "session_id": "sess_xxx", + "session_token": "tok_xxx", + "verification_url": "https://...", + "status": "Pending" + } + } + } + } + }, + "400": { + "description": "Missing DIDIT_API_KEY or DIDIT_WORKFLOW_ID" + }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "bearer": [] }], + "summary": "Create verification session", + "tags": ["Didit Identity Verification"] + } + }, + "/api/didit/webhook": { + "post": { + "description": "Receives verification completion events from Didit. Verifies X-Signature-V2 when DIDIT_WEBHOOK_SECRET is set. Updates user verification status and DiditVerificationSession.", + "operationId": "DiditController_webhook", + "parameters": [], + "responses": { + "200": { "description": "Webhook accepted" }, + "400": { "description": "Invalid signature" } + }, + "summary": "Didit webhook", + "tags": ["Didit Identity Verification"] + } + }, + "/api/pricing/preview": { + "get": { + "operationId": "PricingController_preview", + "parameters": [ + { + "name": "pillar", + "required": true, + "in": "query", + "schema": { + "type": "string", + "enum": ["Hackathon", "Bounty", "Grant", "Crowdfunding"] + } + }, + { + "name": "organizationId", + "required": true, + "in": "query", + "schema": { "type": "string" } + }, + { + "name": "budgetStroops", + "required": true, + "in": "query", + "description": "Budget in stroops (7-decimal). String to preserve precision.", + "schema": { "type": "string" } + }, + { + "name": "salesOverrideBps", + "required": false, + "in": "query", + "description": "Override fee bps from a sales authority. 0 = waiver.", + "schema": { "minimum": 0, "maximum": 5000, "type": "number" } + }, + { + "name": "salesOverrideReason", + "required": false, + "in": "query", + "description": "Free-text reason for the audit log.", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PricingPreviewResponseDto" + } + } + } + } + }, + "summary": "Compute the financial preview for a publish wizard", + "tags": ["pricing"] + } + }, + "/api/admin/ops/pause": { + "post": { + "operationId": "AdminOpsController_pause", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["AdminOps"] + } + }, + "/api/admin/ops/unpause": { + "post": { + "operationId": "AdminOpsController_unpause", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["AdminOps"] + } + }, + "/api/admin/ops/set-fee-bps": { + "post": { + "operationId": "AdminOpsController_setFeeBps", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["AdminOps"] + } + }, + "/api/prices": { + "get": { + "description": "Returns per-unit USD prices for XLM, USDC, EURC and USDGLO. Resolved from the Reflector on-chain oracle, with CoinGecko and stablecoin-peg fallbacks. Cached for 5 minutes (matches Reflector update cadence).", + "operationId": "PricesController_getAll", + "parameters": [], + "responses": { + "200": { + "description": "Map of asset symbol → USD price as a decimal string (6 dp).", + "content": { + "application/json": { + "schema": { + "example": { + "XLM": "0.117800", + "USDC": "1.000000", + "EURC": "1.080000", + "USDGLO": "1.000000" + } + } + } + } + } + }, + "summary": "Get USD prices for all supported assets", + "tags": ["prices"] + } + }, + "/api/prices/debug": { + "get": { + "description": "Bypasses the cache and pings Reflector + CoinGecko for every supported asset. Returns what each provider returned alongside which one the resolution chain would have picked. Use to verify both price paths are live.", + "operationId": "PricesController_getDebug", + "parameters": [], + "responses": { + "200": { + "description": "Per-asset debug info. `source` is which provider won the resolution chain.", + "content": { + "application/json": { + "schema": { + "example": { + "XLM": { + "resolved": "0.117800", + "source": "reflector", + "providers": { + "reflector": "0.117800", + "coingecko": "0.117850", + "stablecoinFallback": null + } + }, + "USDC": { + "resolved": "1.000000", + "source": "reflector", + "providers": { + "reflector": "1.000000", + "coingecko": "1.000000", + "stablecoinFallback": "1.0000" + } + } + } + } + } + } + } + }, + "summary": "Per-provider price resolution (diagnostic)", + "tags": ["prices"] + } + }, + "/api/prices/{symbol}": { + "get": { + "description": "Convenience lookup — internally reads from the same cached map as the list endpoint.", + "operationId": "PricesController_getOne", + "parameters": [ + { + "name": "symbol", + "required": true, + "in": "path", + "description": "Asset ticker (case-insensitive).", + "schema": { + "enum": ["XLM", "USDC", "EURC", "USDGLO"], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "USD price as a decimal string (6 dp).", + "content": { + "application/json": { "schema": { "example": "0.117800" } } + } + } + }, + "summary": "Get USD price for a single asset", + "tags": ["prices"] + } + }, + "/api/projects/drafts": { + "post": { + "operationId": "ProjectsController_createDraft", + "parameters": [], + "requestBody": { + "required": true, + "description": "Full payload for the stepped draft creation", + "content": { + "application/json": { + "schema": { "type": "object" }, + "examples": { + "campaign": { + "value": { + "title": "DeFi Lending Protocol", + "tagline": "Scalable liquidity", + "category": "DeFi", + "description": "A Stellar-native DeFi lending protocol that enables users to deposit assets and earn interest with transparent on-chain accounting.", + "summary": "Lending with transparent on-chain accounting", + "vision": "We aim to make lending safer and more scalable by improving collateral efficiency and risk modeling.", + "details": "Full technical and product details (markdown supported).", + "banner": "https://example.com/banner.png", + "logo": "https://example.com/logo.png", + "githubUrl": "https://github.com/example/defi-lending", + "gitlabUrl": "https://gitlab.com/example/defi-lending", + "bitbucketUrl": "https://bitbucket.org/example/defi-lending", + "projectWebsite": "https://defi-lending.example.com", + "demoVideo": "https://example.com/demo.mp4", + "whitepaperUrl": "https://example.com/whitepaper.pdf", + "pitchVideoUrl": "https://example.com/pitch.mp4", + "socialLinks": { + "twitter": "https://twitter.com/example", + "discord": "https://discord.gg/example" + }, + "contact": { + "primary": "@alex123", + "backup": "alex_doe#1234" + }, + "tags": ["Soroban", "TypeScript", "DeFi"], + "draftData": { + "isCampaign": true, + "campaign": { + "title": "DeFi Lending Protocol Campaign", + "logo": "https://example.com/logo.png", + "vision": "Build, ship, and deliver measurable milestones.", + "banner": "https://example.com/banner.png", + "category": "DeFi", + "details": "Funding request and milestone plan for the lending protocol.", + "fundingAmount": 15000, + "githubUrl": "https://github.com/example/defi-lending", + "gitlabUrl": "https://gitlab.com/example/defi-lending", + "bitbucketUrl": "https://bitbucket.org/example/defi-lending", + "projectWebsite": "https://defi-lending.example.com", + "demoVideo": "https://example.com/demo.mp4", + "milestones": [ + { + "title": "Milestone 1", + "description": "Core lending vault + basic UI.", + "deliverable": "Deploy vault contracts + initial product UI.", + "fundingPercentage": 50, + "amount": 7500, + "expectedDeliveryDate": "2026-04-01T00:00:00.000Z", + "successCriteria": "Contracts deployed and UI shipped.", + "orderIndex": 0 + }, + { + "title": "Milestone 2", + "description": "Risk modeling improvements + analytics.", + "deliverable": "Add risk model and dashboard metrics.", + "fundingPercentage": 50, + "amount": 7500, + "expectedDeliveryDate": "2026-05-01T00:00:00.000Z", + "successCriteria": "Risk model live and dashboards updated.", + "orderIndex": 1 + } + ], + "team": [ + { + "name": "John Doe", + "role": "Lead Developer", + "email": "john@example.com", + "linkedin": "https://linkedin.com/in/johndoe", + "twitter": "https://twitter.com/johndoe" + } + ], + "contact": { + "primary": "@alex123", + "backup": "alex_doe#1234" + }, + "socialLinks": [ + { + "platform": "twitter", + "url": "https://twitter.com/example" + }, + { + "platform": "discord", + "url": "https://discord.gg/example" + } + ] + } + } + } + }, + "nonCampaign": { + "value": { + "title": "NFT Marketplace", + "tagline": "Creator focused", + "category": "NFT", + "description": "A creator-first NFT marketplace for Stellar projects with curated discovery and transparent royalties.", + "summary": "Marketplace for creators", + "vision": "Make discovery and royalties simple.", + "details": "Markdown project details here.", + "banner": "https://example.com/banner.png", + "logo": "https://example.com/logo.png", + "githubUrl": "https://github.com/example/nft-marketplace", + "projectWebsite": "https://nft-marketplace.example.com", + "demoVideo": "https://example.com/demo.mp4", + "socialLinks": { "twitter": "https://twitter.com/example" }, + "contact": { "primary": "@alex123" }, + "tags": ["NFT", "React"], + "draftData": { "isCampaign": false } + } + } + } + } + } + }, + "responses": { "201": { "description": "Draft created successfully" } }, + "security": [{ "bearer": [] }], + "summary": "Create a project draft (stepped form)", + "tags": ["projects"] + } + }, + "/api/projects/{id}/draft": { + "patch": { + "operationId": "ProjectsController_saveDraft", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Project ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "description": "Full payload for stepped draft autosave", + "content": { + "application/json": { + "schema": { "type": "object" }, + "examples": { + "campaign": { + "value": { + "title": "DeFi Lending Protocol", + "tagline": "Scalable liquidity", + "category": "DeFi", + "description": "A Stellar-native DeFi lending protocol that enables users to deposit assets and earn interest with transparent on-chain accounting.", + "summary": "Lending with transparent on-chain accounting", + "vision": "We aim to make lending safer and more scalable by improving collateral efficiency and risk modeling.", + "details": "Full technical and product details (markdown supported).", + "banner": "https://example.com/banner.png", + "logo": "https://example.com/logo.png", + "githubUrl": "https://github.com/example/defi-lending", + "gitlabUrl": "https://gitlab.com/example/defi-lending", + "bitbucketUrl": "https://bitbucket.org/example/defi-lending", + "projectWebsite": "https://defi-lending.example.com", + "demoVideo": "https://example.com/demo.mp4", + "whitepaperUrl": "https://example.com/whitepaper.pdf", + "pitchVideoUrl": "https://example.com/pitch.mp4", + "socialLinks": { + "twitter": "https://twitter.com/example", + "discord": "https://discord.gg/example" + }, + "contact": { + "primary": "@alex123", + "backup": "alex_doe#1234" + }, + "tags": ["Soroban", "TypeScript", "DeFi"], + "draftData": { + "isCampaign": true, + "campaign": { + "title": "DeFi Lending Protocol Campaign", + "logo": "https://example.com/logo.png", + "vision": "Build, ship, and deliver measurable milestones.", + "banner": "https://example.com/banner.png", + "category": "DeFi", + "details": "Funding request and milestone plan for the lending protocol.", + "fundingAmount": 15000, + "githubUrl": "https://github.com/example/defi-lending", + "gitlabUrl": "https://gitlab.com/example/defi-lending", + "bitbucketUrl": "https://bitbucket.org/example/defi-lending", + "projectWebsite": "https://defi-lending.example.com", + "demoVideo": "https://example.com/demo.mp4", + "milestones": [ + { + "title": "Milestone 1", + "description": "Core lending vault + basic UI.", + "deliverable": "Deploy vault contracts + initial product UI.", + "fundingPercentage": 50, + "amount": 7500, + "expectedDeliveryDate": "2026-04-01T00:00:00.000Z", + "successCriteria": "Contracts deployed and UI shipped.", + "orderIndex": 0 + }, + { + "title": "Milestone 2", + "description": "Risk modeling improvements + analytics.", + "deliverable": "Add risk model and dashboard metrics.", + "fundingPercentage": 50, + "amount": 7500, + "expectedDeliveryDate": "2026-05-01T00:00:00.000Z", + "successCriteria": "Risk model live and dashboards updated.", + "orderIndex": 1 + } + ], + "team": [ + { + "name": "John Doe", + "role": "Lead Developer", + "email": "john@example.com", + "linkedin": "https://linkedin.com/in/johndoe", + "twitter": "https://twitter.com/johndoe" + } + ], + "contact": { + "primary": "@alex123", + "backup": "alex_doe#1234" + }, + "socialLinks": [ + { + "platform": "twitter", + "url": "https://twitter.com/example" + }, + { + "platform": "discord", + "url": "https://discord.gg/example" + } + ] + } + } + } + }, + "nonCampaign": { + "value": { + "title": "NFT Marketplace", + "tagline": "Creator focused", + "category": "NFT", + "description": "A creator-first NFT marketplace for Stellar projects with curated discovery and transparent royalties.", + "summary": "Marketplace for creators", + "vision": "Make discovery and royalties simple.", + "details": "Markdown project details here.", + "banner": "https://example.com/banner.png", + "logo": "https://example.com/logo.png", + "githubUrl": "https://github.com/example/nft-marketplace", + "projectWebsite": "https://nft-marketplace.example.com", + "demoVideo": "https://example.com/demo.mp4", + "socialLinks": { "twitter": "https://twitter.com/example" }, + "contact": { "primary": "@alex123" }, + "tags": ["NFT", "React"], + "draftData": { "isCampaign": false } + } + } + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Update a project draft (stepped form autosave)", + "tags": ["projects"] + } + }, + "/api/projects": { + "get": { + "operationId": "ProjectsController_listPublicProjects", + "parameters": [], + "responses": { "200": { "description": "" } }, + "summary": "List public projects (PRD products directory)", + "tags": ["projects"] + } + }, + "/api/projects/search": { + "get": { + "operationId": "ProjectsController_searchPublicProjects", + "parameters": [ + { + "name": "search", + "required": false, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "summary": "Search public projects", + "tags": ["projects"] + } + }, + "/api/projects/featured": { + "get": { + "operationId": "ProjectsController_listFeaturedProjects", + "parameters": [], + "responses": { "200": { "description": "" } }, + "summary": "List featured projects", + "tags": ["projects"] + } + }, + "/api/projects/{id}/edits": { + "post": { + "operationId": "ProjectsController_submitProjectEdit", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/Function" } + } + } + }, + "responses": { "201": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Submit a major/minor edit for your project", + "tags": ["projects"] + }, + "get": { + "operationId": "ProjectsController_listProjectEdits", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "List edit history for your project", + "tags": ["projects"] + } + }, + "/api/projects/{id}/publish": { + "post": { + "operationId": "ProjectsController_publishProject", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Project ID", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "description": "Publish/submit action (Review & Submit)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "isCampaign": { "type": "boolean", "example": true } + } + }, + "examples": { + "publishCampaign": { "value": { "isCampaign": true } }, + "publishNonCampaign": { "value": { "isCampaign": false } } + } + } + } + }, + "responses": { "201": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Publish/submit a project draft (Review & Submit)", + "tags": ["projects"] + } + }, + "/api/projects/me": { + "get": { + "operationId": "ProjectsController_getMyProjects", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "offset", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "status", + "required": true, + "in": "query", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "List my projects", + "tags": ["projects"] + } + }, + "/api/projects/{slug}": { + "get": { + "operationId": "ProjectsController_getPublicProjectBySlug", + "parameters": [ + { + "name": "slug", + "required": true, + "in": "path", + "description": "Project slug", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Get public project by slug", + "tags": ["projects"] + } + }, + "/api/projects/me/{id}": { + "get": { + "operationId": "ProjectsController_getProject", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Project ID", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Get my project by ID", + "tags": ["projects"] + } + }, + "/api/organizations/{organizationId}/bounties/{id}/escrow/publish": { + "post": { + "description": "Validates the draft, transitions it to draft_awaiting_funding, and returns an unsigned XDR (EXTERNAL) or the op in PENDING_CONFIRM (MANAGED). Reconciliation transitions the bounty to OPEN on success.", + "operationId": "OrganizationBountiesEscrowController_publish", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty draft id", + "schema": { "example": "bnt_1234567890", "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublishBountyEscrowDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + }, + "400": { + "description": "Validation failed or bounty not in draft status" + } + }, + "security": [{ "bearer": [] }], + "summary": "Publish a bounty draft to the events contract", + "tags": ["Organization Bounties - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/bounties/{id}/escrow/cancel": { + "post": { + "description": "Builds a cancel_event contract op. The contract refunds partner contributions first (in full), then the owner residual; or pro-rates partners if escrow is short. On settle, BountyEscrowSubscriber moves the bounty to CANCELLED and stamps the cancel audit columns.", + "operationId": "OrganizationBountiesEscrowController_cancel", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CancelBountyEscrowDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Cancel an active bounty", + "tags": ["Organization Bounties - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/bounties/{id}/escrow/select-winners": { + "post": { + "description": "Builds a select_winners contract op that pays out per the on-chain winner_distribution and bumps each winner's profile credits / reputation / earnings. On settle, BountyEscrowSubscriber moves the bounty to COMPLETED and marks the winning BountySubmission rows accepted with the reward tx hash.", + "operationId": "OrganizationBountiesEscrowController_selectWinners", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SelectBountyWinnersDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Select winners for a bounty", + "tags": ["Organization Bounties - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/bounties/{id}/escrow/ops/{opRowId}/submit-signed": { + "post": { + "operationId": "OrganizationBountiesEscrowController_submitSigned", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountySubmitSignedXdrDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Submit signed XDR for a previously-built bounty escrow op", + "tags": ["Organization Bounties - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/bounties/{id}/escrow/ops/{opRowId}": { + "get": { + "operationId": "OrganizationBountiesEscrowController_getOp", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Read the current state of a bounty escrow op", + "tags": ["Organization Bounties - Escrow (v2)"] + } + }, + "/api/bounties/{id}/escrow/apply": { + "post": { + "description": "Builds an apply_to_bounty contract op. EXTERNAL returns unsigned XDR; MANAGED signs and submits. The contract charges the bounty's application_credit_cost via the profile contract on settle.", + "operationId": "BountyParticipantEscrowController_apply", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ApplyBountyDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Apply to a bounty", + "tags": ["Bounties - Participant Escrow (v2)"] + } + }, + "/api/bounties/{id}/escrow/withdraw-application": { + "post": { + "description": "Builds a withdraw_application contract op. Contract refunds half the application_credit_cost via the profile contract on settle.", + "operationId": "BountyParticipantEscrowController_withdrawApplication", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WithdrawApplicationDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Withdraw a bounty application", + "tags": ["Bounties - Participant Escrow (v2)"] + } + }, + "/api/bounties/{id}/escrow/submit": { + "post": { + "description": "Builds a submit contract op. Requires the applicant's prior apply_to_bounty to be in active status (contract enforces; the service pre-checks for a cleaner 4xx).", + "operationId": "BountyParticipantEscrowController_submit", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SubmitBountyDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Submit work for a bounty", + "tags": ["Bounties - Participant Escrow (v2)"] + } + }, + "/api/bounties/{id}/escrow/withdraw-submission": { + "post": { + "operationId": "BountyParticipantEscrowController_withdrawSubmission", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/WithdrawSubmissionDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Withdraw a bounty submission anchor", + "tags": ["Bounties - Participant Escrow (v2)"] + } + }, + "/api/bounties/{id}/escrow/contribute": { + "post": { + "description": "Builds an add_funds contract op signed by the caller. Contract enforces a 10 USDC minimum. Anyone with a funded wallet can contribute; this v1 surface requires Boundless auth, so multiple top-ups from the same wallet are allowed (one row per attempt).", + "operationId": "BountyParticipantEscrowController_contribute", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ContributeBountyDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Contribute funds to a bounty pool", + "tags": ["Bounties - Participant Escrow (v2)"] + } + }, + "/api/bounties/{id}/escrow/ops/{opRowId}/submit-signed": { + "post": { + "operationId": "BountyParticipantEscrowController_submitSigned", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountySubmitSignedXdrDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Submit signed XDR for a previously-built participant op", + "tags": ["Bounties - Participant Escrow (v2)"] + } + }, + "/api/bounties/{id}/escrow/ops/{opRowId}": { + "get": { + "operationId": "BountyParticipantEscrowController_getOp", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Bounty id", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "description": "EscrowOp cuid", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BountyEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Read the state of a participant op", + "tags": ["Bounties - Participant Escrow (v2)"] + } + }, + "/api/bounties/{bountyId}/v2/applications": { + "post": { + "operationId": "BountyApplicationController_create", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBountyApplicationDto" + } + } + } + }, + "responses": { "201": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Submit an application for a LIGHT/HEAVY bounty", + "tags": ["Bounty v2 - Applications"] + } + }, + "/api/bounties/{bountyId}/v2/applications/me": { + "get": { + "operationId": "BountyApplicationController_getMine", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Read the caller's application for this bounty", + "tags": ["Bounty v2 - Applications"] + } + }, + "/api/bounties/{bountyId}/v2/applications/{appId}": { + "patch": { + "operationId": "BountyApplicationController_edit", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "appId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditBountyApplicationDto" + } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Edit a SUBMITTED application (before shortlist)", + "tags": ["Bounty v2 - Applications"] + }, + "delete": { + "operationId": "BountyApplicationController_withdraw", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "appId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Withdraw a SUBMITTED application", + "tags": ["Bounty v2 - Applications"] + } + }, + "/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications": { + "get": { + "operationId": "OrganizationBountyShortlistController_list", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by application status", + "schema": { + "enum": [ + "SUBMITTED", + "SHORTLISTED", + "SELECTED", + "DECLINED", + "WITHDRAWN" + ], + "type": "string" + } + }, + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": {} + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "List applications on a bounty", + "tags": ["Bounty v2 - Organizer Shortlist"] + } + }, + "/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications/select": { + "post": { + "operationId": "OrganizationBountyShortlistController_selectForPick", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SelectForPickDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Select a single application (Curated Pick / Pitched Pick)", + "tags": ["Bounty v2 - Organizer Shortlist"] + } + }, + "/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications/shortlist": { + "post": { + "operationId": "OrganizationBountyShortlistController_createShortlist", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CreateShortlistDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Approve a shortlist (Curated Showdown / Pitched Showdown)", + "tags": ["Bounty v2 - Organizer Shortlist"] + } + }, + "/api/organizations/{organizationId}/bounties/{bountyId}/v2/applications/{appId}/decline": { + "post": { + "operationId": "OrganizationBountyShortlistController_decline", + "parameters": [ + { + "name": "appId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/DeclineApplicationDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Decline an application with optional reason", + "tags": ["Bounty v2 - Organizer Shortlist"] + } + }, + "/api/bounties/{bountyId}/v2/showdown/join": { + "post": { + "operationId": "BountyShowdownJoinController_join", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/JoinShowdownDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Join an Open Showdown bounty", + "tags": ["Bounty v2 - Open Showdown"] + }, + "delete": { + "operationId": "BountyShowdownJoinController_leave", + "parameters": [ + { + "name": "bountyId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/JoinShowdownDto" } + } + } + }, + "responses": { "200": { "description": "" } }, + "security": [{ "bearer": [] }], + "summary": "Leave an Open Showdown before submitting", + "tags": ["Bounty v2 - Open Showdown"] + } + }, + "/api/bounties": { + "get": { + "operationId": "BountyPublicController_list", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { "type": "number" } + }, + { "name": "search", "required": false, "in": "query", "schema": {} }, + { "name": "status", "required": false, "in": "query", "schema": {} }, + { + "name": "organizationId", + "required": false, + "in": "query", + "schema": {} + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/BountyPublicListDto" } + } + } + } + }, + "summary": "Public bounty marketplace list", + "tags": ["bounties"] + } + }, + "/api/bounties/{id}": { + "get": { + "operationId": "BountyPublicController_findOne", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/BountyPublicDto" } + } + } + } + }, + "summary": "Public bounty detail", + "tags": ["bounties"] + } + }, + "/api/organizations/{organizationId}/grants/{id}/escrow/publish": { + "post": { + "description": "Validates the draft, transitions to DRAFT_AWAITING_FUNDING, and returns an unsigned XDR (EXTERNAL) or the op in PENDING_CONFIRM (MANAGED). Reconciliation transitions the grant to OPEN on success.", + "operationId": "OrganizationGrantsEscrowController_publish", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "example": "org_1234567890", "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "description": "Grant id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/PublishGrantEscrowDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantEscrowOpResponseDto" + } + } + } + }, + "400": { "description": "Draft not in DRAFT status" } + }, + "security": [{ "bearer": [] }], + "summary": "Publish a grant draft to the events contract", + "tags": ["Organization Grants - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/grants/{id}/escrow/cancel": { + "post": { + "operationId": "OrganizationGrantsEscrowController_cancel", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/CancelGrantEscrowDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Cancel an active grant", + "tags": ["Organization Grants - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/grants/{id}/escrow/select-winners": { + "post": { + "description": "For Multi release_kind, select_winners records recipients with amount=0 — payouts happen per-milestone via claim_milestone.", + "operationId": "OrganizationGrantsEscrowController_selectWinners", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SelectGrantWinnersDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Select grant recipients", + "tags": ["Organization Grants - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/grants/{id}/escrow/claim-milestone": { + "post": { + "description": "Builds a claim_milestone contract op. Contract pays the per-milestone amount to the recipient and bumps profile credits / reputation / earnings.", + "operationId": "OrganizationGrantsEscrowController_claimMilestone", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClaimGrantMilestoneDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Pay out a specific milestone for a recipient", + "tags": ["Organization Grants - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/grants/{id}/escrow/ops/{opRowId}/submit-signed": { + "post": { + "operationId": "OrganizationGrantsEscrowController_submitSigned", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantSubmitSignedXdrDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Submit signed XDR for a grant op", + "tags": ["Organization Grants - Escrow (v2)"] + } + }, + "/api/organizations/{organizationId}/grants/{id}/escrow/ops/{opRowId}": { + "get": { + "operationId": "OrganizationGrantsEscrowController_getOp", + "parameters": [ + { + "name": "organizationId", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "id", + "required": true, + "in": "path", + "schema": { "type": "string" } + }, + { + "name": "opRowId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Read the state of a grant op", + "tags": ["Organization Grants - Escrow (v2)"] + } + }, + "/api/grants/{id}/escrow/contribute": { + "post": { + "description": "Open add_funds op. Contract enforces a 10 USDC minimum. Anyone authenticated can contribute; multiple top-ups from the same wallet are allowed (one row per attempt).", + "operationId": "GrantContributeEscrowController_contribute", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Grant id", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ContributeGrantDto" } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantEscrowOpResponseDto" + } + } + } + } + }, + "security": [{ "bearer": [] }], + "summary": "Contribute funds to a grant pool", + "tags": ["Grants - Contribute (v2)"] + } + }, + "/api/grants": { + "get": { + "description": "Public, page-based list of grant programs. Parallel to /bounties and /hackathons. For a multi-pillar feed (Bounty, Hackathon, Grant, Crowdfunding), use /opportunities instead.", + "operationId": "GrantsPublicController_list", + "parameters": [ + { + "name": "status", + "required": false, + "in": "query", + "description": "Pillar-specific status filter (open, closed, in_progress).", + "schema": { "example": "open", "type": "string" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Case-insensitive substring match against project title and summary.", + "schema": { "example": "governance", "type": "string" } + }, + { + "name": "category", + "required": false, + "in": "query", + "description": "Filter by the underlying project category.", + "schema": { "example": "defi", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (1-indexed).", + "schema": { + "minimum": 1, + "default": 1, + "example": 1, + "type": "number" + } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page.", + "schema": { + "minimum": 1, + "maximum": 50, + "default": 20, + "example": 20, + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "Grants page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GrantPublicListResponseDto" + } + } + } + } + }, + "summary": "List published grants", + "tags": ["Grants"] + } + }, + "/api/opportunities": { + "get": { + "description": "Returns a unified, cursor-paginated feed across Bounty, Hackathon, Grant, and Crowdfunding. Pass type= to restrict to one. The cursor is opaque; pass it back as-is to fetch the next page.", + "operationId": "OpportunitiesController_list", + "parameters": [ + { + "name": "type", + "required": false, + "in": "query", + "description": "Which pillar to query. \"all\" fans out across the four adapters; the others restrict to a single adapter.", + "schema": { + "default": "all", + "example": "all", + "type": "string", + "enum": ["all", "bounty", "hackathon", "grant", "crowdfunding"] + } + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Pillar-specific status filter. Adapters match case-insensitively against their own enum and return [] when no value matches.", + "schema": { "example": "open", "type": "string" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Case-insensitive substring match against title and summary across adapters.", + "schema": { "example": "governance", "type": "string" } + }, + { + "name": "tags", + "required": false, + "in": "query", + "description": "Comma-separated tag list. Pillar-aware: bounty has no tag field and returns [] for any tags filter.", + "schema": { "example": "stellar,defi", "type": "string" } + }, + { + "name": "sort", + "required": false, + "in": "query", + "description": "Sort mode. \"deadline\" sorts ascending by the next deadline (NULLS LAST); \"prize_desc\" sorts by reward descending.", + "schema": { + "default": "newest", + "example": "newest", + "type": "string", + "enum": ["newest", "deadline", "prize_desc"] + } + }, + { + "name": "cursor", + "required": false, + "in": "query", + "description": "Opaque pagination cursor returned by the previous response. Omit to start from page 1.", + "schema": { + "example": "eyJzb3J0IjoibmV3ZXN0IiwicHJpbWFyeSI6IjIwMjYtMDUtMTVUMDA6MDA6MDAuMDAwWiIsImlkIjoiY2t4eXoxMjMifQ", + "type": "string" + } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page. Capped at 50.", + "schema": { + "minimum": 1, + "maximum": 50, + "default": 12, + "example": 12, + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "Opportunities page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpportunityListResponseDto" + } + } + } + } + }, + "summary": "List opportunities across all pillars", + "tags": ["Opportunities"] + } + }, + "/api/newsletter/subscribe": { + "post": { + "description": "Subscribe an email address to the newsletter. Sends a confirmation email (double opt-in). Rate limited to 5 requests per minute.", + "operationId": "NewsletterController_subscribe", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SubscribeDto" } + } + } + }, + "responses": { + "201": { + "description": "Confirmation email sent successfully", + "content": { + "application/json": { + "schema": { + "example": { + "message": "Confirmation email sent. Please check your inbox.", + "id": "clx1234567890" + } + } + } + } + }, + "400": { "description": "Invalid tags provided" }, + "409": { "description": "Email is already subscribed" }, + "429": { "description": "Too many requests — rate limited" } + }, + "summary": "Subscribe to the newsletter", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/confirm/{token}": { + "get": { + "description": "Confirm a newsletter subscription via the token sent in the confirmation email. Redirects to the frontend on success.", + "operationId": "NewsletterController_confirmSubscription", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Confirmation token received via email", + "schema": { "type": "string" } + } + ], + "responses": { + "302": { "description": "Redirects to frontend confirmation page" }, + "400": { "description": "Confirmation token has expired" }, + "404": { "description": "Invalid or expired confirmation token" } + }, + "summary": "Confirm newsletter subscription", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/unsubscribe/{token}": { + "get": { + "description": "Unsubscribe from the newsletter using the one-click unsubscribe token from emails. Redirects to the frontend.", + "operationId": "NewsletterController_unsubscribeByToken", + "parameters": [ + { + "name": "token", + "required": true, + "in": "path", + "description": "Unsubscribe token from the email footer", + "schema": { "type": "string" } + } + ], + "responses": { + "302": { + "description": "Redirects to frontend unsubscribe confirmation page" + }, + "404": { "description": "Invalid unsubscribe link" } + }, + "summary": "Unsubscribe by token", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/unsubscribe": { + "post": { + "description": "Legacy unsubscribe endpoint. Unsubscribe a subscriber by their email address.", + "operationId": "NewsletterController_unsubscribe", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UnsubscribeDto" } + } + } + }, + "responses": { + "200": { "description": "Successfully unsubscribed" }, + "404": { "description": "Subscriber not found" } + }, + "summary": "Unsubscribe by email", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/preferences": { + "patch": { + "description": "Update topic tag preferences for a subscriber. Valid tags: bounties, hackathons, grants, updates.", + "operationId": "NewsletterController_updatePreferences", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UpdatePreferencesDto" } + } + } + }, + "responses": { + "200": { "description": "Preferences updated successfully" }, + "400": { "description": "Invalid tags provided" }, + "404": { "description": "Subscriber not found" } + }, + "summary": "Update subscription preferences", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/tracking/open/{campaignId}/{subscriberId}": { + "get": { + "description": "Open tracking pixel endpoint. Returns a 1x1 transparent GIF and records the open event. Used in campaign emails.", + "operationId": "NewsletterController_trackOpen", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "description": "Campaign ID", + "schema": { "type": "string" } + }, + { + "name": "subscriberId", + "required": true, + "in": "path", + "description": "Subscriber ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Returns 1x1 transparent GIF" } + }, + "summary": "Track email open", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/tracking/click/{campaignId}/{subscriberId}": { + "get": { + "description": "Click tracking endpoint. Records the click event and redirects the subscriber to the target URL.", + "operationId": "NewsletterController_trackClick", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "description": "Campaign ID", + "schema": { "type": "string" } + }, + { + "name": "subscriberId", + "required": true, + "in": "path", + "description": "Subscriber ID", + "schema": { "type": "string" } + }, + { + "name": "url", + "required": true, + "in": "query", + "description": "Target URL to redirect to after tracking", + "schema": { + "example": "https://www.boundlessfi.xyz/hackathons", + "type": "string" + } + } + ], + "responses": { + "302": { "description": "Redirects to the target URL" } + }, + "summary": "Track email link click", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/subscribers": { + "get": { + "description": "Get a paginated list of newsletter subscribers with optional filters by status, source, tags, and search.", + "operationId": "NewsletterController_getSubscribers", + "parameters": [ + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by status", + "schema": { + "enum": ["active", "pending", "unsubscribed", "bounced"], + "type": "string" + } + }, + { + "name": "source", + "required": false, + "in": "query", + "description": "Filter by source", + "schema": { "example": "website", "type": "string" } + }, + { + "name": "tags", + "required": false, + "in": "query", + "description": "Filter by tags (comma-separated)", + "schema": { "example": "updates,hackathons", "type": "string" } + }, + { + "name": "search", + "required": false, + "in": "query", + "description": "Search by email or name", + "schema": { "example": "john", "type": "string" } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page (default: 50)", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { + "description": "Subscribers retrieved successfully", + "content": { + "application/json": { + "schema": { + "example": { + "subscribers": [], + "total": 0, + "page": 1, + "limit": 50 + } + } + } + } + }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "bearer": [] }], + "summary": "List newsletter subscribers", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/stats": { + "get": { + "description": "Get subscriber counts by status, subscription sources, and campaign statistics (sent, opens, clicks).", + "operationId": "NewsletterController_getStats", + "parameters": [], + "responses": { + "200": { + "description": "Statistics retrieved successfully", + "content": { + "application/json": { + "schema": { + "example": { + "subscribers": { + "total": 100, + "active": 80, + "pending": 10, + "unsubscribed": 8, + "bounced": 2 + }, + "bySource": [{ "source": "website", "count": 60 }], + "campaigns": { + "total": 5, + "totalSent": 400, + "totalOpens": 200, + "totalClicks": 50 + } + } + } + } + } + }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "bearer": [] }], + "summary": "Get newsletter statistics", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/export": { + "get": { + "description": "Download a CSV file of subscribers with optional status and tag filters.", + "operationId": "NewsletterController_exportSubscribers", + "parameters": [ + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by subscriber status", + "schema": { + "enum": ["active", "pending", "unsubscribed", "bounced"], + "type": "string" + } + }, + { + "name": "tags", + "required": false, + "in": "query", + "description": "Filter by tags (comma-separated)", + "schema": { "example": "updates,hackathons", "type": "string" } + } + ], + "responses": { + "200": { + "description": "CSV file downloaded", + "content": { "text/csv": {} } + }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "bearer": [] }], + "summary": "Export subscribers as CSV", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/subscribers/{id}": { + "delete": { + "description": "Permanently delete a newsletter subscriber by ID.", + "operationId": "NewsletterController_deleteSubscriber", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Subscriber ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Subscriber deleted successfully", + "content": { + "application/json": { + "schema": { "example": { "success": true } } + } + } + }, + "401": { "description": "Unauthorized" }, + "404": { "description": "Subscriber not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Delete a subscriber", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/campaigns": { + "post": { + "description": "Create a new newsletter campaign draft. Use {{name}} placeholder in content for personalization. Target specific subscribers using tags.", + "operationId": "NewsletterController_createCampaign", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNewsletterCampaignDto" + } + } + } + }, + "responses": { + "201": { "description": "Campaign created successfully" }, + "400": { "description": "Invalid tags provided" }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "bearer": [] }], + "summary": "Create a new campaign", + "tags": ["Newsletter"] + }, + "get": { + "description": "Get a paginated list of newsletter campaigns, ordered by most recent first.", + "operationId": "NewsletterController_getCampaigns", + "parameters": [ + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": { "type": "number" } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page (default: 20)", + "schema": { "type": "number" } + } + ], + "responses": { + "200": { + "description": "Campaigns retrieved successfully", + "content": { + "application/json": { + "schema": { + "example": { + "campaigns": [], + "total": 0, + "page": 1, + "limit": 20 + } + } + } + } + }, + "401": { "description": "Unauthorized" } + }, + "security": [{ "bearer": [] }], + "summary": "List newsletter campaigns", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/campaigns/{id}": { + "get": { + "description": "Get detailed information about a specific campaign, including the most recent 100 send logs.", + "operationId": "NewsletterController_getCampaign", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { "description": "Campaign details retrieved successfully" }, + "401": { "description": "Unauthorized" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Get campaign details", + "tags": ["Newsletter"] + } + }, + "/api/newsletter/campaigns/{id}/send": { + "post": { + "description": "Send a campaign to all matching subscribers. Delivers in batches of 10 with 1-second delays. Cannot re-send an already sent campaign.", + "operationId": "NewsletterController_sendCampaign", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Campaign ID to send", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Campaign sent successfully", + "content": { + "application/json": { + "schema": { + "example": { "sentCount": 80, "failedCount": 2, "total": 82 } + } + } + } + }, + "400": { + "description": "Campaign already sent or currently sending" + }, + "401": { "description": "Unauthorized" }, + "404": { "description": "Campaign not found" } + }, + "security": [{ "bearer": [] }], + "summary": "Send a campaign", + "tags": ["Newsletter"] + } + }, + "/api/admin/queues/dlq/depth": { + "get": { + "operationId": "DlqAdminController_getDepth", + "parameters": [], + "responses": { "200": { "description": "Total parked jobs" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Current DLQ depth (admin only)", + "tags": ["Admin / Queues"] + } + }, + "/api/admin/queues/dlq": { + "get": { + "operationId": "DlqAdminController_list", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "description": "Max entries to return (1 to 200, default 50)", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "List parked DLQ entries (admin only)", + "tags": ["Admin / Queues"] + } + }, + "/api/admin/queues/dlq/{jobId}": { + "get": { + "operationId": "DlqAdminController_getOne", + "parameters": [ + { + "name": "jobId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "200": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Fetch a single parked DLQ entry (admin only)", + "tags": ["Admin / Queues"] + } + }, + "/api/admin/queues/dlq/{jobId}/replay": { + "post": { + "description": "The DLQ row is removed on success. Replay uses the original queue's normal retry budget, so a job that died after 3 retries gets another 3 retries on replay.", + "operationId": "DlqAdminController_replay", + "parameters": [ + { + "name": "jobId", + "required": true, + "in": "path", + "schema": { "type": "string" } + } + ], + "responses": { "201": { "description": "" } }, + "security": [{ "JWT-auth": [] }], + "summary": "Re-enqueue a parked DLQ entry on its original queue", + "tags": ["Admin / Queues"] + } + }, + "/api/auth/sign-in/social": { + "post": { + "tags": ["Default"], + "description": "Sign in with a social provider", + "operationId": "socialSignIn", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "callbackURL": { + "type": ["string", "null"], + "description": "Callback URL to redirect to after the user has signed in" + }, + "newUserCallbackURL": { "type": ["string", "null"] }, + "errorCallbackURL": { + "type": ["string", "null"], + "description": "Callback URL to redirect to if an error happens" + }, + "provider": { "type": "string" }, + "disableRedirect": { + "type": ["boolean", "null"], + "description": "Disable automatic redirection to the provider. Useful for handling the redirection yourself" + }, + "idToken": { + "type": ["object", "null"], + "properties": { + "token": { + "type": "string", + "description": "ID token from the provider" + }, + "nonce": { + "type": ["string", "null"], + "description": "Nonce used to generate the token" + }, + "accessToken": { + "type": ["string", "null"], + "description": "Access token from the provider" + }, + "refreshToken": { + "type": ["string", "null"], + "description": "Refresh token from the provider" + }, + "expiresAt": { + "type": ["number", "null"], + "description": "Expiry date of the token" + } + }, + "required": ["token"] + }, + "scopes": { + "type": ["array", "null"], + "description": "Array of scopes to request from the provider. This will override the default scopes passed." + }, + "requestSignUp": { + "type": ["boolean", "null"], + "description": "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" + }, + "loginHint": { + "type": ["string", "null"], + "description": "The login hint to use for the authorization code request" + }, + "additionalData": { "type": ["string", "null"] } + }, + "required": ["provider"] + } + } + } + }, + "responses": { + "200": { + "description": "Success - Returns either session details or redirect URL", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Session response when idToken is provided", + "properties": { + "token": { "type": "string" }, + "user": { + "type": "object", + "$ref": "#/components/schemas/User" + }, + "url": { "type": "string" }, + "redirect": { "type": "boolean", "enum": [false] } + }, + "required": ["redirect", "token", "user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/get-session": { + "get": { + "tags": ["Default"], + "description": "Get the current session", + "operationId": "getSession", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "nullable": true, + "properties": { + "session": { "$ref": "#/components/schemas/Session" }, + "user": { "$ref": "#/components/schemas/User" } + }, + "required": ["session", "user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/sign-out": { + "post": { + "tags": ["Default"], + "description": "Sign out the current user", + "operationId": "signOut", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { "type": "object", "properties": {} } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/sign-up/email": { + "post": { + "tags": ["Default"], + "description": "Sign up a user using email and password", + "operationId": "signUpWithEmailAndPassword", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the user" + }, + "email": { + "type": "string", + "description": "The email of the user" + }, + "password": { + "type": "string", + "description": "The password of the user" + }, + "image": { + "type": "string", + "description": "The profile image URL of the user" + }, + "callbackURL": { + "type": "string", + "description": "The URL to use for email verification callback" + }, + "rememberMe": { + "type": "boolean", + "description": "If this is false, the session will not be remembered. Default is `true`." + } + }, + "required": ["name", "email", "password"] + } + } + } + }, + "responses": { + "200": { + "description": "Successfully created user", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "nullable": true, + "description": "Authentication token for the session" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the user" + }, + "email": { + "type": "string", + "format": "email", + "description": "The email address of the user" + }, + "name": { + "type": "string", + "description": "The name of the user" + }, + "image": { + "type": "string", + "format": "uri", + "nullable": true, + "description": "The profile image URL of the user" + }, + "emailVerified": { + "type": "boolean", + "description": "Whether the email has been verified" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the user was created" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the user was last updated" + } + }, + "required": [ + "id", + "email", + "name", + "emailVerified", + "createdAt", + "updatedAt" + ] + } + }, + "required": ["user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "422": { + "description": "Unprocessable Entity. User already exists or failed to create user.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + } + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/sign-in/email": { + "post": { + "tags": ["Default"], + "description": "Sign in with email and password", + "operationId": "signInEmail", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email of the user" + }, + "password": { + "type": "string", + "description": "Password of the user" + }, + "callbackURL": { + "type": ["string", "null"], + "description": "Callback URL to use as a redirect for email verification" + }, + "rememberMe": { + "type": ["boolean", "null"], + "description": "If this is false, the session will not be remembered. Default is `true`.", + "default": true + } + }, + "required": ["email", "password"] + } + } + } + }, + "responses": { + "200": { + "description": "Success - Returns either session details or redirect URL", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Session response when idToken is provided", + "properties": { + "redirect": { "type": "boolean", "enum": [false] }, + "token": { + "type": "string", + "description": "Session token" + }, + "url": { "type": "string", "nullable": true }, + "user": { + "type": "object", + "$ref": "#/components/schemas/User" + } + }, + "required": ["redirect", "token", "user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/reset-password": { + "post": { + "tags": ["Default"], + "description": "Reset the password for a user", + "operationId": "resetPassword", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "newPassword": { + "type": "string", + "description": "The new password to set" + }, + "token": { + "type": ["string", "null"], + "description": "The token to reset the password" + } + }, + "required": ["newPassword"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/verify-password": { + "post": { + "tags": ["Default"], + "description": "Verify the current user's password", + "operationId": "verifyPassword", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string", + "description": "The password to verify" + } + }, + "required": ["password"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/verify-email": { + "get": { + "tags": ["Default"], + "description": "Verify the email of the user", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "token", + "in": "query", + "description": "The token to verify the email", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "callbackURL", + "in": "query", + "description": "The URL to redirect to after email verification", + "required": false, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "$ref": "#/components/schemas/User" + }, + "status": { + "type": "boolean", + "description": "Indicates if the email was verified successfully" + } + }, + "required": ["user", "status"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/send-verification-email": { + "post": { + "tags": ["Default"], + "description": "Send a verification email to the user", + "operationId": "sendVerificationEmail", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "The email to send the verification email to", + "example": "user@example.com" + }, + "callbackURL": { + "type": "string", + "description": "The URL to use for email verification callback", + "example": "https://example.com/callback", + "nullable": true + } + }, + "required": ["email"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "boolean", + "description": "Indicates if the email was sent successfully", + "example": true + } + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Error message", + "example": "Verification email isn't enabled" + } + } + } + } + } + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/change-email": { + "post": { + "tags": ["Default"], + "operationId": "changeEmail", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "newEmail": { + "type": "string", + "description": "The new email address to set must be a valid email address" + }, + "callbackURL": { + "type": ["string", "null"], + "description": "The URL to redirect to after email verification" + } + }, + "required": ["newEmail"] + } + } + } + }, + "responses": { + "200": { + "description": "Email change request processed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "$ref": "#/components/schemas/User" + }, + "status": { + "type": "boolean", + "description": "Indicates if the request was successful" + }, + "message": { + "type": "string", + "enum": ["Email updated", "Verification email sent"], + "description": "Status message of the email change process", + "nullable": true + } + }, + "required": ["status"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "422": { + "description": "Unprocessable Entity. Email already exists", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + } + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/change-password": { + "post": { + "tags": ["Default"], + "description": "Change the password of the user", + "operationId": "changePassword", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "newPassword": { + "type": "string", + "description": "The new password to set" + }, + "currentPassword": { + "type": "string", + "description": "The current password is required" + }, + "revokeOtherSessions": { + "type": ["boolean", "null"], + "description": "Must be a boolean value" + } + }, + "required": ["newPassword", "currentPassword"] + } + } + } + }, + "responses": { + "200": { + "description": "Password successfully changed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "nullable": true, + "description": "New session token if other sessions were revoked" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the user" + }, + "email": { + "type": "string", + "format": "email", + "description": "The email address of the user" + }, + "name": { + "type": "string", + "description": "The name of the user" + }, + "image": { + "type": "string", + "format": "uri", + "nullable": true, + "description": "The profile image URL of the user" + }, + "emailVerified": { + "type": "boolean", + "description": "Whether the email has been verified" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the user was created" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the user was last updated" + } + }, + "required": [ + "id", + "email", + "name", + "emailVerified", + "createdAt", + "updatedAt" + ] + } + }, + "required": ["user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/update-user": { + "post": { + "tags": ["Default"], + "description": "Update the current user", + "operationId": "updateUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the user" + }, + "image": { + "type": "string", + "description": "The image of the user", + "nullable": true + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "$ref": "#/components/schemas/User" + } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/delete-user": { + "post": { + "tags": ["Default"], + "description": "Delete the user", + "operationId": "deleteUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "callbackURL": { + "type": "string", + "description": "The callback URL to redirect to after the user is deleted" + }, + "password": { + "type": "string", + "description": "The user's password. Required if session is not fresh" + }, + "token": { + "type": "string", + "description": "The deletion verification token" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "User deletion processed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Indicates if the operation was successful" + }, + "message": { + "type": "string", + "enum": ["User deleted", "Verification email sent"], + "description": "Status message of the deletion process" + } + }, + "required": ["success", "message"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/request-password-reset": { + "post": { + "tags": ["Default"], + "description": "Send a password reset email to the user", + "operationId": "requestPasswordReset", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "The email address of the user to send a password reset email to" + }, + "redirectTo": { + "type": ["string", "null"], + "description": "The URL to redirect the user to reset their password. If the token isn't valid or expired, it'll be redirected with a query parameter `?error=INVALID_TOKEN`. If the token is valid, it'll be redirected with a query parameter `?token=VALID_TOKEN" + } + }, + "required": ["email"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { "type": "boolean" }, + "message": { "type": "string" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/reset-password/{token}": { + "get": { + "tags": ["Default"], + "description": "Redirects the user to the callback URL with the token", + "operationId": "resetPasswordCallback", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "token", + "in": "path", + "required": true, + "description": "The token to reset the password", + "schema": { "type": "string" } + }, + { + "name": "callbackURL", + "in": "query", + "required": true, + "description": "The URL to redirect the user to reset their password", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "token": { "type": "string" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/list-sessions": { + "get": { + "tags": ["Default"], + "description": "List all active sessions for the user", + "operationId": "listUserSessions", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/Session" } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/revoke-session": { + "post": { + "tags": ["Default"], + "description": "Revoke a single session", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "The token to revoke" + } + }, + "required": ["token"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "boolean", + "description": "Indicates if the session was revoked successfully" + } + }, + "required": ["status"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/revoke-sessions": { + "post": { + "tags": ["Default"], + "description": "Revoke all sessions for the user", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { "type": "object", "properties": {} } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "boolean", + "description": "Indicates if all sessions were revoked successfully" + } + }, + "required": ["status"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/revoke-other-sessions": { + "post": { + "tags": ["Default"], + "description": "Revoke all other sessions for the user except the current one", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { "type": "object", "properties": {} } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "boolean", + "description": "Indicates if all other sessions were revoked successfully" + } + }, + "required": ["status"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/link-social": { + "post": { + "tags": ["Default"], + "description": "Link a social account to the user", + "operationId": "linkSocialAccount", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "callbackURL": { + "type": ["string", "null"], + "description": "The URL to redirect to after the user has signed in" + }, + "provider": { "type": "string" }, + "idToken": { + "type": ["object", "null"], + "properties": { + "token": { "type": "string" }, + "nonce": { "type": ["string", "null"] }, + "accessToken": { "type": ["string", "null"] }, + "refreshToken": { "type": ["string", "null"] }, + "scopes": { "type": ["array", "null"] } + }, + "required": ["token"] + }, + "requestSignUp": { "type": ["boolean", "null"] }, + "scopes": { + "type": ["array", "null"], + "description": "Additional scopes to request from the provider" + }, + "errorCallbackURL": { + "type": ["string", "null"], + "description": "The URL to redirect to if there is an error during the link process" + }, + "disableRedirect": { + "type": ["boolean", "null"], + "description": "Disable automatic redirection to the provider. Useful for handling the redirection yourself" + }, + "additionalData": { "type": ["string", "null"] } + }, + "required": ["provider"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The authorization URL to redirect the user to" + }, + "redirect": { + "type": "boolean", + "description": "Indicates if the user should be redirected to the authorization URL" + }, + "status": { "type": "boolean" } + }, + "required": ["redirect"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/list-accounts": { + "get": { + "tags": ["Default"], + "description": "List all accounts linked to the user", + "operationId": "listUserAccounts", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "providerId": { "type": "string" }, + "createdAt": { "type": "string", "format": "date-time" }, + "updatedAt": { "type": "string", "format": "date-time" }, + "accountId": { "type": "string" }, + "userId": { "type": "string" }, + "scopes": { + "type": "array", + "items": { "type": "string" } + } + }, + "required": [ + "id", + "providerId", + "createdAt", + "updatedAt", + "accountId", + "userId", + "scopes" + ] + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/delete-user/callback": { + "get": { + "tags": ["Default"], + "description": "Callback to complete user deletion with verification token", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "token", + "in": "query", + "schema": { + "type": "string", + "description": "The token to verify the deletion request" + } + }, + { + "name": "callbackURL", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "The URL to redirect to after deletion" + } + } + ], + "responses": { + "200": { + "description": "User successfully deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Indicates if the deletion was successful" + }, + "message": { + "type": "string", + "enum": ["User deleted"], + "description": "Confirmation message" + } + }, + "required": ["success", "message"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/unlink-account": { + "post": { + "tags": ["Default"], + "description": "Unlink an account", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "providerId": { "type": "string" }, + "accountId": { "type": ["string", "null"] } + }, + "required": ["providerId"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/refresh-token": { + "post": { + "tags": ["Default"], + "description": "Refresh the access token using a refresh token", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "providerId": { + "type": "string", + "description": "The provider ID for the OAuth provider" + }, + "accountId": { + "type": ["string", "null"], + "description": "The account ID associated with the refresh token" + }, + "userId": { + "type": ["string", "null"], + "description": "The user ID associated with the account" + } + }, + "required": ["providerId"] + } + } + } + }, + "responses": { + "200": { + "description": "Access token refreshed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tokenType": { "type": "string" }, + "idToken": { "type": "string" }, + "accessToken": { "type": "string" }, + "refreshToken": { "type": "string" }, + "accessTokenExpiresAt": { + "type": "string", + "format": "date-time" + }, + "refreshTokenExpiresAt": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "400": { + "description": "Invalid refresh token or provider configuration" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/get-access-token": { + "post": { + "tags": ["Default"], + "description": "Get a valid access token, doing a refresh if needed", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "providerId": { + "type": "string", + "description": "The provider ID for the OAuth provider" + }, + "accountId": { + "type": ["string", "null"], + "description": "The account ID associated with the refresh token" + }, + "userId": { + "type": ["string", "null"], + "description": "The user ID associated with the account" + } + }, + "required": ["providerId"] + } + } + } + }, + "responses": { + "200": { + "description": "A Valid access token", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tokenType": { "type": "string" }, + "idToken": { "type": "string" }, + "accessToken": { "type": "string" }, + "accessTokenExpiresAt": { + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "400": { + "description": "Invalid refresh token or provider configuration" + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/account-info": { + "get": { + "tags": ["Default"], + "description": "Get the account info provided by the provider", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "email": { "type": "string" }, + "image": { "type": "string" }, + "emailVerified": { "type": "boolean" } + }, + "required": ["id", "emailVerified"] + }, + "data": { + "type": "object", + "properties": {}, + "additionalProperties": true + } + }, + "required": ["user", "data"], + "additionalProperties": false + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/ok": { + "get": { + "tags": ["Default"], + "description": "Check if the API is working", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "API is working", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ok": { + "type": "boolean", + "description": "Indicates if the API is working" + } + }, + "required": ["ok"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/error": { + "get": { + "tags": ["Default"], + "description": "Displays an error page", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "text/html": { + "schema": { + "type": "string", + "description": "The HTML content of the error page" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/sign-in/username": { + "post": { + "tags": ["Username"], + "description": "Sign in with username", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "The username of the user" + }, + "password": { + "type": "string", + "description": "The password of the user" + }, + "rememberMe": { + "type": ["boolean", "null"], + "description": "Remember the user session" + }, + "callbackURL": { + "type": ["string", "null"], + "description": "The URL to redirect to after email verification" + } + }, + "required": ["username", "password"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Session token for the authenticated session" + }, + "user": { "$ref": "#/components/schemas/User" } + }, + "required": ["token", "user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "422": { + "description": "Unprocessable Entity. Validation error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + } + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/is-username-available": { + "post": { + "tags": ["Username"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "The username to check" + } + }, + "required": ["username"] + } + } + } + }, + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/get-totp-uri": { + "post": { + "tags": ["Two-factor"], + "description": "Use this endpoint to get the TOTP URI", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string", + "description": "User password" + } + }, + "required": ["password"] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "totpURI": { "type": "string" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/verify-totp": { + "post": { + "tags": ["Two-factor"], + "description": "Verify two factor TOTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "The otp code to verify. Eg: \"012345\"" + }, + "trustDevice": { + "type": ["boolean", "null"], + "description": "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" + } + }, + "required": ["code"] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/send-otp": { + "post": { + "tags": ["Two-factor"], + "description": "Send two factor OTP to the user", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/verify-otp": { + "post": { + "tags": ["Two-factor"], + "description": "Verify two factor OTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "The otp code to verify. Eg: \"012345\"" + }, + "trustDevice": { "type": ["boolean", "null"] } + }, + "required": ["code"] + } + } + } + }, + "responses": { + "200": { + "description": "Two-factor OTP verified successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Session token for the authenticated session" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the user" + }, + "email": { + "type": "string", + "format": "email", + "nullable": true, + "description": "User's email address" + }, + "emailVerified": { + "type": "boolean", + "nullable": true, + "description": "Whether the email is verified" + }, + "name": { + "type": "string", + "nullable": true, + "description": "User's name" + }, + "image": { + "type": "string", + "format": "uri", + "nullable": true, + "description": "User's profile image URL" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the user was created" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the user was last updated" + } + }, + "required": ["id", "createdAt", "updatedAt"], + "description": "The authenticated user object" + } + }, + "required": ["token", "user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/verify-backup-code": { + "post": { + "tags": ["Two-factor"], + "description": "Verify a backup code for two-factor authentication", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "A backup code to verify. Eg: \"123456\"" + }, + "disableSession": { + "type": ["boolean", "null"], + "description": "If true, the session cookie will not be set." + }, + "trustDevice": { + "type": ["boolean", "null"], + "description": "If true, the device will be trusted for 30 days. It'll be refreshed on every sign in request within this time. Eg: true" + } + }, + "required": ["code"] + } + } + } + }, + "responses": { + "200": { + "description": "Backup code verified successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the user" + }, + "email": { + "type": "string", + "format": "email", + "nullable": true, + "description": "User's email address" + }, + "emailVerified": { + "type": "boolean", + "nullable": true, + "description": "Whether the email is verified" + }, + "name": { + "type": "string", + "nullable": true, + "description": "User's name" + }, + "image": { + "type": "string", + "format": "uri", + "nullable": true, + "description": "User's profile image URL" + }, + "twoFactorEnabled": { + "type": "boolean", + "description": "Whether two-factor authentication is enabled for the user" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the user was created" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the user was last updated" + } + }, + "required": [ + "id", + "twoFactorEnabled", + "createdAt", + "updatedAt" + ], + "description": "The authenticated user object with two-factor details" + }, + "session": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Session token" + }, + "userId": { + "type": "string", + "description": "ID of the user associated with the session" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the session was created" + }, + "expiresAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the session expires" + } + }, + "required": ["token", "userId", "createdAt", "expiresAt"], + "description": "The current session object, included unless disableSession is true" + } + }, + "required": ["user", "session"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/generate-backup-codes": { + "post": { + "tags": ["Two-factor"], + "description": "Generate new backup codes for two-factor authentication", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string", + "description": "The users password." + } + }, + "required": ["password"] + } + } + } + }, + "responses": { + "200": { + "description": "Backup codes generated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "boolean", + "description": "Indicates if the backup codes were generated successfully", + "enum": [true] + }, + "backupCodes": { + "type": "array", + "items": { "type": "string" }, + "description": "Array of generated backup codes in plain text" + } + }, + "required": ["status", "backupCodes"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/enable": { + "post": { + "tags": ["Two-factor"], + "description": "Use this endpoint to enable two factor authentication. This will generate a TOTP URI and backup codes. Once the user verifies the TOTP URI, the two factor authentication will be enabled.", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string", + "description": "User password" + }, + "issuer": { + "type": ["string", "null"], + "description": "Custom issuer for the TOTP URI" + } + }, + "required": ["password"] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "totpURI": { "type": "string", "description": "TOTP URI" }, + "backupCodes": { + "type": "array", + "items": { "type": "string" }, + "description": "Backup codes" + } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/two-factor/disable": { + "post": { + "tags": ["Two-factor"], + "description": "Use this endpoint to disable two factor authentication.", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "password": { + "type": "string", + "description": "User password" + } + }, + "required": ["password"] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/one-tap/callback": { + "post": { + "tags": ["One-tap"], + "description": "Use this endpoint to authenticate with Google One Tap", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "idToken": { + "type": "string", + "description": "Google ID token, which the client obtains from the One Tap API" + } + }, + "required": ["idToken"] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "session": { "$ref": "#/components/schemas/Session" }, + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { "description": "Invalid token" }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/email-otp/send-verification-otp": { + "post": { + "tags": ["Email-otp"], + "description": "Send a verification OTP to an email", + "operationId": "sendEmailVerificationOTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to send the OTP" + }, + "type": { "type": "string", "description": "Type of the OTP" } + }, + "required": ["email", "type"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/email-otp/check-verification-otp": { + "post": { + "tags": ["Email-otp"], + "description": "Verify an email with an OTP", + "operationId": "verifyEmailWithOTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address the OTP was sent to" + }, + "type": { + "type": "string", + "description": "Type of the OTP" + }, + "otp": { "type": "string", "description": "OTP to verify" } + }, + "required": ["email", "type", "otp"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/email-otp/verify-email": { + "post": { + "tags": ["Email-otp"], + "description": "Verify email with OTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to verify" + }, + "otp": { "type": "string", "description": "OTP to verify" } + }, + "required": ["email", "otp"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "boolean", + "description": "Indicates if the verification was successful", + "enum": [true] + }, + "token": { + "type": "string", + "nullable": true, + "description": "Session token if autoSignInAfterVerification is enabled, otherwise null" + }, + "user": { "$ref": "#/components/schemas/User" } + }, + "required": ["status", "token", "user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/sign-in/email-otp": { + "post": { + "tags": ["Email-otp"], + "description": "Sign in with email and OTP", + "operationId": "signInWithEmailOTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to sign in" + }, + "otp": { + "type": "string", + "description": "OTP sent to the email" + } + }, + "required": ["email", "otp"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Session token for the authenticated session" + }, + "user": { "$ref": "#/components/schemas/User" } + }, + "required": ["token", "user"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/email-otp/request-password-reset": { + "post": { + "tags": ["Email-otp"], + "description": "Request password reset with email and OTP", + "operationId": "requestPasswordResetWithEmailOTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to send the OTP" + } + }, + "required": ["email"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Indicates if the OTP was sent successfully" + } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/forget-password/email-otp": { + "post": { + "tags": ["Email-otp"], + "description": "Deprecated: Use /email-otp/request-password-reset instead.", + "operationId": "forgetPasswordWithEmailOTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to send the OTP" + } + }, + "required": ["email"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Indicates if the OTP was sent successfully" + } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/email-otp/reset-password": { + "post": { + "tags": ["Email-otp"], + "description": "Reset password with email and OTP", + "operationId": "resetPasswordWithEmailOTP", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to reset the password" + }, + "otp": { + "type": "string", + "description": "OTP sent to the email" + }, + "password": { + "type": "string", + "description": "New password" + } + }, + "required": ["email", "otp", "password"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/create": { + "post": { + "tags": ["Organization"], + "description": "Create an organization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the organization" + }, + "slug": { + "type": "string", + "description": "The slug of the organization" + }, + "userId": { + "type": ["string", "null"], + "description": "The user id of the organization creator. If not provided, the current user will be used. Should only be used by admins or when called by the server. server-only. Eg: \"user-id\"" + }, + "logo": { + "type": ["string", "null"], + "description": "The logo of the organization" + }, + "metadata": { + "type": ["string", "null"], + "description": "The metadata of the organization" + }, + "keepCurrentActiveOrganization": { + "type": ["boolean", "null"], + "description": "Whether to keep the current active organization active after creating a new one. Eg: true" + } + }, + "required": ["name", "slug"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "The organization that was created", + "$ref": "#/components/schemas/Organization" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/update": { + "post": { + "tags": ["Organization"], + "description": "Update an organization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "name": { + "type": ["string", "null"], + "description": "The name of the organization" + }, + "slug": { + "type": ["string", "null"], + "description": "The slug of the organization" + }, + "logo": { + "type": ["string", "null"], + "description": "The logo of the organization" + }, + "metadata": { + "type": ["string", "null"], + "description": "The metadata of the organization" + } + } + }, + "organizationId": { + "type": ["string", "null"], + "description": "The organization ID. Eg: \"org-id\"" + } + }, + "required": ["data"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "The updated organization", + "$ref": "#/components/schemas/Organization" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/delete": { + "post": { + "tags": ["Organization"], + "description": "Delete an organization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "The organization id to delete" + } + }, + "required": ["organizationId"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "string", + "description": "The organization id that was deleted" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/set-active": { + "post": { + "tags": ["Organization"], + "description": "Set the active organization", + "operationId": "setActiveOrganization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "organizationId": { "type": ["string", "null"] }, + "organizationSlug": { + "type": ["string", "null"], + "description": "The organization slug to set as active. It can be null to unset the active organization if organizationId is not provided. Eg: \"org-slug\"" + } + }, + "required": [] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "The organization", + "$ref": "#/components/schemas/Organization" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/get-full-organization": { + "get": { + "tags": ["Organization"], + "description": "Get the full organization", + "operationId": "getOrganization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "The organization", + "$ref": "#/components/schemas/Organization" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/list": { + "get": { + "tags": ["Organization"], + "description": "List all organizations", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/Organization" } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/invite-member": { + "post": { + "tags": ["Organization"], + "description": "Create an invitation to an organization", + "operationId": "createOrganizationInvitation", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "The email address of the user to invite" + }, + "role": { + "type": "string", + "description": "The role(s) to assign to the user. It can be `admin`, `member`, owner. Eg: \"member\"" + }, + "organizationId": { + "type": ["string", "null"], + "description": "The organization ID to invite the user to" + }, + "resend": { + "type": ["boolean", "null"], + "description": "Resend the invitation email, if the user is already invited. Eg: true" + }, + "teamId": { "type": "string" } + }, + "required": ["email", "role", "teamId"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "email": { "type": "string" }, + "role": { "type": "string" }, + "organizationId": { "type": "string" }, + "inviterId": { "type": "string" }, + "status": { "type": "string" }, + "expiresAt": { "type": "string" }, + "createdAt": { "type": "string" } + }, + "required": [ + "id", + "email", + "role", + "organizationId", + "inviterId", + "status", + "expiresAt", + "createdAt" + ] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/cancel-invitation": { + "post": { + "tags": ["Organization"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "invitationId": { + "type": "string", + "description": "The ID of the invitation to cancel" + } + }, + "required": ["invitationId"] + } + } + } + }, + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/accept-invitation": { + "post": { + "tags": ["Organization"], + "description": "Accept an invitation to an organization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "invitationId": { + "type": "string", + "description": "The ID of the invitation to accept" + } + }, + "required": ["invitationId"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "invitation": { "type": "object" }, + "member": { "type": "object" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/get-invitation": { + "get": { + "tags": ["Organization"], + "description": "Get an invitation by ID", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "type": "string", + "description": "The ID of the invitation to get" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "email": { "type": "string" }, + "role": { "type": "string" }, + "organizationId": { "type": "string" }, + "inviterId": { "type": "string" }, + "status": { "type": "string" }, + "expiresAt": { "type": "string" }, + "organizationName": { "type": "string" }, + "organizationSlug": { "type": "string" }, + "inviterEmail": { "type": "string" } + }, + "required": [ + "id", + "email", + "role", + "organizationId", + "inviterId", + "status", + "expiresAt", + "organizationName", + "organizationSlug", + "inviterEmail" + ] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/reject-invitation": { + "post": { + "tags": ["Organization"], + "description": "Reject an invitation to an organization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "invitationId": { + "type": "string", + "description": "The ID of the invitation to reject" + } + }, + "required": ["invitationId"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "invitation": { "type": "object" }, + "member": { "type": "object", "nullable": true } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/list-invitations": { + "get": { + "tags": ["Organization"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/get-active-member": { + "get": { + "tags": ["Organization"], + "description": "Get the member details of the active organization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "userId": { "type": "string" }, + "organizationId": { "type": "string" }, + "role": { "type": "string" } + }, + "required": ["id", "userId", "organizationId", "role"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/check-slug": { + "post": { + "tags": ["Organization"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string", + "description": "The organization slug to check. Eg: \"my-org\"" + } + }, + "required": ["slug"] + } + } + } + }, + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/remove-member": { + "post": { + "tags": ["Organization"], + "description": "Remove a member from an organization", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "memberIdOrEmail": { + "type": "string", + "description": "The ID or email of the member to remove" + }, + "organizationId": { + "type": ["string", "null"], + "description": "The ID of the organization to remove the member from. If not provided, the active organization will be used. Eg: \"org-id\"" + } + }, + "required": ["memberIdOrEmail"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "member": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "userId": { "type": "string" }, + "organizationId": { "type": "string" }, + "role": { "type": "string" } + }, + "required": ["id", "userId", "organizationId", "role"] + } + }, + "required": ["member"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/update-member-role": { + "post": { + "tags": ["Organization"], + "description": "Update the role of a member in an organization", + "operationId": "updateOrganizationMemberRole", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "type": "string", + "description": "The new role to be applied. This can be a string or array of strings representing the roles. Eg: [\"admin\", \"sale\"]" + }, + "memberId": { + "type": "string", + "description": "The member id to apply the role update to. Eg: \"member-id\"" + }, + "organizationId": { + "type": ["string", "null"], + "description": "An optional organization ID which the member is a part of to apply the role update. If not provided, you must provide session headers to get the active organization. Eg: \"organization-id\"" + } + }, + "required": ["role", "memberId"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "member": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "userId": { "type": "string" }, + "organizationId": { "type": "string" }, + "role": { "type": "string" } + }, + "required": ["id", "userId", "organizationId", "role"] + } + }, + "required": ["member"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/leave": { + "post": { + "tags": ["Organization"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "The organization Id for the member to leave. Eg: \"organization-id\"" + } + }, + "required": ["organizationId"] + } + } + } + }, + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/list-user-invitations": { + "get": { + "tags": ["Organization"], + "description": "List all invitations a user has received", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "email": { "type": "string" }, + "role": { "type": "string" }, + "organizationId": { "type": "string" }, + "organizationName": { "type": "string" }, + "inviterId": { + "type": "string", + "description": "The ID of the user who created the invitation" + }, + "teamId": { + "type": "string", + "description": "The ID of the team associated with the invitation", + "nullable": true + }, + "status": { "type": "string" }, + "expiresAt": { "type": "string" }, + "createdAt": { "type": "string" } + }, + "required": [ + "id", + "email", + "role", + "organizationId", + "organizationName", + "inviterId", + "status", + "expiresAt", + "createdAt" + ] + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/list-members": { + "get": { + "tags": ["Organization"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/get-active-member-role": { + "get": { + "tags": ["Organization"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/organization/has-permission": { + "post": { + "tags": ["Organization"], + "description": "Check if the user has permission", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "permission": { + "type": "object", + "description": "The permission to check", + "deprecated": true + }, + "permissions": { + "type": "object", + "description": "The permission to check" + } + }, + "required": ["permissions"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { "type": "string" }, + "success": { "type": "boolean" } + }, + "required": ["success"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/set-role": { + "post": { + "tags": ["Admin"], + "description": "Set the role of a user", + "operationId": "setUserRole", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" }, + "role": { + "type": "string", + "description": "The role to set, this can be a string or an array of strings. Eg: `admin` or `[admin, user]`" + } + }, + "required": ["userId", "role"] + } + } + } + }, + "responses": { + "200": { + "description": "User role updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/get-user": { + "get": { + "tags": ["Admin"], + "description": "Get an existing user", + "operationId": "getUser", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { "type": "string", "description": "The id of the User" } + } + ], + "responses": { + "200": { + "description": "User", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/create-user": { + "post": { + "tags": ["Admin"], + "description": "Create a new user", + "operationId": "createUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "The email of the user" + }, + "password": { "type": ["string", "null"] }, + "name": { + "type": "string", + "description": "The name of the user" + }, + "role": { "type": ["string", "null"] }, + "data": { "type": ["string", "null"] } + }, + "required": ["email", "name"] + } + } + } + }, + "responses": { + "200": { + "description": "User created", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/update-user": { + "post": { + "tags": ["Admin"], + "description": "Update a user's details", + "operationId": "updateUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" }, + "data": { + "type": "string", + "description": "The user data to update" + } + }, + "required": ["userId", "data"] + } + } + } + }, + "responses": { + "200": { + "description": "User updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/list-users": { + "get": { + "tags": ["Admin"], + "description": "List users", + "operationId": "listUsers", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "searchValue", + "in": "query", + "schema": { "type": ["string", "null"] } + }, + { + "name": "searchField", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "The field to search in, defaults to email. Can be `email` or `name`. Eg: \"name\"" + } + }, + { + "name": "searchOperator", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "The operator to use for the search. Can be `contains`, `starts_with` or `ends_with`. Eg: \"contains\"" + } + }, + { + "name": "limit", + "in": "query", + "schema": { "type": ["string", "null"] } + }, + { + "name": "offset", + "in": "query", + "schema": { "type": ["string", "null"] } + }, + { + "name": "sortBy", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "The field to sort by" + } + }, + { + "name": "sortDirection", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "The direction to sort by" + } + }, + { + "name": "filterField", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "The field to filter by" + } + }, + { + "name": "filterValue", + "in": "query", + "schema": { "type": ["string", "null"] } + }, + { + "name": "filterOperator", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "The operator to use for the filter" + } + } + ], + "responses": { + "200": { + "description": "List of users", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { "$ref": "#/components/schemas/User" } + }, + "total": { "type": "number" }, + "limit": { "type": "number" }, + "offset": { "type": "number" } + }, + "required": ["users", "total"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/list-user-sessions": { + "post": { + "tags": ["Admin"], + "description": "List user sessions", + "operationId": "listUserSessions", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" } + }, + "required": ["userId"] + } + } + } + }, + "responses": { + "200": { + "description": "List of user sessions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessions": { + "type": "array", + "items": { "$ref": "#/components/schemas/Session" } + } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/unban-user": { + "post": { + "tags": ["Admin"], + "description": "Unban a user", + "operationId": "unbanUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" } + }, + "required": ["userId"] + } + } + } + }, + "responses": { + "200": { + "description": "User unbanned", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/ban-user": { + "post": { + "tags": ["Admin"], + "description": "Ban a user", + "operationId": "banUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" }, + "banReason": { + "type": ["string", "null"], + "description": "The reason for the ban" + }, + "banExpiresIn": { + "type": ["number", "null"], + "description": "The number of seconds until the ban expires" + } + }, + "required": ["userId"] + } + } + } + }, + "responses": { + "200": { + "description": "User banned", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/impersonate-user": { + "post": { + "tags": ["Admin"], + "description": "Impersonate a user", + "operationId": "impersonateUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" } + }, + "required": ["userId"] + } + } + } + }, + "responses": { + "200": { + "description": "Impersonation session created", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "session": { "$ref": "#/components/schemas/Session" }, + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/stop-impersonating": { + "post": { + "tags": ["Admin"], + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/revoke-user-session": { + "post": { + "tags": ["Admin"], + "description": "Revoke a user session", + "operationId": "revokeUserSession", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionToken": { + "type": "string", + "description": "The session token" + } + }, + "required": ["sessionToken"] + } + } + } + }, + "responses": { + "200": { + "description": "Session revoked", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/revoke-user-sessions": { + "post": { + "tags": ["Admin"], + "description": "Revoke all user sessions", + "operationId": "revokeUserSessions", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" } + }, + "required": ["userId"] + } + } + } + }, + "responses": { + "200": { + "description": "Sessions revoked", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/remove-user": { + "post": { + "tags": ["Admin"], + "description": "Delete a user and all their sessions and accounts. Cannot be undone.", + "operationId": "removeUser", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "The user id" } + }, + "required": ["userId"] + } + } + } + }, + "responses": { + "200": { + "description": "User removed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/set-user-password": { + "post": { + "tags": ["Admin"], + "description": "Set a user's password", + "operationId": "setUserPassword", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "newPassword": { + "type": "string", + "description": "The new password" + }, + "userId": { "type": "string", "description": "The user id" } + }, + "required": ["newPassword", "userId"] + } + } + } + }, + "responses": { + "200": { + "description": "Password set", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/admin/has-permission": { + "post": { + "tags": ["Admin"], + "description": "Check if the user has permission", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "permission": { + "type": "object", + "description": "The permission to check", + "deprecated": true + }, + "permissions": { + "type": "object", + "description": "The permission to check" + } + }, + "required": ["permissions"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { "type": "string" }, + "success": { "type": "boolean" } + }, + "required": ["success"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/passkey/generate-register-options": { + "get": { + "tags": ["Passkey"], + "description": "Generate registration options for a new passkey", + "operationId": "generatePasskeyRegistrationOptions", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "parameters": { + "query": { + "authenticatorAttachment": { + "description": "Type of authenticator to use for registration.\n \"platform\" for device-specific authenticators,\n \"cross-platform\" for authenticators that can be used across devices.", + "required": false + }, + "name": { + "description": "Optional custom name for the passkey.\n This can help identify the passkey when managing multiple credentials.", + "required": false + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "challenge": { "type": "string" }, + "rp": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "id": { "type": "string" } + } + }, + "user": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "displayName": { "type": "string" } + } + }, + "pubKeyCredParams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { "type": "string" }, + "alg": { "type": "number" } + } + } + }, + "timeout": { "type": "number" }, + "excludeCredentials": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "type": { "type": "string" }, + "transports": { + "type": "array", + "items": { "type": "string" } + } + } + } + }, + "authenticatorSelection": { + "type": "object", + "properties": { + "authenticatorAttachment": { "type": "string" }, + "requireResidentKey": { "type": "boolean" }, + "userVerification": { "type": "string" } + } + }, + "attestation": { "type": "string" }, + "extensions": { "type": "object" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/passkey/generate-authenticate-options": { + "get": { + "tags": ["Passkey"], + "description": "Generate authentication options for a passkey", + "operationId": "passkeyGenerateAuthenticateOptions", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "challenge": { "type": "string" }, + "rp": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "id": { "type": "string" } + } + }, + "user": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "displayName": { "type": "string" } + } + }, + "timeout": { "type": "number" }, + "allowCredentials": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "type": { "type": "string" }, + "transports": { + "type": "array", + "items": { "type": "string" } + } + } + } + }, + "userVerification": { "type": "string" }, + "authenticatorSelection": { + "type": "object", + "properties": { + "authenticatorAttachment": { "type": "string" }, + "requireResidentKey": { "type": "boolean" }, + "userVerification": { "type": "string" } + } + }, + "extensions": { "type": "object" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/passkey/verify-registration": { + "post": { + "tags": ["Passkey"], + "description": "Verify registration of a new passkey", + "operationId": "passkeyVerifyRegistration", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "response": { "type": "string" }, + "name": { + "type": ["string", "null"], + "description": "Name of the passkey" + } + }, + "required": ["response"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/Passkey" } + } + } + }, + "400": { "description": "Bad request" }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/passkey/verify-authentication": { + "post": { + "tags": ["Passkey"], + "description": "Verify authentication of a passkey", + "operationId": "passkeyVerifyAuthentication", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "response": { "type": "string" } }, + "required": ["response"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "session": { "$ref": "#/components/schemas/Session" }, + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/passkey/list-user-passkeys": { + "get": { + "tags": ["Passkey"], + "description": "List all passkeys for the authenticated user", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "responses": { + "200": { + "description": "Passkeys retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Passkey", + "required": [ + "id", + "userId", + "publicKey", + "createdAt", + "updatedAt" + ] + }, + "description": "Array of passkey objects associated with the user" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/passkey/delete-passkey": { + "post": { + "tags": ["Passkey"], + "description": "Delete a specific passkey", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the passkey to delete. Eg: \"some-passkey-id\"" + } + }, + "required": ["id"] + } + } + } + }, + "responses": { + "200": { + "description": "Passkey deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "type": "boolean", + "description": "Indicates whether the deletion was successful" + } + }, + "required": ["status"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/passkey/update-passkey": { + "post": { + "tags": ["Passkey"], + "description": "Update a specific passkey's name", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the passkey which will be updated. Eg: \"passkey-id\"" + }, + "name": { + "type": "string", + "description": "The new name which the passkey will be updated to. Eg: \"my-new-passkey-name\"" + } + }, + "required": ["id", "name"] + } + } + } + }, + "responses": { + "200": { + "description": "Passkey updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "passkey": { "$ref": "#/components/schemas/Passkey" } + }, + "required": ["passkey"] + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/sign-in/magic-link": { + "post": { + "tags": ["Magic-link"], + "description": "Sign in with magic link", + "operationId": "signInWithMagicLink", + "security": [{ "bearerAuth": [] }], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to send the magic link" + }, + "name": { + "type": ["string", "null"], + "description": "User display name. Only used if the user is registering for the first time. Eg: \"my-name\"" + }, + "callbackURL": { + "type": ["string", "null"], + "description": "URL to redirect after magic link verification" + }, + "newUserCallbackURL": { + "type": ["string", "null"], + "description": "URL to redirect after new user signup. Only used if the user is registering for the first time." + }, + "errorCallbackURL": { + "type": ["string", "null"], + "description": "URL to redirect after error." + } + }, + "required": ["email"] + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "status": { "type": "boolean" } } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + }, + "/api/auth/magic-link/verify": { + "get": { + "tags": ["Magic-link"], + "description": "Verify magic link", + "operationId": "verifyMagicLink", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "token", + "in": "query", + "schema": { "type": "string", "description": "Verification token" } + }, + { + "name": "callbackURL", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "URL to redirect after magic link verification, if not provided the user will be redirected to the root URL. Eg: \"/dashboard\"" + } + }, + { + "name": "errorCallbackURL", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "URL to redirect after error." + } + }, + { + "name": "newUserCallbackURL", + "in": "query", + "schema": { + "type": ["string", "null"], + "description": "URL to redirect after new user signup. Only used if the user is registering for the first time." + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "session": { "$ref": "#/components/schemas/Session" }, + "user": { "$ref": "#/components/schemas/User" } + } + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Bad Request. Usually due to missing parameters, or invalid parameters." + }, + "401": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + }, + "description": "Unauthorized. Due to missing or invalid authentication." + }, + "403": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Forbidden. You do not have permission to access this resource or to perform this action." + }, + "404": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Not Found. The requested resource was not found." + }, + "429": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Too Many Requests. You have exceeded the rate limit. Try again later." + }, + "500": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + } + }, + "description": "Internal Server Error. This is a problem with the server that you cannot fix." + } + } + } + } + }, + "info": { + "title": "Boundless API", + "description": "The Boundless API description", + "version": "1.0", + "contact": {} + }, + "tags": [ + { "name": "boundless", "description": "" }, + { + "name": "Default", + "description": "Default endpoints that are included with Better Auth by default. These endpoints are not part of any plugin." + } + ], + "servers": [ + { "url": "http://localhost:8000", "description": "Development server" } + ], + "components": { + "securitySchemes": { + "JWT-auth": { + "scheme": "bearer", + "bearerFormat": "JWT", + "type": "http", + "name": "JWT", + "description": "Enter JWT token", + "in": "header" + }, + "apiKeyCookie": { + "type": "apiKey", + "in": "cookie", + "name": "apiKeyCookie", + "description": "API Key authentication via cookie" + }, + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "description": "Bearer token authentication" + } + }, + "schemas": { + "NotificationPreferencesDto": { "type": "object", "properties": {} }, + "UpdatePrivacySettingsDto": { + "type": "object", + "properties": { + "publicProfile": { + "type": "boolean", + "description": "Public profile", + "example": true + }, + "emailVisibility": { + "type": "boolean", + "description": "Email visibility", + "example": true + }, + "locationVisibility": { + "type": "boolean", + "description": "Location visibility", + "example": true + }, + "companyVisibility": { + "type": "boolean", + "description": "Company visibility", + "example": true + }, + "websiteVisibility": { + "type": "boolean", + "description": "Website visibility", + "example": true + }, + "socialLinksVisibility": { + "type": "boolean", + "description": "Social links visibility", + "example": true + } + }, + "required": [ + "publicProfile", + "emailVisibility", + "locationVisibility", + "companyVisibility", + "websiteVisibility", + "socialLinksVisibility" + ] + }, + "UpdateAppearanceSettingsDto": { + "type": "object", + "properties": { + "theme": { + "type": "string", + "description": "Theme", + "example": "light", + "enum": ["light", "dark", "auto"] + } + }, + "required": ["theme"] + }, + "PublicEarningsSummaryDto": { + "type": "object", + "properties": { + "totalEarned": { + "type": "number", + "description": "All-time total earned (normalized, e.g. USDC 7 decimals)", + "example": 50000 + } + }, + "required": ["totalEarned"] + }, + "EarningsBreakdownDto": { + "type": "object", + "properties": { + "hackathons": { + "type": "number", + "description": "Total from hackathons", + "example": 20000 + }, + "grants": { + "type": "number", + "description": "Total from grants", + "example": 10000 + }, + "crowdfunding": { + "type": "number", + "description": "Total from crowdfunding", + "example": 15000 + }, + "bounties": { + "type": "number", + "description": "Total from bounties", + "example": 5000 + } + }, + "required": ["hackathons", "grants", "crowdfunding", "bounties"] + }, + "PublicEarningActivityDto": { + "type": "object", + "properties": { + "id": { "type": "string", "description": "Unique activity id" }, + "source": { + "type": "string", + "description": "Earnings source category", + "enum": ["hackathons", "grants", "crowdfunding", "bounties"] + }, + "title": { + "type": "string", + "description": "Human-readable title", + "example": "Winner of Stellar Hackathon Q1" + }, + "amount": { + "type": "number", + "description": "Amount (normalized)", + "example": 5000 + }, + "currency": { + "type": "string", + "description": "Currency code", + "example": "USDC" + }, + "occurredAt": { + "type": "string", + "description": "When the earning occurred (ISO date string)", + "example": "2024-01-19T14:30:00Z" + } + }, + "required": [ + "id", + "source", + "title", + "amount", + "currency", + "occurredAt" + ] + }, + "PublicEarningsResponseDto": { + "type": "object", + "properties": { + "summary": { + "$ref": "#/components/schemas/PublicEarningsSummaryDto" + }, + "breakdown": { "$ref": "#/components/schemas/EarningsBreakdownDto" }, + "activities": { + "description": "Verified activity history (completed only)", + "type": "array", + "items": { "$ref": "#/components/schemas/PublicEarningActivityDto" } + } + }, + "required": ["summary", "breakdown", "activities"] + }, + "EarningsSummaryDto": { + "type": "object", + "properties": { + "totalEarned": { + "type": "number", + "description": "All-time total earned (normalized, e.g. USDC 7 decimals)", + "example": 50000 + }, + "pendingWithdrawal": { + "type": "number", + "description": "Amount currently claimable / pending withdrawal", + "example": 10000 + }, + "completedWithdrawal": { + "type": "number", + "description": "Amount already paid out (completed withdrawals)", + "example": 40000 + } + }, + "required": ["totalEarned", "pendingWithdrawal", "completedWithdrawal"] + }, + "EarningActivityDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique activity id (e.g. submissionId or milestoneId)" + }, + "source": { + "type": "string", + "description": "Earnings source category", + "enum": ["hackathons", "grants", "crowdfunding", "bounties"] + }, + "title": { + "type": "string", + "description": "Human-readable title", + "example": "Winner of Stellar Hackathon Q1" + }, + "amount": { + "type": "number", + "description": "Amount (normalized)", + "example": 5000 + }, + "currency": { + "type": "string", + "description": "Currency code", + "example": "USDC" + }, + "status": { + "type": "string", + "description": "Activity status", + "enum": ["pending", "claimable", "completed"] + }, + "occurredAt": { + "type": "string", + "description": "When the earning occurred (ISO date string)", + "example": "2024-01-19T14:30:00Z" + }, + "entityId": { + "type": "string", + "description": "Entity id for claim (e.g. submissionId, milestoneId)" + } + }, + "required": [ + "id", + "source", + "title", + "amount", + "currency", + "status", + "occurredAt" + ] + }, + "EarningsResponseDto": { + "type": "object", + "properties": { + "summary": { "$ref": "#/components/schemas/EarningsSummaryDto" }, + "breakdown": { "$ref": "#/components/schemas/EarningsBreakdownDto" }, + "activities": { + "description": "Activity feed", + "type": "array", + "items": { "$ref": "#/components/schemas/EarningActivityDto" } + } + }, + "required": ["summary", "breakdown", "activities"] + }, + "WithdrawItemDto": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Source of the claimable (crowdfunding or grants; user claims release to wallet)", + "enum": ["crowdfunding", "grants"] + }, + "entityId": { + "type": "string", + "description": "Entity id (e.g. milestoneId for crowdfunding or grants)" + } + }, + "required": ["source", "entityId"] + }, + "WithdrawRequestDto": { + "type": "object", + "properties": { + "items": { + "description": "Items to claim (source + entityId). Only crowdfunding supported (grants not yet). Payout goes to user's linked wallet.", + "type": "array", + "items": { "$ref": "#/components/schemas/WithdrawItemDto" } + } + } + }, + "ConfirmReleaseDto": { + "type": "object", + "properties": { + "signedXdr": { + "type": "string", + "description": "Signed XDR from creator/grantee wallet (release milestone transaction from real wallet)" + }, + "entityId": { + "type": "string", + "description": "Entity id (e.g. crowdfunding milestone id)" + }, + "source": { + "type": "string", + "description": "Source of the claimable (only crowdfunding supported for confirm-release)", + "example": "crowdfunding", + "enum": ["crowdfunding"] + } + }, + "required": ["signedXdr", "entityId", "source"] + }, + "ConfirmReleaseResponseDto": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the release was submitted successfully", + "example": true + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash once the release is executed on-chain" + }, + "message": { + "type": "string", + "description": "Human-readable message", + "example": "Release submitted successfully" + } + }, + "required": ["success"] + }, + "DashboardUserStatsDto": { + "type": "object", + "properties": { + "followers": { "type": "number" }, + "following": { "type": "number" } + }, + "required": ["followers", "following"] + }, + "DashboardUserDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string", "nullable": true }, + "email": { "type": "string" }, + "username": { "type": "string", "nullable": true }, + "displayUsername": { "type": "string", "nullable": true }, + "image": { "type": "string", "nullable": true }, + "role": { "type": "string" }, + "createdAt": { "format": "date-time", "type": "string" }, + "stats": { "$ref": "#/components/schemas/DashboardUserStatsDto" } + }, + "required": [ + "id", + "name", + "email", + "username", + "displayUsername", + "image", + "role", + "createdAt" + ] + }, + "UserStatsDto": { + "type": "object", + "properties": { + "projectsCreated": { "type": "number" }, + "projectsFunded": { "type": "number" }, + "totalContributed": { "type": "number" }, + "commentsPosted": { "type": "number" }, + "votes": { "type": "number" }, + "grants": { "type": "number" }, + "hackathons": { "type": "number" }, + "followers": { "type": "number" }, + "following": { "type": "number" }, + "reputation": { "type": "number" }, + "communityScore": { "type": "number" } + }, + "required": [ + "projectsCreated", + "projectsFunded", + "totalContributed", + "commentsPosted", + "votes", + "grants", + "hackathons", + "followers", + "following", + "reputation", + "communityScore" + ] + }, + "ChartDataPointDto": { + "type": "object", + "properties": { + "date": { + "type": "string", + "description": "Date in YYYY-MM-DD format" + }, + "count": { "type": "number", "description": "Count for that date" } + }, + "required": ["date", "count"] + }, + "ChartDto": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { "$ref": "#/components/schemas/ChartDataPointDto" } + } + }, + "required": ["data"] + }, + "ActivitiesGraphDto": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { "$ref": "#/components/schemas/ChartDataPointDto" } + } + }, + "required": ["data"] + }, + "ActivityProjectDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "banner": { "type": "string", "nullable": true }, + "logo": { "type": "string", "nullable": true } + }, + "required": ["id", "title"] + }, + "ActivityOrganizationDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + }, + "required": ["id", "name"] + }, + "RecentActivityDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "type": { "type": "string" }, + "userId": { "type": "string" }, + "projectId": { "type": "string", "nullable": true }, + "organizationId": { "type": "string", "nullable": true }, + "createdAt": { "format": "date-time", "type": "string" }, + "project": { "$ref": "#/components/schemas/ActivityProjectDto" }, + "organization": { + "$ref": "#/components/schemas/ActivityOrganizationDto" + } + }, + "required": ["id", "type", "userId", "createdAt"] + }, + "DashboardDto": { + "type": "object", + "properties": { + "user": { + "description": "User profile data", + "allOf": [{ "$ref": "#/components/schemas/DashboardUserDto" }] + }, + "stats": { "$ref": "#/components/schemas/UserStatsDto" }, + "chart": { "$ref": "#/components/schemas/ChartDto" }, + "activitiesGraph": { + "$ref": "#/components/schemas/ActivitiesGraphDto" + }, + "recentActivities": { + "description": "Recent activities", + "type": "array", + "items": { "$ref": "#/components/schemas/RecentActivityDto" } + } + }, + "required": [ + "user", + "stats", + "chart", + "activitiesGraph", + "recentActivities" + ] + }, + "UpdateProfileDto": { "type": "object", "properties": {} }, + "UpdateUserDto": { "type": "object", "properties": {} }, + "UploadResponseDto": { "type": "object", "properties": {} }, + "MultipleUploadResponseDto": { "type": "object", "properties": {} }, + "FileInfoResponseDto": { "type": "object", "properties": {} }, + "SearchFilesResponseDto": { "type": "object", "properties": {} }, + "OptimizedUrlResponseDto": { "type": "object", "properties": {} }, + "ResponsiveUrlsResponseDto": { "type": "object", "properties": {} }, + "UsageStatsResponseDto": { "type": "object", "properties": {} }, + "RegisterDto": { "type": "object", "properties": {} }, + "LoginDto": { "type": "object", "properties": {} }, + "RefreshTokenDto": { "type": "object", "properties": {} }, + "VerifySignatureDto": { "type": "object", "properties": {} }, + "CreateConversationDto": { + "type": "object", + "properties": { + "otherUserId": { + "type": "string", + "description": "User ID of the other participant" + } + }, + "required": ["otherUserId"] + }, + "CreateMessageDto": { + "type": "object", + "properties": { + "body": { + "type": "string", + "description": "Message text", + "maxLength": 10000 + } + }, + "required": ["body"] + }, + "ContactDto": { "type": "object", "properties": {} }, + "CreateCampaignDto": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Title of the campaign", + "example": "Web3 Campaign" + }, + "logo": { + "type": "string", + "description": "Logo of the campaign", + "example": "https://example.com/logo.png" + }, + "vision": { + "type": "string", + "description": "Vision of the campaign", + "example": "Web3 Campaign" + }, + "banner": { + "type": "string", + "description": "Banner image URL of the campaign", + "example": "https://example.com/banner.png" + }, + "category": { + "type": "string", + "description": "Category of the campaign", + "example": "web3" + }, + "details": { + "type": "string", + "description": "Details of the campaign", + "example": "Web3 Campaign" + }, + "fundingAmount": { + "type": "number", + "description": "Funding amount of the campaign", + "example": 1000 + }, + "githubUrl": { + "type": "string", + "description": "Github URL of the campaign", + "example": "https://github.com/example/project" + }, + "gitlabUrl": { + "type": "string", + "description": "Gitlab URL of the campaign", + "example": "https://gitlab.com/example/project" + }, + "bitbucketUrl": { + "type": "string", + "description": "Bitbucket URL of the campaign", + "example": "https://bitbucket.com/example/project" + }, + "projectWebsite": { + "type": "string", + "description": "Project website of the campaign", + "example": "https://example.com/project" + }, + "demoVideo": { + "type": "string", + "description": "Demo video of the campaign", + "example": "https://example.com/demo.mp4" + }, + "milestones": { + "description": "Milestones of the campaign", + "example": [ + { + "name": "Milestone 1", + "description": "Milestone 1 description", + "startDate": "2025-01-01", + "endDate": "2025-01-02", + "amount": 1000 + } + ], + "type": "array", + "items": { "type": "string" } + }, + "team": { + "description": "Team of the campaign", + "example": [ + { + "name": "John Doe", + "role": "Developer", + "email": "john.doe@example.com", + "linkedin": "https://linkedin.com/in/john-doe", + "twitter": "https://twitter.com/john-doe" + } + ], + "type": "array", + "items": { "type": "string" } + }, + "contact": { + "description": "Contact of the campaign", + "example": { + "primary": "john.doe", + "backup": "john.doe@example.com" + }, + "allOf": [{ "$ref": "#/components/schemas/ContactDto" }] + }, + "socialLinks": { + "description": "Social links of the campaign", + "example": [ + { "platform": "twitter", "url": "https://twitter.com/john-doe" } + ], + "type": "array", + "items": { "type": "string" } + }, + "escrowId": { + "type": "string", + "description": "Escrow contract ID for the campaign", + "example": "CCAJPWPKSR6FY5Q5RYT5E3EIZQNDMDFYVVKJ656C5SUOIXQOQ4JQVWGV" + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash of the deployed escrow contract", + "example": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6" + } + }, + "required": [ + "title", + "logo", + "vision", + "banner", + "category", + "details", + "fundingAmount", + "githubUrl", + "gitlabUrl", + "bitbucketUrl", + "projectWebsite", + "demoVideo", + "milestones", + "team", + "contact", + "socialLinks" + ] + }, + "UpdateCampaignDto": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Title of the campaign", + "example": "Web3 Campaign" + }, + "logo": { + "type": "string", + "description": "Logo of the campaign", + "example": "https://example.com/logo.png" + }, + "vision": { + "type": "string", + "description": "Vision of the campaign", + "example": "Web3 Campaign" + }, + "banner": { + "type": "string", + "description": "Banner image URL of the campaign", + "example": "https://example.com/banner.png" + }, + "category": { + "type": "string", + "description": "Category of the campaign", + "example": "web3" + }, + "details": { + "type": "string", + "description": "Details of the campaign", + "example": "Web3 Campaign" + }, + "fundingAmount": { + "type": "number", + "description": "Funding amount of the campaign", + "example": 1000 + }, + "githubUrl": { + "type": "string", + "description": "Github URL of the campaign", + "example": "https://github.com/example/project" + }, + "gitlabUrl": { + "type": "string", + "description": "Gitlab URL of the campaign", + "example": "https://gitlab.com/example/project" + }, + "bitbucketUrl": { + "type": "string", + "description": "Bitbucket URL of the campaign", + "example": "https://bitbucket.com/example/project" + }, + "projectWebsite": { + "type": "string", + "description": "Project website of the campaign", + "example": "https://example.com/project" + }, + "demoVideo": { + "type": "string", + "description": "Demo video of the campaign", + "example": "https://example.com/demo.mp4" + }, + "milestones": { + "description": "Milestones of the campaign", + "example": [ + { + "name": "Milestone 1", + "description": "Milestone 1 description", + "startDate": "2025-01-01", + "endDate": "2025-01-02", + "amount": 1000 + } + ], + "type": "array", + "items": { "type": "string" } + }, + "team": { + "description": "Team of the campaign", + "example": [ + { + "name": "John Doe", + "role": "Developer", + "email": "john.doe@example.com", + "linkedin": "https://linkedin.com/in/john-doe", + "twitter": "https://twitter.com/john-doe" + } + ], + "type": "array", + "items": { "type": "string" } + }, + "contact": { + "description": "Contact of the campaign", + "example": { + "primary": "john.doe", + "backup": "john.doe@example.com" + }, + "allOf": [{ "$ref": "#/components/schemas/ContactDto" }] + }, + "socialLinks": { + "description": "Social links of the campaign", + "example": [ + { "platform": "twitter", "url": "https://twitter.com/john-doe" } + ], + "type": "array", + "items": { "type": "string" } + }, + "escrowId": { + "type": "string", + "description": "Escrow contract ID for the campaign", + "example": "CCAJPWPKSR6FY5Q5RYT5E3EIZQNDMDFYVVKJ656C5SUOIXQOQ4JQVWGV" + }, + "transactionHash": { + "type": "string", + "description": "Transaction hash of the deployed escrow contract", + "example": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6" + } + } + }, + "UpdateEscrowDto": { + "type": "object", + "properties": { + "transactionHash": { + "type": "string", + "description": "Transaction hash of the deployed escrow contract", + "example": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6" + }, + "escrowAddress": { + "type": "string", + "description": "Escrow contract address", + "example": "CCAJPWPKSR6FY5Q5RYT5E3EIZQNDMDFYVVKJ656C5SUOIXQOQ4JQVWGV" + }, + "trustlessWorkStatus": { + "type": "string", + "description": "Trustless Work status", + "example": "deployed", + "enum": ["pending", "deployed", "funded", "failed"] + }, + "escrowType": { + "type": "string", + "description": "Escrow type", + "example": "multi-release", + "enum": ["single-release", "multi-release"] + } + } + }, + "InviteTeamMemberDto": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "user@example.com", + "description": "The email address of the team member to invite" + }, + "role": { + "type": "string", + "example": "Developer", + "description": "The role of the team member in the campaign" + } + }, + "required": ["email", "role"] + }, + "ContributeCampaignDto": { + "type": "object", + "properties": { + "amount": { + "type": "number", + "description": "Amount of the contribution", + "example": 100 + }, + "message": { + "type": "string", + "description": "Optional message from the contributor", + "example": "I love this campaign!" + }, + "anonymous": { + "type": "boolean", + "description": "Whether to make this contribution anonymous", + "example": false, + "default": false + } + }, + "required": ["amount"] + }, + "ValidateMilestoneSubmissionDto": { + "type": "object", + "properties": { + "proofOfWorkFiles": { + "description": "Array of proof of work file URLs (documents, images, reports, etc.) - must be valid URLs with http, https, or ipfs protocol", + "example": [ + "https://example.com/report.pdf", + "https://example.com/screenshot.png" + ], + "type": "array", + "items": { "type": "string" } + }, + "proofOfWorkLinks": { + "description": "Array of proof of work links (GitHub PRs, demos, deployed sites, etc.) - must be valid URLs", + "example": [ + "https://github.com/user/repo/pull/123", + "https://demo.example.com" + ], + "type": "array", + "items": { "type": "string" } + }, + "submissionNotes": { + "type": "string", + "description": "Additional notes about the submission - optional but must be at least 10 characters if provided", + "minLength": 10, + "example": "Successfully deployed the MVP with all core features implemented and tested." + } + }, + "required": ["proofOfWorkFiles", "proofOfWorkLinks"] + }, + "UpdateMilestoneDto": { + "type": "object", + "properties": { + "proofOfWorkFiles": { + "description": "Array of proof of work file URLs (documents, images, etc.)", + "type": "array", + "items": { "type": "string" } + }, + "proofOfWorkLinks": { + "description": "Array of proof of work links (GitHub PRs, demos, etc.)", + "type": "array", + "items": { "type": "string" } + }, + "submissionNotes": { + "type": "string", + "description": "Additional notes about the submission", + "minLength": 10 + } + }, + "required": ["proofOfWorkFiles", "proofOfWorkLinks"] + }, + "PublishCrowdfundingEscrowDto": { + "type": "object", + "properties": { + "builderAddress": { + "type": "string", + "description": "Stellar G-address that signs create_event. Strictly the builder's Boundless abstracted wallet (D9). MANAGED funding is the only path.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "tokenAddress": { + "type": "string", + "description": "Whitelisted SAC token contract (USDC by default).", + "example": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" + }, + "fundingGoal": { + "type": "string", + "description": "Funding goal in token-native units (e.g. 5000 = 5000 USDC). Informational on chain; backers determine the actual raised total.", + "example": "5000" + }, + "nMilestones": { + "type": "number", + "description": "Number of milestones for ReleaseKind::Multi(n).", + "example": 3 + }, + "fundingDeadline": { + "type": "number", + "description": "Funding deadline as Unix seconds.", + "example": 1735689600 + }, + "contentUri": { + "type": "string", + "description": "Override content URI." + } + }, + "required": [ + "builderAddress", + "tokenAddress", + "fundingGoal", + "nMilestones", + "fundingDeadline" + ] + }, + "CancelCrowdfundingEscrowDto": { + "type": "object", + "properties": { + "builderAddress": { + "type": "string", + "description": "Builder G-address." + } + }, + "required": ["builderAddress"] + }, + "ClaimCrowdfundingMilestoneDto": { + "type": "object", + "properties": { + "builderAddress": { + "type": "string", + "description": "Builder G-address (must match campaign)." + }, + "crowdfundingMilestoneId": { + "type": "string", + "description": "Crowdfunding milestone id." + } + }, + "required": ["builderAddress", "crowdfundingMilestoneId"] + }, + "ContributeCrowdfundingDto": { + "type": "object", + "properties": { + "contributorAddress": { + "type": "string", + "description": "G-address that signs add_funds.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "walletOrigin": { + "type": "string", + "description": "Wallet origin: BOUNDLESS uses the managed signer; EXTERNAL returns an unsigned XDR for the connected wallet (D9).", + "enum": ["BOUNDLESS", "EXTERNAL"], + "example": "BOUNDLESS" + }, + "amount": { + "type": "string", + "description": "Amount in token-native units (10 USDC minimum).", + "example": "25" + }, + "message": { + "type": "string", + "description": "Optional message attached." + }, + "anonymous": { + "type": "boolean", + "description": "Hide displayName / usernameSnapshot if true.", + "default": false + } + }, + "required": ["contributorAddress", "walletOrigin", "amount"] + }, + "CastCrowdfundingVoteDto": { + "type": "object", + "properties": { + "choice": { + "type": "string", + "description": "UP supports the campaign, DOWN opposes it.", + "enum": ["UP", "DOWN"], + "example": "UP" + } + }, + "required": ["choice"] + }, + "ApproveCrowdfundingCampaignDto": { + "type": "object", + "properties": { + "delegatedReviewerId": { + "type": "string", + "description": "The user delegated to validate this campaign's milestones. D6=A: exactly one reviewer per campaign, assigned at approval time.", + "example": "user_1234567890" + } + }, + "required": ["delegatedReviewerId"] + }, + "RejectCrowdfundingCampaignDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Reason for rejection; surfaced to the builder." + } + } + }, + "PauseCrowdfundingCampaignDto": { + "type": "object", + "properties": { + "reason": { "type": "string", "description": "Reason for the pause." } + } + }, + "ReclaimDormantDto": { + "type": "object", + "properties": { + "minIdleDays": { + "type": "number", + "description": "Minimum days a wallet must have been idle to be eligible. Default 90.", + "minimum": 7, + "maximum": 3650, + "example": 90 + }, + "maxToProcess": { + "type": "number", + "description": "Maximum number of wallets to reclaim in this call. Hard-capped at 100.", + "minimum": 1, + "maximum": 100, + "example": 25 + }, + "dryRun": { + "type": "boolean", + "description": "When true (default), report what would be reclaimed without submitting transactions. Set false to actually merge accounts.", + "example": true + } + } + }, + "AddTrustlineDto": { + "type": "object", + "properties": { + "assetCode": { + "type": "string", + "description": "Asset code to add a trustline for (e.g. USDC, EURC)", + "example": "USDC", + "minLength": 1, + "maxLength": 12 + } + }, + "required": ["assetCode"] + }, + "UserSendDto": { + "type": "object", + "properties": { + "destinationPublicKey": { + "type": "string", + "description": "Stellar destination public key (G...)", + "example": "GABCD..." + }, + "amount": { + "type": "number", + "description": "Amount to send (positive number)", + "example": 100.5 + }, + "currency": { + "type": "string", + "description": "Asset code (XLM, USDC, EURC, etc.)", + "example": "USDC" + }, + "memo": { + "type": "string", + "description": "Memo (required by some exchanges). Max 28 bytes UTF-8." + }, + "memoRequired": { + "type": "boolean", + "description": "If true, request fails when memo is missing (e.g. exchange requires it)" + }, + "idempotencyKey": { + "type": "string", + "description": "Idempotency key to prevent duplicate sends" + } + }, + "required": ["destinationPublicKey", "amount", "currency"] + }, + "SendPayoutDto": { + "type": "object", + "properties": { + "destinationPublicKey": { + "type": "string", + "description": "Stellar destination public key (G...)", + "example": "GABCD..." + }, + "amount": { + "type": "number", + "description": "Amount to send (positive number)", + "example": 100.5 + }, + "currency": { + "type": "string", + "description": "Asset code (XLM, USDC, EURC, etc. – must be supported on network)", + "example": "USDC" + }, + "memo": { + "type": "string", + "description": "Memo (required by some exchanges). Max 28 bytes UTF-8." + }, + "memoType": { + "type": "string", + "description": "Memo type", + "enum": ["text", "id"] + }, + "memoRequired": { + "type": "boolean", + "description": "If true, request fails when memo is missing (e.g. exchange requires it)" + }, + "idempotencyKey": { + "type": "string", + "description": "Idempotency key to prevent duplicate payouts" + }, + "reference": { + "type": "string", + "description": "Reference for audit (e.g. earnings-payout-123)" + } + }, + "required": ["destinationPublicKey", "amount", "currency"] + }, + "CreateCommentDto": { + "type": "object", + "properties": { + "content": { + "type": "string", + "description": "Comment content", + "example": "This is a great project!", + "minLength": 1, + "maxLength": 2000 + }, + "entityType": { + "type": "string", + "description": "Entity type for the comment", + "enum": [ + "PROJECT", + "BOUNTY", + "CROWDFUNDING_CAMPAIGN", + "GRANT", + "GRANT_APPLICATION", + "HACKATHON", + "HACKATHON_SUBMISSION", + "BLOG_POST" + ], + "example": "PROJECT" + }, + "entityId": { + "type": "string", + "description": "Entity ID for the comment", + "example": "cm12345abcde" + }, + "parentId": { + "type": "string", + "description": "Parent comment ID for threaded replies", + "example": "cm12345abcde" + } + }, + "required": ["content", "entityType", "entityId"] + }, + "UpdateCommentDto": { "type": "object", "properties": {} }, + "AddReactionDto": { + "type": "object", + "properties": { + "reactionType": { + "type": "string", + "description": "Type of reaction", + "enum": [ + "LIKE", + "DISLIKE", + "LOVE", + "LAUGH", + "THUMBS_UP", + "THUMBS_DOWN", + "FIRE", + "ROCKET" + ], + "example": "LIKE" + } + }, + "required": ["reactionType"] + }, + "ReportCommentDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Reason for reporting the comment", + "enum": [ + "SPAM", + "HARASSMENT", + "HATE_SPEECH", + "INAPPROPRIATE_CONTENT", + "COPYRIGHT_VIOLATION", + "OTHER" + ], + "example": "SPAM" + }, + "description": { + "type": "string", + "description": "Additional details about the report", + "example": "This comment contains unsolicited advertising", + "maxLength": 500 + } + }, + "required": ["reason"] + }, + "ResolveReportDto": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Resolution status for the report", + "enum": ["PENDING", "REVIEWED", "RESOLVED", "DISMISSED"], + "example": "RESOLVED" + }, + "resolution": { + "type": "string", + "description": "Moderator notes about the resolution", + "example": "Comment was reviewed and found to violate community guidelines", + "maxLength": 500 + } + }, + "required": ["status"] + }, + "HackathonsListResponseDto": { "type": "object", "properties": {} }, + "FeeEstimateResponseDto": { + "type": "object", + "properties": { + "totalPool": { + "type": "number", + "example": 5000, + "description": "Total prize pool (USDC)" + }, + "feeRate": { + "type": "number", + "example": 0.023, + "description": "Fee rate as decimal" + }, + "feeRatePercent": { + "type": "number", + "example": 2.3, + "description": "Fee rate as percentage" + }, + "feeAmount": { + "type": "number", + "example": 115, + "description": "Fee amount (USDC)" + }, + "totalFunds": { + "type": "number", + "example": 5115, + "description": "Total to pay (prize pool + fee)" + }, + "feeLabel": { + "type": "string", + "example": "Platform Fee (2.3%)", + "description": "Display label for the fee" + } + }, + "required": [ + "totalPool", + "feeRate", + "feeRatePercent", + "feeAmount", + "totalFunds", + "feeLabel" + ] + }, + "ParticipantDto": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "Username of the participant" + }, + "avatar": { + "type": "object", + "description": "Avatar URL of the participant" + } + }, + "required": ["username"] + }, + "HackathonWinnerDto": { + "type": "object", + "properties": { + "rank": { + "type": "number", + "description": "Rank of the winner (1, 2, 3, etc.)" + }, + "projectName": { + "type": "string", + "description": "Name of the project" + }, + "teamName": { "type": "object", "description": "Name of the team" }, + "logo": { "type": "object", "description": "Logo of the project" }, + "participants": { + "description": "List of participants", + "type": "array", + "items": { "$ref": "#/components/schemas/ParticipantDto" } + }, + "prize": { "type": "string", "description": "Prize information" }, + "submissionId": { "type": "string", "description": "Submission ID" } + }, + "required": [ + "rank", + "projectName", + "participants", + "prize", + "submissionId" + ] + }, + "HackathonWinnersResponseDto": { + "type": "object", + "properties": { + "hackathonId": { "type": "string", "description": "Hackathon ID" }, + "winners": { + "description": "List of winners", + "type": "array", + "items": { "$ref": "#/components/schemas/HackathonWinnerDto" } + } + }, + "required": ["hackathonId", "winners"] + }, + "PublicAggregatedJudgingResultDto": { + "type": "object", + "properties": { + "submissionId": { "type": "string" }, + "projectName": { "type": "string" }, + "teamId": { "type": "object" }, + "participantId": { "type": "string" }, + "status": { "type": "string" }, + "submittedAt": { "format": "date-time", "type": "string" }, + "averageScore": { "type": "number" }, + "totalScore": { "type": "number" }, + "judgeCount": { "type": "number" }, + "expectedJudgeCount": { "type": "number" }, + "judgingProgress": { "type": "string" }, + "rank": { "type": "object" }, + "isComplete": { "type": "boolean" }, + "isPending": { "type": "boolean" }, + "hasDisagreement": { "type": "boolean" } + }, + "required": [ + "submissionId", + "projectName", + "participantId", + "status", + "submittedAt", + "averageScore", + "totalScore", + "judgeCount", + "expectedJudgeCount", + "judgingProgress", + "isComplete", + "isPending", + "hasDisagreement" + ] + }, + "JudgingResultsMetadataDto": { + "type": "object", + "properties": { + "sortedBy": { "type": "string" }, + "includesVariance": { "type": "boolean" }, + "includesIndividualScores": { "type": "boolean" }, + "includesProgressTracking": { "type": "boolean" }, + "onlyWinners": { "type": "boolean" } + }, + "required": [ + "sortedBy", + "includesVariance", + "includesIndividualScores", + "includesProgressTracking" + ] + }, + "PublicJudgingResultsResponseDto": { + "type": "object", + "properties": { + "hackathonId": { "type": "string" }, + "totalSubmissions": { "type": "number" }, + "submissionsScoredCount": { "type": "number" }, + "submissionsPendingCount": { "type": "number" }, + "averageScoreAcrossAll": { "type": "number" }, + "resultsPublished": { "type": "boolean" }, + "judgesAssigned": { "type": "number" }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublicAggregatedJudgingResultDto" + } + }, + "generatedAt": { "format": "date-time", "type": "string" }, + "winnerOverrides": { + "type": "object", + "additionalProperties": { "type": "number" }, + "description": "Manual winner assignments override (submissionId -> rank)" + }, + "metadata": { + "$ref": "#/components/schemas/JudgingResultsMetadataDto" + } + }, + "required": [ + "hackathonId", + "totalSubmissions", + "submissionsScoredCount", + "submissionsPendingCount", + "averageScoreAcrossAll", + "resultsPublished", + "judgesAssigned", + "results", + "generatedAt", + "metadata" + ] + }, + "CreatorRelationDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "username": { "type": "string" }, + "image": { "type": "string" } + }, + "required": ["id", "name"] + }, + "OrganizationRelationDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "logo": { "type": "string" }, + "slug": { "type": "string" } + }, + "required": ["id", "name"] + }, + "HackathonResponseDto": { + "type": "object", + "properties": { + "createdBy": { "$ref": "#/components/schemas/CreatorRelationDto" }, + "organization": { + "$ref": "#/components/schemas/OrganizationRelationDto" + } + }, + "required": ["createdBy"] + }, + "ParticipationResponseDto": { "type": "object", "properties": {} }, + "ParticipantResponseDto": { "type": "object", "properties": {} }, + "HackathonParticipantsResponseDto": { + "type": "object", + "properties": { + "participants": { + "type": "array", + "items": { "$ref": "#/components/schemas/ParticipantResponseDto" } + } + }, + "required": ["participants"] + }, + "TeamMemberDto": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "description": "User ID of the team member", + "example": "user_1234567890" + }, + "name": { + "type": "string", + "description": "Name of the team member", + "example": "John Doe" + }, + "username": { + "type": "string", + "description": "Username of the team member", + "example": "johndoe" + }, + "role": { + "type": "string", + "description": "Role of the team member in the project", + "example": "Full Stack Developer" + }, + "avatar": { + "type": "string", + "description": "Avatar URL of the team member", + "example": "https://example.com/avatar.png" + } + }, + "required": ["userId", "name", "role"] + }, + "SubmissionLinkDto": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Type of link. Each fixed type (github, demo, video, document, presentation) can be used at most once per submission. Use \"other\" for additional links, up to a maximum of 5.", + "example": "github", + "enum": [ + "github", + "demo", + "video", + "document", + "presentation", + "other" + ] + }, + "url": { + "type": "string", + "description": "URL of the link", + "example": "https://github.com/username/project" + }, + "description": { + "type": "string", + "description": "Optional description of the link", + "example": "Main repository with source code" + } + }, + "required": ["type", "url"] + }, + "SocialLinksDto": { + "type": "object", + "properties": { + "github": { + "type": "string", + "description": "GitHub profile or repository", + "example": "https://github.com/username" + }, + "telegram": { + "type": "string", + "description": "Telegram username or group", + "example": "https://t.me/username" + }, + "twitter": { + "type": "string", + "description": "Twitter/X handle", + "example": "https://twitter.com/username" + }, + "email": { + "type": "string", + "description": "Email address", + "example": "contact@example.com" + } + } + }, + "SubmissionResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "hackathonId": { "type": "string" }, + "projectId": { "type": "string" }, + "participantId": { "type": "string" }, + "organizationId": { "type": "string" }, + "participationType": { + "type": "string", + "enum": ["INDIVIDUAL", "TEAM"] + }, + "teamId": { "type": "string" }, + "teamName": { "type": "string" }, + "teamMembers": { + "type": "array", + "items": { "$ref": "#/components/schemas/TeamMemberDto" } + }, + "projectName": { "type": "string" }, + "category": { "type": "string" }, + "description": { "type": "string" }, + "logo": { "type": "string" }, + "banner": { "type": "string" }, + "videoUrl": { "type": "string" }, + "introduction": { "type": "string" }, + "links": { + "type": "array", + "items": { "$ref": "#/components/schemas/SubmissionLinkDto" } + }, + "socialLinks": { "$ref": "#/components/schemas/SocialLinksDto" }, + "status": { "type": "string" }, + "rank": { "type": "number" }, + "trackEntries": { + "description": "Track entries this submission has opted into. Each entry carries the track slug/name and a wonRank stamped when the submission won that track (null until results are published).", + "type": "array", + "items": { "type": "array" } + }, + "tagline": { "type": "string" }, + "builtWith": { "type": "array", "items": { "type": "string" } }, + "screenshots": { "type": "array", "items": { "type": "string" } }, + "license": { "type": "string" }, + "codeAttestedAt": { "format": "date-time", "type": "string" }, + "registeredAt": { "format": "date-time", "type": "string" }, + "submittedAt": { "format": "date-time", "type": "string" }, + "createdAt": { "format": "date-time", "type": "string" }, + "updatedAt": { "format": "date-time", "type": "string" } + }, + "required": [ + "id", + "hackathonId", + "projectId", + "participantId", + "organizationId", + "participationType", + "projectName", + "category", + "description", + "links", + "status", + "registeredAt", + "createdAt", + "updatedAt" + ] + }, + "CreateSubmissionDto": { + "type": "object", + "properties": { + "organizationId": { + "type": "string", + "description": "Organization ID", + "example": "org_1234567890" + }, + "projectId": { + "type": "string", + "description": "Project ID (must be owned by the user or organization). If not provided, a base project will be created automatically.", + "example": "proj_1234567890" + }, + "participationType": { + "type": "string", + "description": "Type of participation", + "enum": ["INDIVIDUAL", "TEAM"], + "example": "INDIVIDUAL" + }, + "teamId": { + "type": "string", + "description": "[Ignored by backend.] Team ID is snapshotted from the user's authoritative team record at submission time. Field accepted for backwards compatibility only.", + "example": "team_1234567890", + "deprecated": true + }, + "teamName": { + "type": "string", + "description": "[Ignored by backend.] Team name is snapshotted from the user's authoritative team record at submission time.", + "example": "Awesome Hackers", + "deprecated": true + }, + "teamMembers": { + "description": "[Ignored by backend.] Team members are snapshotted from the user's authoritative team record at submission time. Sending this field has no effect.", + "deprecated": true, + "type": "array", + "items": { "$ref": "#/components/schemas/TeamMemberDto" } + }, + "projectName": { + "type": "string", + "description": "Project name for the submission", + "example": "DeFi Lending Platform" + }, + "category": { + "type": "string", + "description": "Category of the project", + "example": "DeFi" + }, + "description": { + "type": "string", + "description": "Detailed description of the project", + "example": "A decentralized lending platform built on Stellar..." + }, + "logo": { + "type": "string", + "description": "Project logo URL", + "example": "https://example.com/logo.png" + }, + "banner": { + "type": "string", + "description": "Project banner image URL (wide hero image)", + "example": "https://example.com/banner.png" + }, + "videoUrl": { + "type": "string", + "description": "Video demonstration URL", + "example": "https://youtube.com/watch?v=xyz" + }, + "introduction": { + "type": "string", + "description": "Brief introduction to the project", + "example": "We built a platform that allows users to..." + }, + "links": { + "description": "Links to project resources. Each fixed link type (github, demo, video, document, presentation) can appear at most once. Use \"other\" for additional links, up to a maximum of 5.", + "type": "array", + "items": { "$ref": "#/components/schemas/SubmissionLinkDto" } + }, + "socialLinks": { + "description": "Social links for the project", + "allOf": [{ "$ref": "#/components/schemas/SocialLinksDto" }] + }, + "trackIds": { + "description": "Optional list of track ids to enter. Only allowed when the hackathon has prizeStructure != OVERALL_ONLY. Capped at Hackathon.tracksMaxPerSubmission.", + "example": ["trk_abc", "trk_def"], + "type": "array", + "items": { "type": "string" } + }, + "trackAnswers": { + "type": "object", + "description": "Per-track answers. Keyed by trackId; each value is { promptAnswer?, customAnswers?, artifacts? }. Phase B.", + "example": { + "trk_abc": { + "promptAnswer": "We focused on a one-tap escrow flow.", + "customAnswers": { "q_audience": "Freelancers" }, + "artifacts": { "figma": "https://figma.com/file/..." } + } + } + }, + "tagline": { + "type": "string", + "description": "Short elevator pitch shown on cards / sidebars / judge queue. Max ~160 chars.", + "example": "Trustless escrow for one-time freelance gigs on Stellar." + }, + "builtWith": { + "description": "Free-form tech-stack tags. Max 20 entries, 40 chars each.", + "example": [ + "Soroban", + "Stellar SDK", + "Next.js", + "TrustlessWork SDK" + ], + "type": "array", + "items": { "type": "string" } + }, + "screenshots": { + "description": "Up to 5 screenshot URLs for the project gallery.", + "type": "array", + "items": { "type": "string" } + }, + "license": { + "type": "string", + "description": "License the submission ships under.", + "enum": [ + "MIT", + "Apache-2.0", + "GPL-3.0", + "BSD-3", + "PROPRIETARY", + "OTHER" + ] + }, + "codeAttested": { + "type": "boolean", + "description": "Submitter attests the code is original or properly attributed. Required to mark a submission SUBMITTED (vs DRAFT)." + } + }, + "required": [ + "organizationId", + "participationType", + "projectName", + "category", + "description", + "links" + ] + }, + "UpdateSubmissionDto": { + "type": "object", + "properties": { + "projectName": { + "type": "string", + "description": "Project name for the submission", + "example": "DeFi Lending Platform" + }, + "category": { + "type": "string", + "description": "Category of the project", + "example": "DeFi" + }, + "description": { + "type": "string", + "description": "Detailed description of the project", + "example": "A decentralized lending platform built on Stellar..." + }, + "logo": { + "type": "string", + "description": "Project logo URL", + "example": "https://example.com/logo.png" + }, + "banner": { + "type": "string", + "description": "Project banner image URL (wide hero image)", + "example": "https://example.com/banner.png" + }, + "videoUrl": { + "type": "string", + "description": "Video demonstration URL", + "example": "https://youtube.com/watch?v=xyz" + }, + "introduction": { + "type": "string", + "description": "Brief introduction to the project", + "example": "We built a platform that allows users to..." + }, + "links": { + "description": "Links to project resources. Each fixed link type (github, demo, video, document, presentation) can appear at most once. Use \"other\" for additional links, up to a maximum of 5.", + "type": "array", + "items": { "$ref": "#/components/schemas/SubmissionLinkDto" } + }, + "socialLinks": { + "description": "Social links for the project", + "allOf": [{ "$ref": "#/components/schemas/SocialLinksDto" }] + }, + "teamMembers": { + "description": "Team members (for team submissions)", + "type": "array", + "items": { "$ref": "#/components/schemas/TeamMemberDto" } + }, + "trackIds": { + "description": "Replace the submission's track picks. Omit to leave existing entries untouched; pass an empty array to clear all picks.", + "type": "array", + "items": { "type": "string" } + }, + "trackAnswers": { + "type": "object", + "description": "Per-track answers, same shape as on create. Phase B." + }, + "tagline": { "type": "string" }, + "builtWith": { "type": "array", "items": { "type": "string" } }, + "screenshots": { "type": "array", "items": { "type": "string" } }, + "license": { + "type": "string", + "enum": [ + "MIT", + "Apache-2.0", + "GPL-3.0", + "BSD-3", + "PROPRIETARY", + "OTHER" + ] + }, + "codeAttested": { "type": "boolean" } + } + }, + "TeamMemberResponseDto": { + "type": "object", + "properties": { + "userId": { "type": "string", "description": "User ID" }, + "username": { "type": "string", "description": "Username" }, + "name": { "type": "string", "description": "Display name" }, + "role": { + "type": "string", + "description": "Role in team (e.g. leader, member)" + }, + "image": { "type": "string", "description": "Profile image URL" }, + "joinedAt": { + "type": "string", + "description": "When the member joined the team (ISO string)" + } + }, + "required": ["userId", "username", "name", "role", "joinedAt"] + }, + "LookingForRoleDto": { + "type": "object", + "properties": { + "role": { + "type": "string", + "description": "Role title (e.g. \"Frontend Developer\", \"UI Designer\")", + "example": "Frontend Developer" + }, + "skills": { + "description": "Optional free-form skills associated with this role", + "example": ["React", "TypeScript"], + "type": "array", + "items": { "type": "array" } + } + }, + "required": ["role"] + }, + "TeamRoleResponseDto": { + "type": "object", + "properties": { + "skill": { "type": "string", "description": "Skill/role name" }, + "hired": { + "type": "boolean", + "description": "Whether this role has been filled" + } + }, + "required": ["skill", "hired"] + }, + "TeamResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Team ID", + "example": "team_1234567890" + }, + "teamName": { + "type": "string", + "description": "Team name", + "example": "Stellar Innovators" + }, + "description": { + "type": "string", + "description": "Team description" + }, + "hackathonId": { "type": "string", "description": "Hackathon ID" }, + "leader": { + "type": "object", + "description": "Team leader information" + }, + "members": { + "description": "Team members", + "type": "array", + "items": { "$ref": "#/components/schemas/TeamMemberResponseDto" } + }, + "memberCount": { + "type": "number", + "description": "Current number of members", + "example": 3 + }, + "maxSize": { + "type": "number", + "description": "Maximum team size allowed", + "example": 5 + }, + "lookingFor": { + "description": "Roles the team is looking for, with optional free-form skills", + "type": "array", + "items": { "$ref": "#/components/schemas/LookingForRoleDto" } + }, + "rolesStatus": { + "description": "Hired status per role (when using lookingFor)", + "type": "array", + "items": { "$ref": "#/components/schemas/TeamRoleResponseDto" } + }, + "contactInfo": { + "type": "object", + "description": "Contact information (e.g. telegram, discord, email)" + }, + "isOpen": { + "type": "boolean", + "description": "Whether team is accepting new members", + "example": true + }, + "createdAt": { + "type": "string", + "description": "Team creation date" + }, + "updatedAt": { "type": "string", "description": "Last update date" } + }, + "required": [ + "id", + "teamName", + "description", + "hackathonId", + "leader", + "members", + "memberCount", + "maxSize", + "isOpen", + "createdAt", + "updatedAt" + ] + }, + "TeamListResponseDto": { + "type": "object", + "properties": { + "teams": { + "description": "List of teams", + "type": "array", + "items": { "$ref": "#/components/schemas/TeamResponseDto" } + }, + "pagination": { + "type": "object", + "description": "Pagination metadata" + } + }, + "required": ["teams", "pagination"] + }, + "CreateTeamDto": { + "type": "object", + "properties": { + "teamName": { + "type": "string", + "description": "Team name", + "example": "Stellar Innovators", + "minLength": 3, + "maxLength": 100 + }, + "description": { + "type": "string", + "description": "Team description", + "example": "We are building the next generation DeFi platform", + "minLength": 10, + "maxLength": 500 + }, + "lookingFor": { + "description": "Roles the team is looking for. Each entry is a role title with optional free-form skills. Team will be CLOSED unless at least one role is specified. The number of roles is bounded by the hackathon's teamMin/teamMax (excluding the leader).", + "type": "array", + "items": { "$ref": "#/components/schemas/LookingForRoleDto" } + }, + "contactInfo": { + "type": "object", + "description": "Contact information for interested members", + "example": { "telegram": "@teamlead", "discord": "lead#1234" } + } + }, + "required": ["teamName", "description"] + }, + "UpdateTeamDto": { + "type": "object", + "properties": { + "teamName": { + "type": "string", + "description": "Updated team name", + "example": "Stellar Innovators Pro" + }, + "description": { + "type": "string", + "description": "Updated team description" + }, + "lookingFor": { + "description": "Roles the team is looking for. Set to empty array to close the team. Each entry is a role title with optional free-form skills.", + "type": "array", + "items": { "$ref": "#/components/schemas/LookingForRoleDto" } + }, + "contactInfo": { + "type": "object", + "description": "Updated contact information" + }, + "isOpen": { + "type": "boolean", + "description": "Explicitly set team open/closed status. Can only be true if lookingFor is not empty." + } + } + }, + "InviteToTeamDto": { + "type": "object", + "properties": { + "inviteeIdentifier": { + "type": "string", + "description": "User ID or username of the person to invite", + "example": "user_1234567890" + }, + "message": { + "type": "string", + "description": "Optional message to include with the invitation", + "example": "We would love to have you on our team!", + "maxLength": 500 + } + }, + "required": ["inviteeIdentifier"] + }, + "TeamInvitationResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Invitation ID", + "example": "inv_1234567890" + }, + "teamId": { + "type": "string", + "description": "Team ID", + "example": "team_1234567890" + }, + "hackathon": { + "type": "object", + "description": "Hackathon information" + }, + "invitee": { "type": "object", "description": "Invitee information" }, + "inviter": { "type": "object", "description": "Inviter information" }, + "status": { + "type": "string", + "description": "Invitation status", + "example": "pending", + "enum": ["pending", "accepted", "rejected", "expired"] + }, + "message": { + "type": "object", + "description": "Optional message from inviter", + "example": "We would love to have you on our team!" + }, + "role": { + "type": "object", + "description": "Role in the team", + "example": "member" + }, + "expiresAt": { + "format": "date-time", + "type": "string", + "description": "Invitation expiration date", + "example": "2026-01-30T12:00:00.000Z" + }, + "createdAt": { + "format": "date-time", + "type": "string", + "description": "Invitation creation date", + "example": "2026-01-23T12:00:00.000Z" + }, + "respondedAt": { + "type": "object", + "description": "Date when invitation was responded to", + "example": "2026-01-24T12:00:00.000Z" + } + }, + "required": [ + "id", + "teamId", + "hackathon", + "invitee", + "inviter", + "status", + "role", + "expiresAt", + "createdAt" + ] + }, + "TeamInvitationListResponseDto": { + "type": "object", + "properties": { + "invitations": { + "description": "List of invitations", + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamInvitationResponseDto" + } + }, + "total": { + "type": "number", + "description": "Total count", + "example": 5 + } + }, + "required": ["invitations", "total"] + }, + "InvitationActionResponseDto": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "Successfully accepted team invitation" + }, + "teamId": { + "type": "string", + "description": "Team ID that was joined (only for accept)", + "example": "team_1234567890" + }, + "invitation": { + "description": "Updated invitation", + "allOf": [ + { "$ref": "#/components/schemas/TeamInvitationResponseDto" } + ] + } + }, + "required": ["message", "teamId", "invitation"] + }, + "ToggleRoleHiredDto": { + "type": "object", + "properties": { + "skill": { + "type": "string", + "description": "Skill/role name to toggle hired status", + "example": "Rust Developer" + } + }, + "required": ["skill"] + }, + "TransferLeadershipDto": { + "type": "object", + "properties": { + "newLeaderId": { + "type": "string", + "description": "User ID of the new team leader (must be an existing member)", + "example": "user_1234567890" + }, + "reason": { + "type": "string", + "description": "Optional reason for the leadership transfer", + "example": "Stepping down to focus on development tasks", + "maxLength": 500 + } + }, + "required": ["newLeaderId"] + }, + "LeadershipTransferResponseDto": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "Leadership successfully transferred" + }, + "team": { + "description": "Updated team with new leader", + "allOf": [{ "$ref": "#/components/schemas/TeamResponseDto" }] + }, + "previousLeaderId": { + "type": "string", + "description": "Previous leader ID", + "example": "user_1234567890" + }, + "newLeaderId": { + "type": "string", + "description": "New leader ID", + "example": "user_0987654321" + }, + "transferredAt": { + "format": "date-time", + "type": "string", + "description": "Timestamp of the transfer", + "example": "2026-02-16T10:30:00.000Z" + } + }, + "required": [ + "message", + "team", + "previousLeaderId", + "newLeaderId", + "transferredAt" + ] + }, + "InfoFormData": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Hackathon title", + "minLength": 3, + "maxLength": 100 + }, + "banner": { + "type": "string", + "description": "Banner image URL", + "format": "uri" + }, + "description": { + "type": "string", + "description": "Hackathon description", + "minLength": 10, + "maxLength": 5000 + }, + "categories": { + "type": "array", + "description": "One or more hackathon categories", + "items": { + "type": "string", + "enum": [ + "DeFi", + "NFTs", + "DAOs", + "Layer 2", + "Cross-chain", + "Web3 Gaming", + "Social Tokens", + "Infrastructure", + "Privacy", + "Sustainability", + "Real World Assets", + "Other" + ] + } + }, + "venueType": { + "type": "string", + "description": "Venue type", + "enum": ["virtual", "physical"] + }, + "tagline": { + "type": "string", + "description": "Short tagline", + "maxLength": 200 + }, + "country": { "type": "string" }, + "state": { "type": "string" }, + "city": { "type": "string" }, + "venueName": { "type": "string" }, + "venueAddress": { "type": "string" }, + "slug": { + "type": "string", + "description": "Read-only URL slug (server-assigned)" + } + }, + "required": [ + "name", + "banner", + "description", + "categories", + "venueType", + "tagline" + ] + }, + "PhaseDto": { + "type": "object", + "properties": { + "name": { "type": "string", "description": "Phase name" }, + "startDate": { "type": "string", "format": "date-time" }, + "endDate": { "type": "string", "format": "date-time" }, + "description": { "type": "string" } + }, + "required": ["name", "startDate", "endDate"] + }, + "TimelineFormData": { + "type": "object", + "properties": { + "startDate": { "type": "string", "format": "date-time" }, + "submissionDeadline": { "type": "string", "format": "date-time" }, + "timezone": { "type": "string", "description": "IANA timezone" }, + "registrationDeadline": { "type": "string", "format": "date-time" }, + "judgingDeadline": { "type": "string", "format": "date-time" }, + "phases": { + "type": "array", + "items": { "$ref": "#/components/schemas/PhaseDto" } + }, + "submissionDeadlineOriginal": { + "type": "string", + "format": "date-time", + "description": "Read-only: original submission deadline before any extension" + }, + "submissionDeadlineExtendedAt": { + "type": "string", + "format": "date-time", + "description": "Read-only: timestamp the submission deadline was last extended" + } + }, + "required": ["startDate", "submissionDeadline", "timezone"] + }, + "ParticipantFormData": { + "type": "object", + "properties": { + "participantType": { + "type": "string", + "enum": ["individual", "team", "team_or_individual"] + }, + "teamMin": { "type": "number", "minimum": 1, "maximum": 20 }, + "teamMax": { "type": "number", "minimum": 1, "maximum": 20 }, + "maxParticipants": { + "type": "number", + "minimum": 1, + "description": "Participant cap; omit for unlimited" + }, + "require_github": { "type": "boolean" }, + "require_demo_video": { "type": "boolean" }, + "require_other_links": { "type": "boolean" }, + "detailsTab": { "type": "boolean" }, + "participantsTab": { "type": "boolean" }, + "resourcesTab": { "type": "boolean" }, + "submissionTab": { "type": "boolean" }, + "announcementsTab": { "type": "boolean" }, + "discussionTab": { "type": "boolean" }, + "winnersTab": { "type": "boolean" }, + "sponsorsTab": { "type": "boolean" }, + "joinATeamTab": { "type": "boolean" }, + "rulesTab": { "type": "boolean" }, + "submissionVisibility": { + "type": "string", + "enum": ["PUBLIC", "PARTICIPANTS_ONLY"] + }, + "submissionStatusVisibility": { + "type": "string", + "enum": ["ALL", "ACCEPTED_SHORTLISTED", "HIDDEN_UNTIL_RESULTS"] + } + }, + "required": ["participantType"] + }, + "PrizeTierDto": { + "type": "object", + "properties": { + "id": { "type": "string", "description": "Client-generated tier id" }, + "place": { + "type": "string", + "description": "Placement label, e.g. \"1st Place\"" + }, + "prizeAmount": { + "type": "string", + "description": "Prize amount as a decimal string" + }, + "description": { "type": "string" }, + "currency": { "type": "string" }, + "passMark": { "type": "number", "minimum": 0, "maximum": 100 }, + "kind": { "type": "string", "enum": ["OVERALL", "TRACK"] }, + "trackId": { "type": "string" } + }, + "required": ["id", "place", "prizeAmount", "passMark"] + }, + "WinnerOverrideDto": { + "type": "object", + "properties": { + "submissionId": { + "type": "string", + "description": "Submission id the override targets" + }, + "rank": { "type": "number", "minimum": 1 }, + "prizeAmount": { "type": "string" }, + "currency": { "type": "string" } + }, + "required": ["submissionId"] + }, + "RewardsFormData": { + "type": "object", + "properties": { + "prizeTiers": { + "type": "array", + "items": { "$ref": "#/components/schemas/PrizeTierDto" } + }, + "winnerOverrides": { + "type": "array", + "items": { "$ref": "#/components/schemas/WinnerOverrideDto" } + }, + "prizeStructure": { + "type": "string", + "enum": ["OVERALL_ONLY", "OVERALL_AND_TRACKS", "TRACKS_ONLY"] + }, + "tracksMaxPerSubmission": { + "type": "number", + "minimum": 1, + "maximum": 20 + } + }, + "required": ["prizeTiers"] + }, + "ResourceItemDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Client-generated resource id" + }, + "link": { "type": "string" }, + "description": { "type": "string" }, + "file": { + "type": "object", + "description": "Uploaded file metadata", + "properties": { + "url": { "type": "string" }, + "name": { "type": "string" } + } + } + }, + "required": ["id"] + }, + "ResourcesFormData": { + "type": "object", + "properties": { + "resources": { + "type": "array", + "items": { "$ref": "#/components/schemas/ResourceItemDto" } + } + }, + "required": ["resources"] + }, + "CriterionDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Client-generated criterion id" + }, + "name": { "type": "string", "description": "Criterion name" }, + "weight": { "type": "number", "minimum": 0, "maximum": 100 }, + "description": { "type": "string" } + }, + "required": ["id", "name", "weight"] + }, + "JudgingFormData": { + "type": "object", + "properties": { + "criteria": { + "type": "array", + "items": { "$ref": "#/components/schemas/CriterionDto" } + } + }, + "required": ["criteria"] + }, + "SponsorPartnerDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Client-generated sponsor/partner id" + }, + "name": { "type": "string" }, + "logo": { "type": "string" }, + "link": { "type": "string" } + }, + "required": ["id"] + }, + "CollaborationFormData": { + "type": "object", + "properties": { + "contactEmail": { + "type": "string", + "description": "Organizer contact email" + }, + "telegram": { "type": "string" }, + "discord": { "type": "string" }, + "socialLinks": { "type": "array", "items": { "type": "string" } }, + "sponsorsPartners": { + "type": "array", + "items": { "$ref": "#/components/schemas/SponsorPartnerDto" } + } + }, + "required": ["contactEmail"] + }, + "HackathonDraftDataDto": { + "type": "object", + "properties": { + "information": { "$ref": "#/components/schemas/InfoFormData" }, + "timeline": { "$ref": "#/components/schemas/TimelineFormData" }, + "participation": { + "$ref": "#/components/schemas/ParticipantFormData" + }, + "rewards": { "$ref": "#/components/schemas/RewardsFormData" }, + "resources": { "$ref": "#/components/schemas/ResourcesFormData" }, + "judging": { "$ref": "#/components/schemas/JudgingFormData" }, + "collaboration": { + "$ref": "#/components/schemas/CollaborationFormData" + } + } + }, + "HackathonDraftResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "status": { + "type": "string", + "enum": [ + "DRAFT", + "DRAFT_AWAITING_FUNDING", + "PUBLISHED", + "ARCHIVED", + "CANCELLED" + ] + }, + "currentStep": { + "type": "number", + "description": "First incomplete step (1-based)" + }, + "completedSteps": { "type": "array", "items": { "type": "string" } }, + "data": { "$ref": "#/components/schemas/HackathonDraftDataDto" }, + "isValidForPublish": { "type": "boolean" }, + "validationErrors": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { "type": "string" } + }, + "description": "Per-section validation messages, keyed by step" + }, + "createdAt": { "type": "string", "format": "date-time" }, + "updatedAt": { "type": "string", "format": "date-time" } + }, + "required": [ + "id", + "status", + "currentStep", + "completedSteps", + "data", + "isValidForPublish", + "validationErrors", + "createdAt", + "updatedAt" + ] + }, + "UpdateHackathonDraftDto": { + "type": "object", + "properties": { + "information": { "$ref": "#/components/schemas/InfoFormData" }, + "timeline": { "$ref": "#/components/schemas/TimelineFormData" }, + "participation": { + "$ref": "#/components/schemas/ParticipantFormData" + }, + "rewards": { "$ref": "#/components/schemas/RewardsFormData" }, + "resources": { "$ref": "#/components/schemas/ResourcesFormData" }, + "judging": { "$ref": "#/components/schemas/JudgingFormData" }, + "collaboration": { + "$ref": "#/components/schemas/CollaborationFormData" + }, + "autoSave": { + "type": "boolean", + "description": "Hint that this is an autosave (no completion side effects)." + } + } + }, + "PublishDraftDto": { + "type": "object", + "properties": { + "skipAnnouncement": { "type": "boolean" }, + "announcementSubject": { "type": "string", "maxLength": 120 } + } + }, + "PublishHackathonResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "slug": { "type": "string" }, + "publishedAt": { "type": "string", "format": "date-time" }, + "message": { "type": "string" } + }, + "required": ["id", "slug", "publishedAt", "message"] + }, + "UpdateVisibilitySettingsDto": { + "type": "object", + "properties": { + "submissionVisibility": { + "type": "string", + "description": "Who can view hackathon submissions", + "enum": ["PUBLIC", "PARTICIPANTS_ONLY"], + "example": "PUBLIC" + }, + "submissionStatusVisibility": { + "type": "string", + "description": "Which submission statuses are visible to others. ALL exposes SUBMITTED and SHORTLISTED. ACCEPTED_SHORTLISTED exposes only SHORTLISTED. HIDDEN_UNTIL_RESULTS hides every submission from non-owners and non-organizers until the hackathon results are published, then exposes only SHORTLISTED. DISQUALIFIED is never visible to anyone other than the owner or an organizer.", + "enum": ["ALL", "ACCEPTED_SHORTLISTED", "HIDDEN_UNTIL_RESULTS"], + "example": "ACCEPTED_SHORTLISTED" + } + } + }, + "ReviewSubmissionDto": { + "type": "object", + "properties": { + "judgeId": { + "type": "string", + "description": "ID of the assigned judge performing the review", + "example": "user_1234567890" + }, + "status": { + "type": "string", + "description": "Review action", + "example": "SHORTLISTED", + "enum": ["SHORTLISTED", "SUBMITTED"] + }, + "notes": { + "type": "string", + "description": "Reviewer notes or feedback", + "example": "Great project with innovative approach", + "maxLength": 1000 + }, + "rank": { + "type": "number", + "description": "Rank/position for the submission", + "example": 1 + }, + "isOrganizerOverride": { + "type": "boolean", + "description": "Whether this is an organizational override (bypasses COI and assignment checks)", + "default": false + } + }, + "required": ["judgeId", "status"] + }, + "OrganizationHackathonParticipantsResponseDto": { + "type": "object", + "properties": {} + }, + "DisqualifySubmissionDto": { + "type": "object", + "properties": { + "disqualificationReason": { + "type": "string", + "description": "Reason for disqualification", + "example": "Submission does not meet hackathon requirements", + "minLength": 10, + "maxLength": 500 + } + }, + "required": ["disqualificationReason"] + }, + "BulkSubmissionActionDto": { + "type": "object", + "properties": { + "submissionIds": { + "description": "Array of submission IDs", + "example": ["sub_1234567890", "sub_0987654321"], + "type": "array", + "items": { "type": "string" } + }, + "action": { + "type": "string", + "description": "Action to perform", + "example": "SHORTLISTED", + "enum": ["SHORTLISTED", "SUBMITTED", "DISQUALIFIED"] + }, + "reason": { + "type": "string", + "description": "Reason (required for DISQUALIFIED action)", + "example": "Does not meet requirements" + } + }, + "required": ["submissionIds", "action"] + }, + "SummaryMetricsDto": { + "type": "object", + "properties": { + "participantsCount": { "type": "number", "example": 120 }, + "submissionsCount": { "type": "number", "example": 45 }, + "activeJudges": { "type": "number", "example": 6 }, + "completedMilestones": { "type": "number", "example": 3 } + }, + "required": [ + "participantsCount", + "submissionsCount", + "activeJudges", + "completedMilestones" + ] + }, + "TrendPointDto": { + "type": "object", + "properties": { + "date": { "type": "string", "example": "2026-02-01" }, + "count": { "type": "number", "example": 5 } + }, + "required": ["date", "count"] + }, + "TrendsDto": { + "type": "object", + "properties": { + "submissionsOverTime": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrendPointDto" } + }, + "participantSignupsOverTime": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrendPointDto" } + } + }, + "required": ["submissionsOverTime", "participantSignupsOverTime"] + }, + "TimelinePhaseDto": { + "type": "object", + "properties": { + "phase": { "type": "string", "example": "Registration" }, + "description": { + "type": "string", + "example": "Individuals and teams are signing up to participate in the hackathon." + }, + "date": { "type": "string", "example": "2026-01-20" }, + "status": { + "type": "string", + "enum": ["upcoming", "ongoing", "completed"] + } + }, + "required": ["phase", "description", "date", "status"] + }, + "HackathonAnalyticsResponseDto": { + "type": "object", + "properties": { + "hackathonId": { "type": "string", "example": "hack_1234567890" }, + "summary": { "$ref": "#/components/schemas/SummaryMetricsDto" }, + "trends": { "$ref": "#/components/schemas/TrendsDto" }, + "timeline": { + "type": "array", + "items": { "$ref": "#/components/schemas/TimelinePhaseDto" } + } + }, + "required": ["hackathonId", "summary", "trends", "timeline"] + }, + "AnnouncementAuthorDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "image": { "type": "string" }, + "username": { "type": "string" } + }, + "required": ["id", "name"] + }, + "AnnouncementResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "hackathonId": { "type": "string" }, + "title": { "type": "string" }, + "content": { "type": "string" }, + "isDraft": { "type": "boolean" }, + "isPinned": { "type": "boolean" }, + "publishedAt": { "format": "date-time", "type": "string" }, + "createdAt": { "format": "date-time", "type": "string" }, + "updatedAt": { "format": "date-time", "type": "string" }, + "author": { "$ref": "#/components/schemas/AnnouncementAuthorDto" } + }, + "required": [ + "id", + "hackathonId", + "title", + "content", + "isDraft", + "isPinned", + "createdAt", + "updatedAt", + "author" + ] + }, + "CreateAnnouncementDto": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Title of the announcement", + "example": "Hackathon Starts Now!", + "minLength": 3, + "maxLength": 100 + }, + "content": { + "type": "string", + "description": "Content of the announcement in Markdown", + "example": "# Welcome\n\nWe are excited to start...", + "minLength": 10, + "maxLength": 10000 + }, + "isDraft": { + "type": "boolean", + "description": "Whether the announcement is a draft", + "default": true + }, + "isPinned": { + "type": "boolean", + "description": "Whether the announcement should be pinned", + "default": false + } + }, + "required": ["title", "content"] + }, + "UpdateAnnouncementDto": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Title of the announcement", + "example": "Hackathon Starts Now!", + "minLength": 3, + "maxLength": 100 + }, + "content": { + "type": "string", + "description": "Content of the announcement in Markdown", + "example": "# Welcome\n\nWe are excited to start...", + "minLength": 10, + "maxLength": 10000 + }, + "isDraft": { + "type": "boolean", + "description": "Whether the announcement is a draft" + }, + "isPinned": { + "type": "boolean", + "description": "Whether the announcement should be pinned" + } + } + }, + "CriterionScoreDto": { + "type": "object", + "properties": { + "criterionId": { + "type": "string", + "description": "Criterion ID or name", + "example": "Technical Complexity" + }, + "score": { + "type": "number", + "description": "Score for this criterion (0-10)", + "example": 8.5 + }, + "comment": { + "type": "string", + "description": "Optional comment for this criterion", + "example": "Great technical implementation" + } + }, + "required": ["criterionId", "score"] + }, + "ScoreSubmissionDto": { + "type": "object", + "properties": { + "submissionId": { + "type": "string", + "description": "Submission ID being judged", + "example": "sub_1234567890" + }, + "criteriaScores": { + "description": "Scores for each individual criterion", + "type": "array", + "items": { "$ref": "#/components/schemas/CriterionScoreDto" } + }, + "judgeId": { + "type": "string", + "description": "Optional ID of the judge to attribute this score to (defaults to calling user)", + "example": "user_123" + }, + "notes": { + "type": "string", + "description": "Optional admin notes", + "example": "Score adjusted per appeal" + }, + "isOrganizerOverride": { + "type": "boolean", + "description": "Whether this is an organizational override (bypasses COI and assignment checks)", + "default": false + } + }, + "required": ["submissionId", "criteriaScores"] + }, + "UserDetailsDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "email": { "type": "string" }, + "name": { "type": "string" }, + "username": { "type": "string" }, + "image": { "type": "string" } + }, + "required": ["id", "email", "name", "username"] + }, + "JudgingSubmissionParticipantDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "userId": { "type": "string" }, + "user": { "$ref": "#/components/schemas/UserDetailsDto" }, + "participationType": { "type": "string" }, + "teamId": { "type": "string" }, + "teamName": { "type": "string" }, + "teamMembers": { "type": "array", "items": { "type": "object" } } + }, + "required": ["id", "userId", "user", "participationType"] + }, + "JudgingSubmissionDataDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "projectName": { "type": "string" }, + "category": { "type": "string" }, + "description": { "type": "string" }, + "logo": { "type": "string" }, + "videoUrl": { "type": "string" }, + "introduction": { "type": "string" }, + "links": { "type": "array", "items": { "type": "object" } }, + "socialLinks": { "type": "object", "additionalProperties": true }, + "submissionDate": { "type": "string" }, + "status": { "type": "string" }, + "rank": { "type": "number" } + }, + "required": [ + "id", + "projectName", + "category", + "description", + "submissionDate", + "status" + ] + }, + "IndividualJudgingResultDto": { + "type": "object", + "properties": { + "judgeId": { "type": "string" }, + "judgeName": { "type": "string" }, + "criteriaScores": { + "type": "array", + "items": { "$ref": "#/components/schemas/CriterionScoreDto" } + }, + "totalScore": { "type": "number" }, + "submittedAt": { "format": "date-time", "type": "string" } + }, + "required": [ + "judgeId", + "judgeName", + "criteriaScores", + "totalScore", + "submittedAt" + ] + }, + "JudgingSubmissionDto": { + "type": "object", + "properties": { + "participant": { + "$ref": "#/components/schemas/JudgingSubmissionParticipantDto" + }, + "submission": { + "$ref": "#/components/schemas/JudgingSubmissionDataDto" + }, + "myScore": { + "$ref": "#/components/schemas/IndividualJudgingResultDto" + }, + "averageScore": { "type": "object", "nullable": true }, + "judgeCount": { "type": "number" } + }, + "required": ["participant", "submission", "averageScore", "judgeCount"] + }, + "JudgingPaginationDto": { + "type": "object", + "properties": { + "page": { "type": "number" }, + "limit": { "type": "number" }, + "total": { "type": "number" }, + "totalPages": { "type": "number" } + }, + "required": ["page", "limit", "total", "totalPages"] + }, + "JudgingSubmissionsResponseDto": { + "type": "object", + "properties": { + "submissions": { + "type": "array", + "items": { "$ref": "#/components/schemas/JudgingSubmissionDto" } + }, + "criteria": { + "type": "array", + "items": { "$ref": "#/components/schemas/CriterionDto" } + }, + "pagination": { "$ref": "#/components/schemas/JudgingPaginationDto" }, + "scoredCount": { + "type": "number", + "description": "Number of submissions in this hackathon that the calling judge has already scored. Independent of pagination so the progress strip is accurate even when the user is on page 2." + } + }, + "required": ["submissions", "criteria", "pagination"] + }, + "AddJudgeDto": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address of the user to be assigned as a judge", + "example": "judge@example.com" + } + }, + "required": ["email"] + }, + "JudgeResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "userId": { "type": "string" }, + "name": { "type": "string" }, + "image": { "type": "object" } + }, + "required": ["id", "userId", "name"] + }, + "IndividualScoreDto": { + "type": "object", + "properties": { + "judgeId": { "type": "string" }, + "judgeName": { "type": "string" }, + "score": { "type": "number" } + }, + "required": ["judgeId", "judgeName", "score"] + }, + "ScoreRangeDto": { + "type": "object", + "properties": { + "min": { "type": "number" }, + "max": { "type": "number" } + }, + "required": ["min", "max"] + }, + "CriteriaBreakdownDto": { + "type": "object", + "properties": { + "criterionId": { "type": "string" }, + "averageScore": { "type": "number" }, + "min": { "type": "number" }, + "max": { "type": "number" }, + "variance": { "type": "number" } + }, + "required": ["criterionId", "averageScore", "min", "max", "variance"] + }, + "AggregatedJudgingResultDto": { + "type": "object", + "properties": { + "submissionId": { "type": "string" }, + "projectName": { "type": "string" }, + "teamId": { "type": "object" }, + "participantId": { "type": "string" }, + "status": { "type": "string" }, + "submittedAt": { "format": "date-time", "type": "string" }, + "averageScore": { "type": "number" }, + "totalScore": { "type": "number" }, + "judgeCount": { "type": "number" }, + "expectedJudgeCount": { "type": "number" }, + "judgingProgress": { "type": "string" }, + "individualScores": { + "type": "array", + "items": { "$ref": "#/components/schemas/IndividualScoreDto" } + }, + "scoreVariance": { "type": "number" }, + "scoreRange": { "$ref": "#/components/schemas/ScoreRangeDto" }, + "criteriaBreakdown": { + "type": "array", + "items": { "$ref": "#/components/schemas/CriteriaBreakdownDto" } + }, + "rank": { "type": "object" }, + "computedRank": { "type": "number" }, + "prize": { "type": "string" }, + "isComplete": { "type": "boolean" }, + "isPending": { "type": "boolean" }, + "hasDisagreement": { "type": "boolean" }, + "trackIds": { "type": "array", "items": { "type": "string" } } + }, + "required": [ + "submissionId", + "projectName", + "participantId", + "status", + "submittedAt", + "averageScore", + "totalScore", + "judgeCount", + "expectedJudgeCount", + "judgingProgress", + "individualScores", + "scoreVariance", + "scoreRange", + "criteriaBreakdown", + "isComplete", + "isPending", + "hasDisagreement" + ] + }, + "JudgingResultsResponseDto": { + "type": "object", + "properties": { + "hackathonId": { "type": "string" }, + "totalSubmissions": { "type": "number" }, + "submissionsScoredCount": { "type": "number" }, + "submissionsPendingCount": { "type": "number" }, + "averageScoreAcrossAll": { "type": "number" }, + "resultsPublished": { "type": "boolean" }, + "judgesAssigned": { "type": "number" }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AggregatedJudgingResultDto" + } + }, + "generatedAt": { "format": "date-time", "type": "string" }, + "winnerOverrides": { + "type": "object", + "additionalProperties": { "type": "number" }, + "description": "Manual winner assignments override (submissionId -> rank)" + }, + "metadata": { + "$ref": "#/components/schemas/JudgingResultsMetadataDto" + } + }, + "required": [ + "hackathonId", + "totalSubmissions", + "submissionsScoredCount", + "submissionsPendingCount", + "averageScoreAcrossAll", + "resultsPublished", + "judgesAssigned", + "results", + "generatedAt", + "metadata" + ] + }, + "InviteJudgeDto": { + "type": "object", + "properties": { + "email": { "type": "string", "example": "judge@example.com" }, + "displayName": { + "type": "string", + "description": "Optional public display name for the judge" + }, + "message": { + "type": "string", + "description": "Personal message included in the invitation email" + }, + "expiresInDays": { + "type": "number", + "description": "Override expiry in days (default 14). Maximum 60 to prevent indefinite invitations.", + "minimum": 1, + "maximum": 60 + } + }, + "required": ["email"] + }, + "AcceptJudgeInvitationDto": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Optional display name override. If omitted, the inviter-provided displayName (or the user’s account name) is used." + } + } + }, + "PublishedInfoFormDataDto": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 100, + "example": "Web3 Innovation Hackathon" + }, + "banner": { + "type": "string", + "example": "https://example.com/banner.png" + }, + "description": { + "type": "string", + "minLength": 10, + "maxLength": 5000, + "example": "Build products for the decentralized future." + }, + "categories": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "DeFi", + "NFTs", + "DAOs", + "Layer 2", + "Cross-chain", + "Web3 Gaming", + "Social Tokens", + "Infrastructure", + "Privacy", + "Sustainability", + "Real World Assets", + "Other" + ] + } + }, + "venueType": { + "type": "string", + "enum": ["virtual", "physical"], + "example": "virtual" + }, + "tagline": { + "type": "string", + "maxLength": 200, + "example": "Build the future of Web3" + }, + "country": { "type": "string", "example": "Nigeria" }, + "state": { "type": "string", "example": "Lagos" }, + "city": { "type": "string", "example": "Ikeja" }, + "venueName": { "type": "string", "example": "Eko Convention Center" }, + "venueAddress": { + "type": "string", + "example": "Plot 1415 Adetokunbo Ademola St" + }, + "slug": { "type": "string", "example": "web3-innovation-hackathon" } + }, + "required": [ + "name", + "banner", + "description", + "categories", + "venueType", + "tagline" + ] + }, + "PublishedSponsorPartnerDto": { + "type": "object", + "properties": { + "id": { "type": "string", "example": "sp-1" }, + "name": { "type": "string", "example": "Stellar Foundation" }, + "logo": { + "type": "string", + "example": "https://example.com/logo.png" + }, + "link": { "type": "string", "example": "https://stellar.org" } + }, + "required": ["id"] + }, + "PublishedCollaborationFormDataDto": { + "type": "object", + "properties": { + "contactEmail": { + "type": "string", + "example": "organizer@boundless.dev" + }, + "telegram": { "type": "string", "example": "@boundless" }, + "discord": { "type": "string", "example": "boundless-hackathon" }, + "socialLinks": { + "example": ["https://x.com/boundless"], + "type": "array", + "items": { "type": "string" } + }, + "sponsorsPartners": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublishedSponsorPartnerDto" + } + } + }, + "required": ["contactEmail", "socialLinks", "sponsorsPartners"] + }, + "UpdatePublishedHackathonContentDto": { + "type": "object", + "properties": { + "information": { + "$ref": "#/components/schemas/PublishedInfoFormDataDto" + }, + "collaboration": { + "$ref": "#/components/schemas/PublishedCollaborationFormDataDto" + } + } + }, + "PublishedPhaseDto": { + "type": "object", + "properties": { + "name": { "type": "string", "example": "Building Phase" }, + "startDate": { + "type": "string", + "example": "2026-04-01T00:00:00.000Z" + }, + "endDate": { + "type": "string", + "example": "2026-04-10T00:00:00.000Z" + }, + "description": { + "type": "string", + "example": "Core build phase for teams" + } + }, + "required": ["name", "startDate", "endDate"] + }, + "PublishedTimelineFormDataDto": { + "type": "object", + "properties": { + "startDate": { + "type": "string", + "example": "2026-04-01T00:00:00.000Z" + }, + "submissionDeadline": { + "type": "string", + "example": "2026-04-15T00:00:00.000Z" + }, + "timezone": { "type": "string", "example": "Africa/Lagos" }, + "registrationDeadline": { + "type": "string", + "example": "2026-04-02T00:00:00.000Z", + "description": "Optional. When null, registration stays open until submission deadline." + }, + "judgingDeadline": { + "type": "string", + "example": "2026-04-18T00:00:00.000Z", + "description": "Optional judging deadline. When null, no judging phase is rendered on the timeline." + }, + "phases": { + "type": "array", + "items": { "$ref": "#/components/schemas/PublishedPhaseDto" } + } + } + }, + "PublishedParticipantFormDataDto": { + "type": "object", + "properties": { + "participantType": { + "type": "string", + "enum": ["individual", "team", "team_or_individual"] + }, + "teamMin": { + "type": "number", + "minimum": 1, + "maximum": 20, + "example": 2 + }, + "teamMax": { + "type": "number", + "minimum": 1, + "maximum": 20, + "example": 5 + }, + "maxParticipants": { + "type": "number", + "minimum": 1, + "example": 200, + "description": "Optional cap on total participants. null = unlimited. Can be updated after publishing." + }, + "require_github": { "type": "boolean", "example": true }, + "require_demo_video": { "type": "boolean", "example": false }, + "require_other_links": { "type": "boolean", "example": true }, + "detailsTab": { "type": "boolean" }, + "participantsTab": { "type": "boolean" }, + "resourcesTab": { "type": "boolean" }, + "submissionTab": { "type": "boolean" }, + "announcementsTab": { "type": "boolean" }, + "discussionTab": { "type": "boolean" }, + "winnersTab": { "type": "boolean" }, + "sponsorsTab": { "type": "boolean" }, + "joinATeamTab": { "type": "boolean" }, + "rulesTab": { "type": "boolean" } + }, + "required": ["participantType"] + }, + "UpdatePublishedHackathonScheduleDto": { + "type": "object", + "properties": { + "timeline": { + "$ref": "#/components/schemas/PublishedTimelineFormDataDto" + }, + "participation": { + "$ref": "#/components/schemas/PublishedParticipantFormDataDto" + } + } + }, + "PublishedPrizeTierDto": { + "type": "object", + "properties": { + "id": { "type": "string", "example": "tier-1" }, + "place": { "type": "string", "example": "1st Place" }, + "prizeAmount": { "type": "string", "example": "5000" }, + "currency": { "type": "string", "example": "USDC" }, + "description": { "type": "string", "example": "Top overall project" }, + "rank": { + "type": "number", + "minimum": 1, + "example": 1, + "description": "Display rank / ordering of the tier (1 = highest)" + }, + "passMark": { + "type": "number", + "minimum": 0, + "maximum": 100, + "example": 70 + }, + "kind": { "type": "string", "enum": ["OVERALL", "TRACK"] }, + "trackId": { + "type": "string", + "description": "Required when kind=TRACK. References a HackathonTrack id." + } + }, + "required": ["id", "place", "prizeAmount", "passMark"] + }, + "PublishedRewardsFormDataDto": { + "type": "object", + "properties": { + "prizeTiers": { + "type": "array", + "items": { "$ref": "#/components/schemas/PublishedPrizeTierDto" } + }, + "winnerOverrides": { + "type": "object", + "example": { "sub-1": 1, "sub-2": 2 }, + "description": "Manual winner assignments override (submissionId -> rank)", + "additionalProperties": { "type": "number" } + }, + "prizeStructure": { + "type": "string", + "enum": ["OVERALL_ONLY", "OVERALL_AND_TRACKS", "TRACKS_ONLY"] + }, + "tracksMaxPerSubmission": { + "type": "number", + "minimum": 1, + "maximum": 20 + } + }, + "required": ["prizeTiers"] + }, + "UpdatePublishedHackathonFinancialDto": { + "type": "object", + "properties": { + "rewards": { + "$ref": "#/components/schemas/PublishedRewardsFormDataDto" + } + }, + "required": ["rewards"] + }, + "AdvancedSettingsFormDataDto": { + "type": "object", + "properties": { + "isPublic": { "type": "boolean", "example": true }, + "allowLateRegistration": { "type": "boolean", "example": false }, + "requireApproval": { "type": "boolean", "example": true }, + "maxParticipants": { + "type": "number", + "minimum": 1, + "maximum": 100000, + "example": 500 + }, + "customDomain": { + "type": "string", + "example": "hackathons.boundless.dev" + }, + "enableDiscord": { "type": "boolean", "example": true }, + "discordInviteLink": { + "type": "string", + "example": "https://discord.gg/boundless" + }, + "enableTelegram": { "type": "boolean", "example": true }, + "telegramInviteLink": { + "type": "string", + "example": "https://t.me/boundless" + } + }, + "required": [ + "isPublic", + "allowLateRegistration", + "requireApproval", + "enableDiscord", + "enableTelegram" + ] + }, + "UpdatePublishedHackathonAdvancedSettingsDto": { + "type": "object", + "properties": { + "advancedSettings": { + "$ref": "#/components/schemas/AdvancedSettingsFormDataDto" + } + }, + "required": ["advancedSettings"] + }, + "CreateRewardDistributionDto": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Client-supplied UUID for idempotent triggering. Duplicate requests with same key return existing distribution.", + "example": "a1b2c3d4-e5f6-47g8-h9i0-j1k2l3m4n5o6" + }, + "organizerNote": { + "type": "string", + "description": "Optional organizer note (max 500 chars) explaining the distribution context", + "example": "Allocating sponsors tier to finalists" + } + }, + "required": ["idempotencyKey"] + }, + "WinnerSnapshot": { + "type": "object", + "properties": { + "submissionId": { + "type": "string", + "description": "Submission ID of the winner" + }, + "rank": { + "type": "number", + "description": "Rank of the winner (1-based)" + }, + "submissionTitle": { + "type": "string", + "description": "Display name of the submission/team" + }, + "prizeTierName": { + "type": "string", + "description": "Prize tier this winner maps to" + }, + "prizeAmount": { + "type": "number", + "description": "Prize amount in USDC (7 decimals)" + }, + "walletAddresses": { + "type": "string", + "description": "Wallet public keys (Stellar) for prize distribution - comma-separated for teams, single address for individuals. Fetched from user.wallet.publicKey." + } + }, + "required": [ + "submissionId", + "rank", + "submissionTitle", + "prizeTierName", + "prizeAmount", + "walletAddresses" + ] + }, + "RewardDistributionSnapshot": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Client-supplied idempotency key (UUID) for replay safety. Duplicate trigger with same key returns existing distribution.", + "example": "a1b2c3d4-e5f6-47g8-h9i0-j1k2l3m4n5o6" + }, + "winners": { + "description": "Array of winners ranked and assigned to tiers at trigger time", + "type": "array", + "items": { "$ref": "#/components/schemas/WinnerSnapshot" } + }, + "totalPrizePool": { + "type": "number", + "description": "Total prize pool in USDC (7 decimals)" + }, + "platformFee": { + "type": "number", + "description": "Platform fee (7 decimals)" + }, + "totalRequired": { + "type": "number", + "description": "Total funding required (prizePool + platformFee)" + }, + "currency": { + "type": "string", + "description": "Currency code (hardcoded: USDC)" + }, + "escrowAddress": { + "type": "string", + "description": "Hackathon escrow address where funds will be released from (captures state at trigger)" + }, + "winnersChecksum": { + "type": "string", + "description": "SHA256 checksum of winners array (prevents tampering)" + }, + "snapshotAt": { + "type": "string", + "description": "ISO timestamp when snapshot was created", + "example": "2024-01-19T14:30:00Z" + }, + "organizerNote": { + "type": "string", + "description": "Organizer-supplied note explaining reward distribution context", + "nullable": true + } + }, + "required": [ + "idempotencyKey", + "winners", + "totalPrizePool", + "platformFee", + "totalRequired", + "currency", + "escrowAddress", + "winnersChecksum", + "snapshotAt", + "organizerNote" + ] + }, + "RewardDistributionResponseDto": { + "type": "object", + "properties": { + "distributionId": { + "type": "object", + "description": "UUID of the distribution record (only at trigger; null for status-only)", + "nullable": true + }, + "status": { + "type": "string", + "description": "Current status of the distribution", + "enum": [ + "NOT_TRIGGERED", + "PENDING_ADMIN_REVIEW", + "APPROVED", + "REJECTED", + "EXECUTING", + "COMPLETED", + "FAILED", + "PARTIAL_SUCCESS" + ] + }, + "snapshot": { + "description": "Immutable snapshot of winners and totals", + "allOf": [ + { "$ref": "#/components/schemas/RewardDistributionSnapshot" } + ] + }, + "rejectionReason": { + "type": "object", + "description": "Admin rejection reason (if status = REJECTED)", + "nullable": true + }, + "adminNote": { + "type": "object", + "description": "Admin note (if status = APPROVED/REJECTED)", + "nullable": true + }, + "adminUserId": { + "type": "object", + "description": "ID of the admin who approved/rejected (null if pending)", + "nullable": true + }, + "adminDecisionAt": { + "type": "object", + "description": "ISO timestamp of admin decision (null if pending)", + "nullable": true, + "example": "2024-01-19T15:45:00Z" + }, + "triggeredAt": { + "type": "string", + "description": "ISO timestamp when distribution was triggered", + "example": "2024-01-19T14:30:00Z" + }, + "updatedAt": { + "type": "string", + "description": "ISO timestamp of last status update", + "example": "2024-01-19T15:45:00Z" + } + }, + "required": ["distributionId", "status", "snapshot", "triggeredAt"] + }, + "HackathonEscrowMilestoneDto": { + "type": "object", + "properties": { + "description": { "type": "string" }, + "amount": { "type": "number" }, + "receiver": { "type": "string" }, + "status": { "type": "string" }, + "evidence": { "type": "string" }, + "flags": { "type": "object" } + }, + "required": ["description", "amount", "receiver", "status", "evidence"] + }, + "HackathonEscrowResponseDto": { + "type": "object", + "properties": { + "contractId": { "type": "string" }, + "escrowAddress": { "type": "string" }, + "balance": { "type": "number" }, + "milestones": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HackathonEscrowMilestoneDto" + } + }, + "isFunded": { "type": "boolean" }, + "canUpdate": { "type": "boolean" } + }, + "required": [ + "contractId", + "escrowAddress", + "balance", + "milestones", + "isFunded", + "canUpdate" + ] + }, + "InvitePartnerDto": { + "type": "object", + "properties": { + "partnerEmail": { "type": "string", "example": "sponsor@partner.io" }, + "partnerName": { "type": "string", "example": "Acme Corp" }, + "partnerLogo": { + "type": "string", + "example": "https://cdn.example.com/logo.png" + }, + "partnerLink": { "type": "string", "example": "https://acme.io" }, + "pledgedAmount": { + "type": "number", + "example": 1000, + "description": "Pledged amount in USDC" + }, + "currency": { + "type": "string", + "example": "USDC", + "default": "USDC" + }, + "message": { + "type": "string", + "description": "Optional message included in the invite" + }, + "showPublicly": { + "type": "boolean", + "description": "Whether the partner is shown publicly on the hackathon page", + "default": true + } + }, + "required": ["partnerEmail", "partnerName", "pledgedAmount"] + }, + "AllocationTargetDto": { + "type": "object", + "properties": { + "tierId": { + "type": "string", + "description": "Existing prize tier id to inflate. Either tierId or newTier must be set." + }, + "newTierLabel": { + "type": "string", + "description": "Create a new prize tier with this label. Either tierId or newTier must be set.", + "example": "Best AI Project" + }, + "newTierDescription": { + "type": "string", + "description": "Optional description for the new tier" + }, + "amount": { + "type": "number", + "description": "Net amount (USDC) to add to the tier" + } + }, + "required": ["amount"] + }, + "AllocateContributionDto": { + "type": "object", + "properties": { + "targets": { + "description": "One or more tiers to allocate this contribution into", + "type": "array", + "items": { "$ref": "#/components/schemas/AllocationTargetDto" } + } + }, + "required": ["targets"] + }, + "PrepareFundTransactionDto": { + "type": "object", + "properties": { + "signerAddress": { + "type": "string", + "description": "Stellar address of the partner wallet that will sign the transaction" + } + }, + "required": ["signerAddress"] + }, + "SubmitSignedTransactionDto": { + "type": "object", + "properties": { + "signedXdr": { + "type": "string", + "description": "Signed transaction XDR returned by the partner wallet" + } + }, + "required": ["signedXdr"] + }, + "TrackCustomQuestionDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Stable id, unique within the track." + }, + "label": { + "type": "string", + "description": "Question label shown on the submission form." + }, + "type": { + "type": "string", + "enum": ["short", "long", "url"], + "description": "Input type. 'short' = single-line, 'long' = textarea, 'url' = URL field." + }, + "maxLength": { + "type": "number", + "description": "Optional maxLength override (defaults: short=200, long=1000)." + }, + "required": { + "type": "boolean", + "description": "Whether an answer is required." + } + }, + "required": ["id", "label", "type"] + }, + "TrackRequiredArtifactDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Stable id, unique within the track." + }, + "label": { + "type": "string", + "description": "Artifact label (e.g. \"Figma file URL\")." + }, + "type": { + "type": "string", + "enum": ["figma", "github", "video", "pdf", "url"], + "description": "Artifact type — drives the placeholder + light hint UI." + }, + "required": { + "type": "boolean", + "description": "Whether submitting this artifact is required." + } + }, + "required": ["id", "label", "type"] + }, + "TrackResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "hackathonId": { "type": "string" }, + "slug": { "type": "string" }, + "name": { "type": "string" }, + "description": { "type": "string" }, + "type": { "type": "string" }, + "eligibility": { "type": "string", "enum": ["OPT_IN", "OPEN"] }, + "displayOrder": { "type": "number" }, + "isArchived": { "type": "boolean" }, + "entryCount": { + "type": "number", + "description": "Count of submissions that have opted into this track. Useful for organizer dashboards." + }, + "prompt": { + "type": "string", + "description": "Per-track customization (Phase B)." + }, + "customQuestions": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackCustomQuestionDto" } + }, + "requiredArtifacts": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackRequiredArtifactDto" } + }, + "createdAt": { "format": "date-time", "type": "string" }, + "updatedAt": { "format": "date-time", "type": "string" } + }, + "required": [ + "id", + "hackathonId", + "slug", + "name", + "eligibility", + "displayOrder", + "isArchived", + "entryCount", + "createdAt", + "updatedAt" + ] + }, + "CreateTrackDto": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Human-readable track name shown on the hackathon page.", + "example": "Best UI/UX" + }, + "slug": { + "type": "string", + "description": "URL-safe handle, unique within the hackathon. Auto-generated from name if omitted.", + "example": "best-ui-ux" + }, + "description": { + "type": "string", + "description": "Short blurb shown in the track picker and on results.", + "example": "Best end-to-end user experience and visual polish." + }, + "type": { + "type": "string", + "description": "Free-form classifier for badge styling. Common values: skill, technology, theme, special.", + "example": "skill" + }, + "eligibility": { + "type": "string", + "description": "OPT_IN (default): submitters explicitly enter. OPEN: every submission auto-eligible.", + "enum": ["OPT_IN", "OPEN"], + "default": "OPT_IN" + }, + "displayOrder": { + "type": "number", + "description": "Sort order. Lower numbers render first. Defaults to 0.", + "example": 10 + }, + "prompt": { + "type": "string", + "description": "Single open-ended prompt shown on the submission form. When set, the submitter must answer to opt in.", + "example": "Why does this project fit Best UI/UX?" + }, + "customQuestions": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackCustomQuestionDto" } + }, + "requiredArtifacts": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackRequiredArtifactDto" } + } + }, + "required": ["name"] + }, + "UpdateTrackDto": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "slug": { "type": "string" }, + "description": { "type": "string" }, + "type": { "type": "string" }, + "eligibility": { "type": "string", "enum": ["OPT_IN", "OPEN"] }, + "displayOrder": { "type": "number" }, + "isArchived": { + "type": "boolean", + "description": "Soft-archive instead of delete when entries already exist. Cannot be unset via this endpoint; recreate the track if needed." + }, + "prompt": { + "type": "string", + "description": "Single open-ended prompt." + }, + "customQuestions": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackCustomQuestionDto" } + }, + "requiredArtifacts": { + "type": "array", + "items": { "$ref": "#/components/schemas/TrackRequiredArtifactDto" } + } + } + }, + "RequestFundingOtpResponseDto": { + "type": "object", + "properties": { + "required": { + "type": "boolean", + "description": "Whether funding step-up is enforced for this action" + }, + "alreadyVerified": { + "type": "boolean", + "description": "True when a recent verification is still valid; the client can fund without entering a new code" + }, + "sent": { + "type": "boolean", + "description": "True when a fresh code was just emailed" + }, + "expiresInSeconds": { + "type": "number", + "description": "Seconds until the emailed code expires (0 when none sent)" + } + }, + "required": ["required", "alreadyVerified", "sent", "expiresInSeconds"] + }, + "VerifyFundingOtpDto": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "The 6-digit code emailed to the organizer", + "example": "123456" + } + }, + "required": ["code"] + }, + "VerifyFundingOtpResponseDto": { + "type": "object", + "properties": { + "verified": { + "type": "boolean", + "description": "True when the code was accepted" + }, + "expiresInSeconds": { + "type": "number", + "description": "Seconds the funding authorization remains valid" + } + }, + "required": ["verified", "expiresInSeconds"] + }, + "WinnerDistributionEntryDto": { + "type": "object", + "properties": { + "position": { + "type": "number", + "description": "Winner position (1-indexed; 1 = top winner).", + "example": 1, + "minimum": 1 + }, + "percent": { + "type": "number", + "description": "Percentage of the total budget allocated to this position. All entries must sum to exactly 100.", + "example": 100, + "minimum": 1 + } + }, + "required": ["position", "percent"] + }, + "PublishHackathonEscrowDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Stellar G-address that will own and sign the on-chain create_event transaction. For managed wallets, this is the platform-derived address tied to the organizer's account; for connected/multisig, it's the org treasury's G-address.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "tokenAddress": { + "type": "string", + "description": "Stellar Asset Contract (SAC) address the prize pool is denominated in. Must be whitelisted on the events contract (see admin runbook).", + "example": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" + }, + "budget": { + "type": "string", + "description": "Total prize budget in token-native units (e.g. 1000 = 1000 USDC, NOT stroops). Use a string when the value exceeds JavaScript's safe integer range. The backend converts to stroops via *10^7.", + "example": "1000" + }, + "winnerDistribution": { + "description": "Optional override for the winner distribution. Each entry maps a position to a percent of total_budget. Percents must sum to exactly 100. Defaults to a single winner at position 1 taking 100%.", + "type": "array", + "items": { + "$ref": "#/components/schemas/WinnerDistributionEntryDto" + } + }, + "contentUri": { + "type": "string", + "description": "Override for the public content_uri the contract stores against the event. Defaults to https://api.boundless.fi/hackathons//content.", + "example": "https://api.boundless.fi/hackathons/abc/content", + "maxLength": 512 + }, + "fundingMode": { + "type": "string", + "description": "Signing path. Defaults to EXTERNAL (return unsigned XDR for the caller to sign). Set to MANAGED to have the backend sign + submit using the caller user's managed wallet; the response carries the op in PENDING_CONFIRM with a txHash.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL", + "example": "MANAGED" + }, + "sourceWalletId": { + "type": "string", + "description": "For MANAGED funding, the organization treasury wallet to fund from. When set, the backend signs with that treasury (managed) wallet instead of the caller's personal wallet; ownerAddress must match the treasury wallet address. Omit to fund from the personal managed wallet." + } + }, + "required": ["ownerAddress", "tokenAddress", "budget"] + }, + "HackathonEscrowOpResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Internal cuid for the EscrowOp row. Use this for follow-up calls.", + "example": "cmpwiox7u0000yy4404ojbk9t" + }, + "opId": { + "type": "string", + "description": "Hex-encoded 32-byte op_id derived deterministically from the operation parameters. Used by the on-chain idempotency check.", + "example": "3cc257d743b1b44423dc8dbd417aedfe6e47ad489b5d301a2fbec5284d36de1c" + }, + "kind": { + "type": "string", + "description": "Contract operation kind.", + "enum": [ + "CREATE_EVENT", + "CANCEL_EVENT", + "ADD_FUNDS", + "APPLY_TO_BOUNTY", + "WITHDRAW_APPLICATION", + "SUBMIT", + "WITHDRAW_SUBMISSION", + "SELECT_WINNERS", + "CLAIM_MILESTONE" + ], + "example": "CREATE_EVENT" + }, + "status": { + "type": "string", + "description": "Status of the EscrowOp in its lifecycle.", + "enum": [ + "PENDING_BUILD", + "PENDING_SIGN", + "PENDING_SUBMIT", + "PENDING_CONFIRM", + "COMPLETED", + "FAILED", + "CANCELLED" + ], + "example": "PENDING_SIGN" + }, + "entityKind": { + "type": "string", + "description": "Entity kind the op operates on. Matches the application-level row (hackathon, bounty, grant, etc.).", + "example": "HACKATHON" + }, + "entityId": { + "type": "string", + "description": "Application-level row id this op acts on.", + "example": "cmpwihilf0000fd44iln3dzbg" + }, + "unsignedXdr": { + "type": "string", + "nullable": true, + "description": "Unsigned XDR transaction the wallet must sign. Present after the build phase completes (PENDING_SIGN onwards).", + "example": "AAAAAgAAAACdiamX7q...truncated..." + }, + "signerHint": { + "type": "string", + "nullable": true, + "description": "Stellar G-address expected to sign this op. The wallet routing layer on the webapp uses this to pick the right signer.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "txHash": { + "type": "string", + "nullable": true, + "description": "Soroban tx hash assigned at submit time. Set once the op reaches PENDING_CONFIRM or beyond.", + "example": "daafec9027da007b54eec34c54a5919edd7a8682bc96ccf7c7072982305cfa3b" + }, + "errorCode": { + "type": "string", + "nullable": true, + "description": "Contract error code when the op transitions to FAILED. Mirrors the on-chain error name (e.g. \"InsufficientEscrow\", \"OpAlreadySeen\", \"txBadAuth\").", + "example": "txBadAuth" + }, + "createdAt": { + "format": "date-time", + "type": "string", + "description": "Row creation time.", + "example": "2026-06-02T11:45:36.927Z" + }, + "updatedAt": { + "format": "date-time", + "type": "string", + "description": "Row last-updated time.", + "example": "2026-06-02T11:45:44.310Z" + } + }, + "required": [ + "id", + "opId", + "kind", + "status", + "entityKind", + "entityId", + "createdAt", + "updatedAt" + ] + }, + "CancelHackathonEscrowDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Organizer's Stellar G-address. Must match the on-chain hackathon owner.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side with the caller's platform-held wallet.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + }, + "sourceWalletId": { + "type": "string", + "description": "For MANAGED, the organization treasury wallet to sign with (the event contract-auth identity). ownerAddress must match it. Omit to use the caller's personal managed wallet." + } + }, + "required": ["ownerAddress"] + }, + "HackathonWinnerSelectionDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Stellar G-address of the participant being declared a winner. Must have an active submission anchor on this hackathon.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "position": { + "type": "number", + "description": "Winner position, 1-indexed. Must exist in the hackathon's on-chain winner_distribution.", + "example": 1, + "minimum": 1 + }, + "creditEarn": { + "type": "number", + "description": "Override the platform default credit_earn for this position. Defaults to 20/10/5 for positions 1/2/3 and 3 for the rest. Capped at 100 by the contract.", + "minimum": 0, + "maximum": 100, + "example": 20 + }, + "reputationBump": { + "type": "number", + "description": "Override the platform default reputation_bump for this position. Defaults to 50/25/10 for positions 1/2/3 and 5 for the rest.", + "minimum": 0, + "example": 50 + } + }, + "required": ["applicantAddress", "position"] + }, + "SelectHackathonWinnersDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Organizer's Stellar G-address that signs select_winners.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "selections": { + "description": "Winners to declare. Each must reference an applicant with an active submission anchor. Positions must be unique within the array.", + "type": "array", + "items": { + "$ref": "#/components/schemas/HackathonWinnerSelectionDto" + } + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + }, + "sourceWalletId": { + "type": "string", + "description": "For MANAGED, the organization treasury wallet to sign with (the event contract-auth identity). ownerAddress must match it. Omit to use the caller's personal managed wallet." + } + }, + "required": ["ownerAddress", "selections"] + }, + "HackathonSubmitSignedXdrDto": { + "type": "object", + "properties": { + "signedXdr": { + "type": "string", + "description": "The fully-signed XDR returned by the wallet (Freighter, Albedo, platform-managed signer, or a multisig coordinator). Backend submits this verbatim to Soroban RPC.", + "example": "AAAAAgAAAACdiamX7q...truncated..." + } + }, + "required": ["signedXdr"] + }, + "SubmitHackathonDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR. MANAGED signs server-side with the caller's platform-held wallet.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + }, + "contentUri": { + "type": "string", + "description": "On-chain content URI for the submission. Stored verbatim in the contract's submission anchor; off-chain content lives wherever the URI points (IPFS, S3, GitHub PR, etc.).", + "example": "ipfs://Qm.../project.json", + "minLength": 1, + "maxLength": 1024 + } + }, + "required": ["applicantAddress", "contentUri"] + }, + "WithdrawHackathonSubmissionDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR. MANAGED signs server-side with the caller's platform-held wallet.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["applicantAddress"] + }, + "ContributeHackathonDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR. MANAGED signs server-side with the caller's platform-held wallet.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + }, + "amount": { + "type": "string", + "description": "Amount in token-native units (e.g. 30 = 30 USDC, NOT stroops). Must be >= 10 USDC (contract minimum).", + "example": "30" + } + }, + "required": ["applicantAddress", "amount"] + }, + "CreateOrganizationDto": { "type": "object", "properties": {} }, + "OrganizationProfileStatsDto": { + "type": "object", + "properties": { + "projectsCount": { + "type": "number", + "description": "Number of projects under this organization", + "example": 12 + }, + "totalHackathons": { + "type": "number", + "description": "Total hackathons run by this organization", + "example": 5 + }, + "totalBounties": { + "type": "number", + "description": "Total bounties offered by this organization", + "example": 8 + }, + "totalGrants": { + "type": "number", + "description": "Total grants (projects with grants) under this organization", + "example": 3 + } + }, + "required": [ + "projectsCount", + "totalHackathons", + "totalBounties", + "totalGrants" + ] + }, + "OrganizationProfileDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Organization ID", + "example": "org_1234567890" + }, + "name": { + "type": "string", + "description": "Organization name", + "example": "Tech Innovators" + }, + "slug": { + "type": "string", + "description": "Organization slug", + "example": "tech-innovators" + }, + "logoUrl": { + "type": "string", + "description": "Logo URL", + "example": "https://example.com/logo.png" + }, + "description": { + "type": "string", + "description": "Organization description (from about or tagline)", + "example": "We are a community of developers building the future." + }, + "stats": { + "description": "Key stats for the organization profile", + "allOf": [ + { "$ref": "#/components/schemas/OrganizationProfileStatsDto" } + ] + } + }, + "required": ["id", "name", "slug", "logoUrl", "description", "stats"] + }, + "UpdateOrganizationDto": { "type": "object", "properties": {} }, + "UpdateMemberRoleDto": { "type": "object", "properties": {} }, + "InviteMemberDto": { "type": "object", "properties": {} }, + "TreasuryWalletResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "organizationId": { "type": "string" }, + "kind": { "type": "string", "enum": ["MANAGED", "CONNECTED"] }, + "publicKey": { "type": "string" }, + "label": { "type": "string" }, + "isDefault": { "type": "boolean" }, + "status": { + "type": "string", + "enum": ["ACTIVE", "ARCHIVED", "NEEDS_REVIEW"] + }, + "isMultisig": { "type": "boolean" }, + "multisigThreshold": { "type": "number", "nullable": true }, + "connectionMethod": { "type": "string", "nullable": true }, + "lastVerifiedAt": { "type": "string", "nullable": true }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" } + }, + "required": [ + "id", + "organizationId", + "kind", + "publicKey", + "label", + "isDefault", + "status", + "isMultisig", + "multisigThreshold", + "connectionMethod", + "lastVerifiedAt", + "createdAt", + "updatedAt" + ] + }, + "CreateManagedWalletDto": { + "type": "object", + "properties": { + "label": { + "type": "string", + "description": "Display label for the wallet", + "example": "Main treasury" + } + }, + "required": ["label"] + }, + "RegisterConnectedWalletDto": { + "type": "object", + "properties": { + "publicKey": { + "type": "string", + "description": "G-address of the external wallet" + }, + "label": { + "type": "string", + "description": "Display label", + "example": "Company multisig" + }, + "connectionMethod": { + "type": "string", + "enum": [ + "freighter", + "lobstr", + "albedo", + "xbull", + "hana", + "rabet", + "walletkit_generic" + ] + } + }, + "required": ["publicKey", "label", "connectionMethod"] + }, + "UpdateTreasuryWalletDto": { + "type": "object", + "properties": { + "label": { "type": "string", "description": "New display label" }, + "isDefault": { + "type": "boolean", + "description": "Make this the organization default" + } + } + }, + "WalletBalanceResponseDto": { + "type": "object", + "properties": { + "publicKey": { "type": "string" }, + "usdc": { "type": "string", "description": "USDC balance" }, + "xlm": { "type": "string", "description": "XLM balance (fee float)" } + }, + "required": ["publicKey", "usdc", "xlm"] + }, + "TreasuryPolicyRuleDto": { + "type": "object", + "properties": { + "min_usdc": { "type": "number", "example": 0 }, + "max_usdc": { "type": "object", "example": 1000, "nullable": true }, + "required_approvals": { "type": "number", "example": 1 }, + "approver_roles": { + "example": ["owner", "admin"], + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["min_usdc", "required_approvals", "approver_roles"] + }, + "TreasuryPolicyResponseDto": { + "type": "object", + "properties": { + "organizationId": { "type": "string" }, + "defaultWalletId": { "type": "string", "nullable": true }, + "rules": { + "type": "array", + "items": { "$ref": "#/components/schemas/TreasuryPolicyRuleDto" } + }, + "isDefault": { + "type": "boolean", + "description": "True when no policy is saved yet (defaults returned)" + }, + "updatedAt": { "type": "string", "nullable": true } + }, + "required": [ + "organizationId", + "defaultWalletId", + "rules", + "isDefault", + "updatedAt" + ] + }, + "UpdateTreasuryPolicyDto": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { "$ref": "#/components/schemas/TreasuryPolicyRuleDto" } + }, + "defaultWalletId": { + "type": "string", + "description": "Default source wallet id" + } + }, + "required": ["rules"] + }, + "InitiateSpendDto": { + "type": "object", + "properties": { + "sourceWalletId": { + "type": "string", + "description": "Treasury wallet to spend from" + }, + "destination": { + "type": "string", + "description": "Destination G-address or escrow contract id" + }, + "amount": { + "type": "string", + "description": "Amount in USDC", + "example": "2500.00" + }, + "purpose": { + "type": "string", + "description": "What the spend funds", + "example": "fund_hackathon_escrow" + }, + "referenceType": { + "type": "string", + "enum": ["hackathon", "bounty", "grant"] + }, + "referenceId": { "type": "string" } + }, + "required": ["sourceWalletId", "destination", "amount", "purpose"] + }, + "SpendRequestResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "organizationId": { "type": "string" }, + "sourceWalletId": { "type": "string" }, + "destination": { "type": "string" }, + "amount": { "type": "string" }, + "currency": { "type": "string" }, + "purpose": { "type": "string" }, + "referenceType": { "type": "string", "nullable": true }, + "referenceId": { "type": "string", "nullable": true }, + "initiatorUserId": { "type": "string" }, + "requiredApprovals": { "type": "number" }, + "approvals": { "type": "array", "items": { "type": "object" } }, + "status": { "type": "string" }, + "onChainTxHash": { "type": "string", "nullable": true }, + "createdAt": { "type": "string" }, + "approvedAt": { "type": "string", "nullable": true } + }, + "required": [ + "id", + "organizationId", + "sourceWalletId", + "destination", + "amount", + "currency", + "purpose", + "referenceType", + "referenceId", + "initiatorUserId", + "requiredApprovals", + "approvals", + "status", + "onChainTxHash", + "createdAt", + "approvedAt" + ] + }, + "SpendDecisionDto": { + "type": "object", + "properties": { + "note": { + "type": "string", + "description": "Optional note for the decision" + } + } + }, + "BuildSpendXdrResponseDto": { + "type": "object", + "properties": { + "unsignedXdr": { + "type": "string", + "description": "Unsigned transaction XDR to sign in-browser" + }, + "request": { "$ref": "#/components/schemas/SpendRequestResponseDto" } + }, + "required": ["unsignedXdr", "request"] + }, + "SubmitSpendSignedXdrDto": { + "type": "object", + "properties": { + "signedXdr": { + "type": "string", + "description": "The browser-signed transaction XDR" + } + }, + "required": ["signedXdr"] + }, + "TreasuryAuditEntryDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "action": { "type": "string" }, + "actorUserId": { "type": "string", "nullable": true }, + "actorKind": { "type": "string" }, + "walletId": { "type": "string", "nullable": true }, + "spendRequestId": { "type": "string", "nullable": true }, + "details": { + "type": "object", + "additionalProperties": true, + "nullable": true + }, + "createdAt": { "type": "string" } + }, + "required": [ + "id", + "action", + "actorUserId", + "actorKind", + "walletId", + "spendRequestId", + "details", + "createdAt" + ] + }, + "TreasuryAuditLogResponseDto": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { "$ref": "#/components/schemas/TreasuryAuditEntryDto" } + }, + "total": { "type": "number" }, + "page": { "type": "number" }, + "limit": { "type": "number" } + }, + "required": ["data", "total", "page", "limit"] + }, + "CreateVoteDto": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "description": "ID of the project being voted on" + }, + "entityType": { + "type": "string", + "enum": [ + "PROJECT", + "CROWDFUNDING_CAMPAIGN", + "HACKATHON_SUBMISSION", + "GRANT" + ], + "description": "Type of entity being voted on" + }, + "voteType": { + "type": "string", + "enum": ["UPVOTE", "DOWNVOTE"], + "default": "UPVOTE", + "description": "Type of vote (UPVOTE or DOWNVOTE)" + }, + "weight": { + "type": "number", + "default": 1, + "description": "Weight of the vote" + } + }, + "required": ["projectId", "entityType"] + }, + "CreateBlogPostDto": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Blog post title", + "example": "Getting Started with Stellar Smart Contracts", + "minLength": 3, + "maxLength": 300 + }, + "content": { + "type": "string", + "description": "Blog post content in markdown format", + "example": "# Introduction\n\nThis tutorial will teach you...", + "minLength": 10 + }, + "excerpt": { + "type": "string", + "description": "Short excerpt or summary", + "example": "Learn how to build your first smart contract on Stellar", + "maxLength": 500 + }, + "coverImage": { + "type": "string", + "description": "Cover image URL", + "example": "https://res.cloudinary.com/demo/image/upload/v1234567890/post-cover.jpg" + }, + "status": { + "type": "string", + "description": "Post status", + "enum": ["DRAFT", "PUBLISHED", "ARCHIVED", "SCHEDULED"], + "example": "DRAFT", + "default": "DRAFT" + }, + "tags": { + "description": "Post tags", + "example": ["smart-contracts", "soroban", "tutorial"], + "type": "array", + "items": { "type": "string" } + }, + "categories": { + "description": "Post categories", + "example": ["tutorials"], + "type": "array", + "items": { "type": "string" } + }, + "isFeatured": { + "type": "boolean", + "description": "Mark as featured post", + "example": false, + "default": false + }, + "isPinned": { + "type": "boolean", + "description": "Pin post to top", + "example": false, + "default": false + }, + "readingTime": { + "type": "number", + "description": "Reading time in minutes (auto-calculated if not provided)", + "example": 5 + }, + "seoTitle": { + "type": "string", + "description": "SEO title (overrides post title)", + "maxLength": 70 + }, + "seoDescription": { + "type": "string", + "description": "SEO meta description", + "maxLength": 160 + }, + "seoKeywords": { + "description": "SEO keywords", + "example": ["stellar", "blockchain", "smart contracts"], + "type": "array", + "items": { "type": "string" } + }, + "scheduledFor": { + "type": "string", + "description": "Schedule publication date (for SCHEDULED status)", + "example": "2025-12-31T10:00:00Z" + }, + "generateAI": { + "type": "boolean", + "description": "Generate AI content (excerpt, reading time, SEO, tags, category) if not provided", + "example": true, + "default": false + } + }, + "required": ["title", "content"] + }, + "UpdateBlogPostDto": { "type": "object", "properties": {} }, + "MetricDataDto": { + "type": "object", + "properties": { + "value": { + "type": "number", + "description": "The metric value", + "example": 1250 + }, + "change": { + "type": "number", + "description": "Percentage change", + "example": 12.5 + }, + "changeType": { + "type": "string", + "enum": ["positive", "negative", "neutral"], + "description": "Type of change", + "example": "positive" + }, + "label": { + "type": "string", + "description": "Metric label", + "example": "Total Users" + }, + "description": { + "type": "string", + "description": "Additional description", + "example": "Active users in the platform" + } + }, + "required": ["value", "change", "changeType", "label"] + }, + "HackathonMetricDataDto": { + "type": "object", + "properties": { + "value": { + "type": "number", + "description": "The metric value", + "example": 1250 + }, + "change": { + "type": "number", + "description": "Percentage change", + "example": 12.5 + }, + "changeType": { + "type": "string", + "enum": ["positive", "negative", "neutral"], + "description": "Type of change", + "example": "positive" + }, + "label": { + "type": "string", + "description": "Metric label", + "example": "Total Users" + }, + "description": { + "type": "string", + "description": "Additional description", + "example": "Active users in the platform" + }, + "additionalInfo": { + "type": "string", + "description": "Additional hackathon info", + "example": "3 active, 7 upcoming" + } + }, + "required": ["value", "change", "changeType", "label"] + }, + "OverviewMetricsDto": { + "type": "object", + "properties": { + "totalUsers": { "$ref": "#/components/schemas/MetricDataDto" }, + "organizations": { "$ref": "#/components/schemas/MetricDataDto" }, + "projects": { "$ref": "#/components/schemas/MetricDataDto" }, + "hackathons": { + "$ref": "#/components/schemas/HackathonMetricDataDto" + } + }, + "required": ["totalUsers", "organizations", "projects", "hackathons"] + }, + "OverviewChartDataDto": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { "$ref": "#/components/schemas/ChartDataPointDto" } + }, + "timeRange": { + "type": "string", + "enum": ["7d", "30d", "90d"], + "description": "Time range for the chart", + "example": "7d" + } + }, + "required": ["data", "timeRange"] + }, + "AdminOverviewResponseDto": { + "type": "object", + "properties": { + "metrics": { "$ref": "#/components/schemas/OverviewMetricsDto" }, + "chart": { "$ref": "#/components/schemas/OverviewChartDataDto" }, + "lastUpdated": { + "type": "string", + "description": "Last updated timestamp", + "example": "2025-12-26T10:30:00Z" + } + }, + "required": ["metrics", "chart", "lastUpdated"] + }, + "AdminCrowdfundingRejectDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Reason for rejection", + "example": "Campaign does not meet requirements" + } + } + }, + "AdminCrowdfundingRequestRevisionDto": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message for the creator explaining requested revisions", + "example": "Please update the project description to be more detailed" + }, + "reasons": { + "description": "Optional structured reasons", + "example": ["incomplete_description", "missing_team_info"], + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["message"] + }, + "AdminCrowdfundingNoteDto": { + "type": "object", + "properties": { + "note": { + "type": "string", + "description": "Short admin note or comment", + "example": "Reviewed initial submission" + } + }, + "required": ["note"] + }, + "AdminCrowdfundingAssignDto": { + "type": "object", + "properties": { + "reviewerId": { + "type": "string", + "description": "Reviewer (user) id to assign", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": ["reviewerId"] + }, + "ApproveMilestoneDto": { + "type": "object", + "properties": { + "notes": { + "type": "string", + "description": "Optional approval notes", + "example": "Milestone completed successfully" + } + } + }, + "RejectMilestoneDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Rejection reason", + "example": "Incomplete deliverables" + }, + "feedback": { + "type": "string", + "description": "Detailed feedback for rejection", + "example": "The submitted work does not meet the project requirements. Please revise and resubmit." + }, + "resubmissionDeadline": { + "type": "string", + "description": "Deadline for resubmission", + "example": "2025-02-01" + } + }, + "required": ["reason", "feedback"] + }, + "RequestMilestoneResubmissionDto": { + "type": "object", + "properties": { + "feedback": { + "type": "string", + "description": "Feedback explaining what needs to change", + "example": "Please improve the documentation and add more test cases" + }, + "resubmissionDeadline": { + "type": "string", + "description": "Deadline for resubmission", + "example": "2025-02-15" + } + }, + "required": ["feedback", "resubmissionDeadline"] + }, + "AddMilestoneReviewNoteDto": { + "type": "object", + "properties": { + "note": { + "type": "string", + "description": "Review note content", + "example": "Reviewed the code quality and found it satisfactory" + } + }, + "required": ["note"] + }, + "ManualEscrowActionDto": { + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": ["RELEASE", "REFUND", "PAUSE", "RESUME"], + "description": "Type of escrow action to execute", + "example": "RELEASE" + }, + "amount": { + "type": "number", + "description": "Amount to transfer (for RELEASE/REFUND)", + "example": 1000 + }, + "notes": { + "type": "string", + "description": "Optional notes for this action", + "example": "Releasing funds for completed milestone" + }, + "recipientAddress": { + "type": "string", + "description": "Recipient address (for RELEASE/REFUND)", + "example": "GAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + } + }, + "required": ["action"] + }, + "AssignDisputeDto": { + "type": "object", + "properties": { + "adminId": { + "type": "string", + "description": "Admin user ID to assign dispute to", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": ["adminId"] + }, + "AddDisputeNoteDto": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message content", + "example": "Contacted the project creator for more information" + }, + "isInternal": { + "type": "boolean", + "description": "Whether this is an internal note (not visible to parties)", + "example": false + } + }, + "required": ["message"] + }, + "ResolveDisputeDto": { + "type": "object", + "properties": { + "resolution": { + "type": "string", + "enum": [ + "APPROVED_WITH_CONDITIONS", + "REQUIRE_RESUBMISSION", + "PARTIAL_REFUND", + "FULL_REFUND", + "DISMISSED", + "ARBITRATION" + ], + "description": "Resolution type", + "example": "APPROVED_WITH_CONDITIONS" + }, + "resolutionNotes": { + "type": "string", + "description": "Detailed notes explaining the resolution", + "example": "Approved with condition that milestone is completed by next week" + } + }, + "required": ["resolution", "resolutionNotes"] + }, + "EscalateDisputeDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Reason for escalation to arbitration", + "example": "Parties cannot agree on resolution terms" + } + }, + "required": ["reason"] + }, + "AdminRewardQueueItemDto": { + "type": "object", + "properties": { + "distributionId": { + "type": "string", + "description": "Distribution ID (UUID)" + }, + "hackathonId": { + "type": "string", + "description": "Hackathon ID this distribution belongs to" + }, + "hackathonName": { + "type": "string", + "description": "Hackathon name" + }, + "organizationId": { + "type": "string", + "description": "Organization ID (for context)" + }, + "organizationName": { + "type": "string", + "description": "Organization name" + }, + "status": { + "type": "string", + "description": "Current status", + "enum": [ + "NOT_TRIGGERED", + "PENDING_ADMIN_REVIEW", + "APPROVED", + "REJECTED", + "EXECUTING", + "COMPLETED", + "FAILED", + "PARTIAL_SUCCESS" + ] + }, + "winnerCount": { + "type": "number", + "description": "Number of winners in snapshot" + }, + "totalRequired": { + "type": "number", + "description": "Total funding required (USDC, 7 decimals)" + }, + "triggeredByUserId": { + "type": "string", + "description": "ID of triggering organizer" + }, + "triggeredAt": { + "type": "string", + "description": "ISO timestamp of trigger", + "example": "2024-01-19T14:30:00Z" + }, + "adminNote": { + "type": "object", + "description": "Admin note (if reviewed)", + "nullable": true + } + }, + "required": [ + "distributionId", + "hackathonId", + "hackathonName", + "organizationId", + "organizationName", + "status", + "winnerCount", + "totalRequired", + "triggeredByUserId", + "triggeredAt" + ] + }, + "ApproveRewardDistributionDto": { + "type": "object", + "properties": { + "adminNote": { + "type": "string", + "description": "Optional admin note (max 500 chars)", + "example": "Approved. Escrow verified and funded." + } + } + }, + "RejectRewardDistributionDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Required reason for rejection (max 500 chars, visible to organizer)", + "example": "Escrow address not approved. Please contact support." + } + }, + "required": ["reason"] + }, + "RejectManualProjectDto": { "type": "object", "properties": {} }, + "RequestManualProjectChangesDto": { "type": "object", "properties": {} }, + "RejectProjectEditDto": { "type": "object", "properties": {} }, + "AdminWalletStatsDto": { + "type": "object", + "properties": { + "totalWallets": { "$ref": "#/components/schemas/MetricDataDto" }, + "activatedWallets": { "$ref": "#/components/schemas/MetricDataDto" }, + "inactiveWallets": { "$ref": "#/components/schemas/MetricDataDto" } + }, + "required": ["totalWallets", "activatedWallets", "inactiveWallets"] + }, + "AdminWalletUserDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "email": { "type": "string" }, + "username": { "type": "string" }, + "image": { "type": "string" } + }, + "required": ["id", "name", "email"] + }, + "AdminWalletListItemDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "publicKey": { "type": "string" }, + "isActivated": { "type": "boolean" }, + "createdAt": { "format": "date-time", "type": "string" }, + "users": { + "type": "array", + "items": { "$ref": "#/components/schemas/AdminWalletUserDto" } + } + }, + "required": ["id", "publicKey", "isActivated", "createdAt", "users"] + }, + "AdminWalletListResponseDto": { + "type": "object", + "properties": { + "wallets": { + "type": "array", + "items": { "$ref": "#/components/schemas/AdminWalletListItemDto" } + }, + "total": { "type": "number" }, + "page": { "type": "number" }, + "limit": { "type": "number" }, + "totalPages": { "type": "number" } + }, + "required": ["wallets", "total", "page", "limit", "totalPages"] + }, + "AdminWalletBalanceDto": { + "type": "object", + "properties": { + "balance": { "type": "string" }, + "assetCode": { "type": "string" }, + "assetIssuer": { "type": "string" }, + "assetType": { "type": "string" } + }, + "required": ["balance", "assetCode", "assetType"] + }, + "AdminWalletDetailsDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "publicKey": { "type": "string" }, + "isActivated": { "type": "boolean" }, + "createdAt": { "format": "date-time", "type": "string" }, + "balances": { + "type": "array", + "items": { "$ref": "#/components/schemas/AdminWalletBalanceDto" } + }, + "users": { + "type": "array", + "items": { "$ref": "#/components/schemas/AdminWalletUserDto" } + } + }, + "required": [ + "id", + "publicKey", + "isActivated", + "createdAt", + "balances", + "users" + ] + }, + "ReviewWindowDto": { + "type": "object", + "properties": { + "minBusinessDays": { "type": "number", "example": 1 }, + "maxBusinessDays": { "type": "number", "example": 3 }, + "estimatedCompletionAt": { + "type": "string", + "description": "ISO timestamp by which the review is expected to complete." + } + }, + "required": [ + "minBusinessDays", + "maxBusinessDays", + "estimatedCompletionAt" + ] + }, + "DeclineDetailsDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Human-readable reason from Didit, if available." + }, + "canRetry": { + "type": "boolean", + "description": "Whether the user is allowed to start a new verification.", + "example": true + } + }, + "required": ["canRetry"] + }, + "VerificationStatusDto": { + "type": "object", + "properties": { + "state": { + "type": "string", + "description": "Normalized verification state. Frontend should hide the verify button unless this is one of: not_started, declined, abandoned, expired.", + "enum": [ + "not_started", + "in_progress", + "in_review", + "approved", + "declined", + "abandoned", + "expired" + ] + }, + "canStartNew": { + "type": "boolean", + "description": "Whether the user can start a new verification session." + }, + "message": { + "type": "string", + "description": "Polite, render-ready copy summarising the current state." + }, + "verifiedAt": { + "type": "string", + "description": "ISO timestamp when the user became verified." + }, + "reviewedAt": { + "type": "string", + "description": "ISO timestamp of the last status transition." + }, + "reviewWindow": { + "description": "Estimated review window. Present only when state === \"in_review\".", + "allOf": [{ "$ref": "#/components/schemas/ReviewWindowDto" }] + }, + "decline": { + "description": "Decline details. Present only when state === \"declined\".", + "allOf": [{ "$ref": "#/components/schemas/DeclineDetailsDto" }] + } + }, + "required": ["state", "canStartNew", "message"] + }, + "CreateDiditSessionDto": { "type": "object", "properties": {} }, + "PricingPreviewResponseDto": { + "type": "object", + "properties": { + "feeBps": { + "type": "number", + "description": "Effective rate applied to this preview." + }, + "feeStroops": { + "type": "string", + "description": "Fee in stroops. String to preserve i128 precision." + }, + "poolStroops": { + "type": "string", + "description": "Pool released to winners; equals the requested budget." + }, + "totalDepositStroops": { + "type": "string", + "description": "budgetStroops + feeStroops; what the organizer signs for." + }, + "reason": { + "type": "string", + "description": "Audit label for the rate choice: default | foundation-tier | sales-override:* | waiver:*." + } + }, + "required": [ + "feeBps", + "feeStroops", + "poolStroops", + "totalDepositStroops", + "reason" + ] + }, + "Function": { "type": "object", "properties": {} }, + "BountyWinnerDistributionEntryDto": { + "type": "object", + "properties": { + "position": { + "type": "number", + "description": "1-indexed winner position.", + "example": 1 + }, + "percent": { + "type": "number", + "description": "Percent of total_budget for this position. All entries sum to 100.", + "example": 100 + } + }, + "required": ["position", "percent"] + }, + "PublishBountyEscrowDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Stellar G-address that will own and sign the create_event transaction.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "tokenAddress": { + "type": "string", + "description": "Whitelisted Stellar Asset Contract address the prize is in.", + "example": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" + }, + "budget": { + "type": "string", + "description": "Total prize in token-native units (e.g. 500 = 500 USDC, NOT stroops). String is required when the value exceeds the JS safe-integer range.", + "example": "500" + }, + "submissionDeadline": { + "type": "number", + "description": "Submission deadline as a Unix timestamp in seconds. Required for bounties that close at a specific time. Pass null only for always-open bounties (rare).", + "example": 1804383600, + "nullable": true + }, + "applicationCreditCost": { + "type": "number", + "description": "Credits required to apply. Defaults to 1; raise on high-value bounties to deter spam. Max 100 (enforced by the contract).", + "example": 1, + "default": 1, + "minimum": 0, + "maximum": 100 + }, + "winnerDistribution": { + "description": "Override for the winner distribution. Defaults to 100% to position 1.", + "type": "array", + "items": { + "$ref": "#/components/schemas/BountyWinnerDistributionEntryDto" + } + }, + "contentUri": { + "type": "string", + "description": "Override for the content URI stored on chain. Defaults to https://api.boundless.fi/bounties//content.", + "maxLength": 512 + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR for the wallet or multisig coordinator to sign. MANAGED has the backend sign and submit using the caller's platform-held wallet; the response is PENDING_CONFIRM with a txHash.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL", + "example": "MANAGED" + } + }, + "required": [ + "ownerAddress", + "tokenAddress", + "budget", + "submissionDeadline" + ] + }, + "BountyEscrowOpResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string", "description": "Internal EscrowOp cuid." }, + "opId": { + "type": "string", + "description": "Hex-encoded 32-byte contract op_id." + }, + "kind": { + "type": "string", + "description": "Contract operation kind." + }, + "status": { "type": "string", "description": "EscrowOp status." }, + "entityKind": { + "type": "string", + "description": "EntityKind (BOUNTY for this surface)." + }, + "entityId": { "type": "string", "description": "Bounty id." }, + "unsignedXdr": { + "type": "string", + "nullable": true, + "description": "Unsigned XDR for the wallet to sign (PENDING_SIGN onward)." + }, + "signerHint": { + "type": "string", + "nullable": true, + "description": "Stellar G-address expected to sign this op." + }, + "txHash": { + "type": "string", + "nullable": true, + "description": "Soroban tx hash (set once the op reaches PENDING_CONFIRM)." + }, + "errorCode": { + "type": "string", + "nullable": true, + "description": "On-chain or platform-side error code when the op transitions to FAILED." + }, + "createdAt": { "format": "date-time", "type": "string" }, + "updatedAt": { "format": "date-time", "type": "string" } + }, + "required": [ + "id", + "opId", + "kind", + "status", + "entityKind", + "entityId", + "createdAt", + "updatedAt" + ] + }, + "CancelBountyEscrowDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Organizer's Stellar G-address that signs cancel_event. Must match the bounty's on-chain owner.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side with the caller's platform-held wallet and submits.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["ownerAddress"] + }, + "BountyWinnerSelectionDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Stellar G-address of the applicant being declared winner. Must have an active submission anchor for this bounty.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "position": { + "type": "number", + "description": "Winner position, 1-indexed. Must exist in the bounty's on-chain winner_distribution (the contract rejects unknown positions).", + "example": 1, + "minimum": 1 + }, + "creditEarn": { + "type": "number", + "description": "Override the platform default credit_earn for this position. Defaults to 20/10/5 for positions 1/2/3 and 3 for the rest. Capped at 100 by the contract.", + "example": 20, + "minimum": 0, + "maximum": 100 + }, + "reputationBump": { + "type": "number", + "description": "Override the platform default reputation_bump for this position. Defaults to 50/25/10 for positions 1/2/3 and 5 for the rest.", + "example": 50, + "minimum": 0 + } + }, + "required": ["applicantAddress", "position"] + }, + "SelectBountyWinnersDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Organizer's Stellar G-address that signs select_winners. Must match the bounty's on-chain owner.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "selections": { + "description": "Winners to declare. Each entry must reference an applicant with an active submission. Positions must be unique within the array.", + "type": "array", + "items": { "$ref": "#/components/schemas/BountyWinnerSelectionDto" } + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) returns unsigned XDR; MANAGED signs server-side with the caller's platform-held wallet and submits.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["ownerAddress", "selections"] + }, + "BountySubmitSignedXdrDto": { + "type": "object", + "properties": { + "signedXdr": { + "type": "string", + "description": "Fully-signed XDR returned by the wallet or coordinator." + } + }, + "required": ["signedXdr"] + }, + "ApplyBountyDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["applicantAddress"] + }, + "WithdrawApplicationDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["applicantAddress"] + }, + "SubmitBountyDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + }, + "contentUri": { + "type": "string", + "description": "URI of the participant's submission content. Stored on chain in the contract's submission anchor; off-chain content lives wherever the URI points (S3, IPFS, GitHub PR, etc.).", + "example": "https://github.com/me/boundless-fix/pull/1", + "minLength": 1, + "maxLength": 1024 + } + }, + "required": ["applicantAddress", "contentUri"] + }, + "WithdrawSubmissionDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["applicantAddress"] + }, + "ContributeBountyDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Caller's Stellar G-address. Must match the caller's linked wallet on the platform; the backend rejects mismatches up front so the wallet does not get a tx it cannot sign.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "fundingMode": { + "type": "string", + "description": "EXTERNAL (default) returns unsigned XDR for the caller to sign. MANAGED signs server-side using the caller's platform-held wallet and submits immediately. Identical semantics to the publish flow.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + }, + "amount": { + "type": "string", + "description": "Amount in token-native units (e.g. 30 = 30 USDC, NOT stroops). Pass a string when the value exceeds the JS safe-integer range. Must be >= 10 USDC (contract minimum).", + "example": "30" + } + }, + "required": ["applicantAddress", "amount"] + }, + "CreateBountyApplicationDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "G-address that will receive payout if selected.", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + }, + "proposalShort": { + "type": "string", + "description": "Light proposal text (LIGHT vetting): 100 to 300 words. Required for LIGHT mode." + }, + "proposalFull": { + "type": "string", + "description": "Full proposal text (HEAVY vetting): 500 to 2000 words. Required for HEAVY mode." + }, + "portfolioLinks": { + "description": "Portfolio links. LIGHT: up to 3. HEAVY: up to 6.", + "type": "array", + "items": { "type": "string" } + }, + "estimatedDays": { + "type": "number", + "description": "Estimated days to complete (LIGHT). Required for LIGHT mode." + }, + "qualifications": { + "type": "string", + "description": "Qualifications text (HEAVY). Required for HEAVY mode." + }, + "videoIntroUrl": { + "type": "string", + "description": "Optional video intro URL (HEAVY)." + } + }, + "required": ["applicantAddress"] + }, + "EditBountyApplicationDto": { + "type": "object", + "properties": { + "proposalShort": { + "type": "string", + "description": "Light proposal text." + }, + "proposalFull": { + "type": "string", + "description": "Full proposal text." + }, + "portfolioLinks": { "type": "array", "items": { "type": "string" } }, + "estimatedDays": { "type": "number" }, + "qualifications": { "type": "string" }, + "videoIntroUrl": { "type": "string" } + } + }, + "SelectForPickDto": { + "type": "object", + "properties": { + "applicationId": { + "type": "string", + "description": "Application id to select as the single winner." + } + }, + "required": ["applicationId"] + }, + "CreateShortlistDto": { + "type": "object", + "properties": { + "applicationIds": { + "description": "Application ids to include in the shortlist.", + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["applicationIds"] + }, + "DeclineApplicationDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Reason for decline (surfaced to builder)." + } + } + }, + "JoinShowdownDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "G-address that will receive payout if winning", + "example": "GBXNQFDSBDPOIA3Q4LYIWBOJFFPCCV6IEDHBSJZEAYFKIKZVUO4QEDVS" + } + }, + "required": ["applicantAddress"] + }, + "BountyPrizeTierPublicDto": { + "type": "object", + "properties": { + "position": { "type": "number" }, + "amount": { + "type": "string", + "description": "Tier amount in token-native units." + }, + "passMark": { + "type": "number", + "nullable": true, + "description": "Optional minimum quality bar." + } + }, + "required": ["position", "amount"] + }, + "BountyOrganizationPublicDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "slug": { "type": "string", "nullable": true }, + "logo": { "type": "string", "nullable": true } + }, + "required": ["id", "name"] + }, + "BountyPublicDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "status": { + "type": "string", + "description": "Pillar lifecycle state (lowercase)." + }, + "type": { "type": "string" }, + "rewardAmount": { "type": "number" }, + "rewardCurrency": { "type": "string" }, + "vettingLevel": { + "type": "string", + "enum": ["NONE", "LIGHT", "HEAVY"] + }, + "selectionMode": { "type": "string", "enum": ["PICK", "SHOWDOWN"] }, + "submissionVisibility": { + "type": "string", + "enum": ["ORGANIZER_ONLY", "HIDDEN_UNTIL_DEADLINE"] + }, + "applicationWindowCloseAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "maxApplicants": { "type": "number", "nullable": true }, + "shortlistSize": { "type": "number", "nullable": true }, + "reputationMinimum": { "type": "number", "nullable": true }, + "prizeTiers": { + "type": "array", + "items": { "$ref": "#/components/schemas/BountyPrizeTierPublicDto" } + }, + "organization": { + "$ref": "#/components/schemas/BountyOrganizationPublicDto" + }, + "escrowEventId": { + "type": "string", + "nullable": true, + "description": "On-chain event id once published; null while in draft." + }, + "escrowTxHash": { "type": "string", "nullable": true }, + "createdAt": { "type": "string", "format": "date-time" } + }, + "required": [ + "id", + "title", + "description", + "status", + "type", + "rewardAmount", + "rewardCurrency", + "submissionVisibility", + "prizeTiers", + "organization", + "createdAt" + ] + }, + "BountyPublicListDto": { + "type": "object", + "properties": { + "bounties": { + "type": "array", + "items": { "$ref": "#/components/schemas/BountyPublicDto" } + }, + "total": { "type": "number" }, + "page": { "type": "number" }, + "limit": { "type": "number" } + }, + "required": ["bounties", "total", "page", "limit"] + }, + "GrantWinnerDistributionEntryDto": { + "type": "object", + "properties": { + "position": { + "type": "number", + "description": "1-indexed winner position", + "example": 1 + }, + "percent": { + "type": "number", + "description": "Percent of total_budget for this position. All sum to 100.", + "example": 100 + } + }, + "required": ["position", "percent"] + }, + "PublishGrantEscrowDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Organizer's Stellar G-address that signs the create_event transaction.", + "example": "GDVGP7DWODFVYQ5NHHLLD3WFVLUH5Y3HHELIKSNO4STEFCBETQAWDMKZ" + }, + "tokenAddress": { + "type": "string", + "description": "Whitelisted Stellar Asset Contract address.", + "example": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA" + }, + "budget": { + "type": "string", + "description": "Total budget in token-native units (NOT stroops).", + "example": "500" + }, + "nMilestones": { + "type": "number", + "description": "Number of milestones (n) for the ReleaseKind::Multi(n) release_kind. Per-recipient amount is total_budget * winner_share% / 100 / n_milestones.", + "example": 2, + "minimum": 1, + "maximum": 100 + }, + "submissionDeadline": { + "type": "number", + "description": "Optional submission deadline (Unix seconds).", + "example": 1804383600 + }, + "winnerDistribution": { + "description": "Override the winner distribution. Defaults to 100% to position 1.", + "type": "array", + "items": { + "$ref": "#/components/schemas/GrantWinnerDistributionEntryDto" + } + }, + "contentUri": { + "type": "string", + "description": "Override the public content_uri. Defaults to /grants//content.", + "maxLength": 512 + }, + "fundingMode": { + "type": "string", + "description": "Signing path. EXTERNAL (default) or MANAGED.", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["ownerAddress", "tokenAddress", "budget", "nMilestones"] + }, + "GrantEscrowOpResponseDto": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "opId": { "type": "string" }, + "kind": { "type": "string" }, + "status": { "type": "string" }, + "entityKind": { "type": "string" }, + "entityId": { "type": "string" }, + "unsignedXdr": { "type": "string", "nullable": true }, + "signerHint": { "type": "string", "nullable": true }, + "txHash": { "type": "string", "nullable": true }, + "errorCode": { "type": "string", "nullable": true }, + "createdAt": { "format": "date-time", "type": "string" }, + "updatedAt": { "format": "date-time", "type": "string" } + }, + "required": [ + "id", + "opId", + "kind", + "status", + "entityKind", + "entityId", + "createdAt", + "updatedAt" + ] + }, + "CancelGrantEscrowDto": { + "type": "object", + "properties": { + "ownerAddress": { + "type": "string", + "description": "Organizer's Stellar G-address." + }, + "fundingMode": { + "type": "string", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["ownerAddress"] + }, + "GrantWinnerSelectionDto": { + "type": "object", + "properties": { + "grantApplicationId": { + "type": "string", + "description": "GrantApplication.id to declare as a winner. The application must already have applicantAddress set (the Stellar G-address receiving the grant)." + }, + "position": { + "type": "number", + "description": "Winner position, 1-indexed.", + "minimum": 1, + "example": 1 + }, + "creditEarn": { + "type": "number", + "minimum": 0, + "maximum": 100, + "example": 20 + }, + "reputationBump": { "type": "number", "minimum": 0, "example": 50 } + }, + "required": ["grantApplicationId", "position"] + }, + "SelectGrantWinnersDto": { + "type": "object", + "properties": { + "ownerAddress": { "type": "string" }, + "selections": { + "type": "array", + "items": { "$ref": "#/components/schemas/GrantWinnerSelectionDto" } + }, + "fundingMode": { + "type": "string", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["ownerAddress", "selections"] + }, + "ClaimGrantMilestoneDto": { + "type": "object", + "properties": { + "ownerAddress": { "type": "string" }, + "grantMilestoneId": { + "type": "string", + "description": "GrantMilestone.id to claim payment for." + }, + "fundingMode": { + "type": "string", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["ownerAddress", "grantMilestoneId"] + }, + "GrantSubmitSignedXdrDto": { + "type": "object", + "properties": { "signedXdr": { "type": "string" } }, + "required": ["signedXdr"] + }, + "ContributeGrantDto": { + "type": "object", + "properties": { + "applicantAddress": { + "type": "string", + "description": "Contributor's Stellar G-address. Must match caller's wallet." + }, + "amount": { + "type": "string", + "description": "Amount in token-native units. Must be >= 10 USDC.", + "example": "30" + }, + "fundingMode": { + "type": "string", + "enum": ["EXTERNAL", "MANAGED"], + "default": "EXTERNAL" + } + }, + "required": ["applicantAddress", "amount"] + }, + "GrantPublicListItemDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Grant id.", + "example": "grant_123" + }, + "title": { + "type": "string", + "description": "Underlying project title used as the card title.", + "example": "On-chain governance research" + }, + "summary": { + "type": "string", + "description": "Short tagline/summary. Empty string when none is available.", + "example": "Funding research into delegated voting models." + }, + "coverImageUrl": { + "type": "string", + "description": "Banner or thumbnail image URL.", + "nullable": true, + "example": "https://cdn.boundless.dev/grants/abc.png" + }, + "status": { + "type": "string", + "description": "Lowercased grant status.", + "example": "open" + }, + "totalBudgetUsdc": { + "type": "string", + "description": "Total program budget in USDC, stringified.", + "nullable": true, + "example": "50000" + }, + "organizationId": { + "type": "string", + "description": "Owning organization id, if any.", + "nullable": true, + "example": "org_123" + }, + "organizationName": { + "type": "string", + "description": "Owning organization display name.", + "nullable": true, + "example": "Boundless Labs" + }, + "organizationLogoUrl": { + "type": "string", + "description": "Owning organization logo URL.", + "nullable": true, + "example": "https://cdn.boundless.dev/orgs/boundless.png" + }, + "category": { + "type": "string", + "description": "Underlying project category, if any.", + "nullable": true, + "example": "governance" + }, + "applicationCount": { + "type": "number", + "description": "Total submitted applications count.", + "example": 12 + }, + "createdAt": { + "type": "string", + "description": "When the grant was created.", + "example": "2026-05-01T12:00:00.000Z" + } + }, + "required": [ + "id", + "title", + "summary", + "coverImageUrl", + "status", + "totalBudgetUsdc", + "organizationId", + "organizationName", + "organizationLogoUrl", + "category", + "applicationCount", + "createdAt" + ] + }, + "GrantPublicListResponseDto": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { "$ref": "#/components/schemas/GrantPublicListItemDto" } + }, + "total": { + "type": "number", + "description": "Total count of grants matching the filters.", + "example": 84 + }, + "page": { + "type": "number", + "description": "Current page (1-indexed).", + "example": 1 + }, + "limit": { + "type": "number", + "description": "Items per page.", + "example": 20 + } + }, + "required": ["items", "total", "page", "limit"] + }, + "OpportunityType": { + "type": "string", + "enum": ["BOUNTY", "HACKATHON", "GRANT", "CROWDFUNDING"], + "description": "The pillar this opportunity belongs to." + }, + "OpportunityListItemDto": { + "type": "object", + "properties": { + "type": { + "description": "The pillar this opportunity belongs to.", + "example": "BOUNTY", + "allOf": [{ "$ref": "#/components/schemas/OpportunityType" }] + }, + "id": { + "type": "string", + "description": "Pillar-local primary key. Globally unique within a type.", + "example": "ckxyz123" + }, + "slug": { + "type": "string", + "description": "Optional URL slug. Hackathons and crowdfunding campaigns expose one; bounties and grants do not.", + "example": "open-defi-hack", + "nullable": true + }, + "title": { + "type": "string", + "description": "Display title for the card.", + "example": "Build a DAO governance dashboard" + }, + "summary": { + "type": "string", + "description": "Short blurb shown under the title. Empty string when the underlying pillar has no summary; never null.", + "example": "Ship a React dashboard that visualizes on-chain governance votes." + }, + "coverImageUrl": { + "type": "string", + "description": "Banner or hero image URL for the card.", + "example": "https://cdn.boundless.dev/banners/abc.png", + "nullable": true + }, + "organizationId": { + "type": "string", + "description": "Owning organization id. Null on crowdfunding or grants that lack an organization.", + "nullable": true, + "example": "org_123" + }, + "organizationName": { + "type": "string", + "description": "Owning organization display name.", + "nullable": true, + "example": "Boundless Labs" + }, + "organizationLogoUrl": { + "type": "string", + "description": "Owning organization logo URL.", + "nullable": true, + "example": "https://cdn.boundless.dev/orgs/boundless.png" + }, + "status": { + "type": "string", + "description": "Lowercased pillar-specific status (e.g. \"open\", \"upcoming\", \"active\").", + "example": "open" + }, + "totalRewardUsdc": { + "type": "string", + "description": "Total advertised reward in USDC, stringified. Null when not applicable to the pillar.", + "nullable": true, + "example": "5000.00" + }, + "fundedAmountUsdc": { + "type": "string", + "description": "Funded amount so far in USDC, crowdfunding only. Null elsewhere.", + "nullable": true, + "example": "1234.56" + }, + "publishedAt": { + "type": "string", + "description": "When this opportunity went live. Falls back to createdAt when the pillar lacks publishedAt.", + "example": "2026-05-01T12:00:00.000Z" + }, + "startsAt": { + "type": "string", + "description": "When the opportunity window opens.", + "nullable": true, + "example": "2026-05-15T00:00:00.000Z" + }, + "endsAt": { + "type": "string", + "description": "Application or submission deadline. Null for open-ended pillars (notably grants).", + "nullable": true, + "example": "2026-06-30T23:59:59.000Z" + }, + "participantCount": { + "type": "number", + "description": "Approximate participant count. Null when the pillar has no relation to count from.", + "nullable": true, + "example": 42 + }, + "tags": { + "description": "Pillar-defined tags. Empty array for pillars without a tag field; never null.", + "example": ["stellar", "defi"], + "type": "array", + "items": { "type": "string" } + }, + "detailUrl": { + "type": "string", + "description": "Path to the detail page on the frontend.", + "example": "/bounties/ckxyz123" + }, + "isFeatured": { + "type": "boolean", + "description": "True when this opportunity is currently featured. Drives the page-1 boost in the marketplace.", + "example": false + } + }, + "required": [ + "type", + "id", + "slug", + "title", + "summary", + "coverImageUrl", + "organizationId", + "organizationName", + "organizationLogoUrl", + "status", + "totalRewardUsdc", + "fundedAmountUsdc", + "publishedAt", + "startsAt", + "endsAt", + "participantCount", + "tags", + "detailUrl", + "isFeatured" + ] + }, + "OpportunityListResponseDto": { + "type": "object", + "properties": { + "items": { + "description": "Cards in the current page, post-merge.", + "type": "array", + "items": { "$ref": "#/components/schemas/OpportunityListItemDto" } + }, + "nextCursor": { + "type": "string", + "description": "Opaque cursor for the next page. Null when no more results are available.", + "nullable": true, + "example": "eyJzb3J0IjoibmV3ZXN0IiwicHJpbWFyeSI6IjIwMjYtMDUtMTVUMDA6MDA6MDAuMDAwWiIsImlkIjoiY2t4eXoxMjMifQ" + }, + "total": { + "type": "number", + "description": "Total rows matching the current filter combo (type, status, search, tags), summed across pillar adapters. Cursor-blind, so stable across paginated requests with the same filters.", + "example": 137 + } + }, + "required": ["items", "nextCursor", "total"] + }, + "SubscribeDto": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to subscribe", + "example": "user@example.com" + }, + "name": { + "type": "string", + "description": "Subscriber name", + "example": "John Doe" + }, + "source": { + "type": "string", + "description": "Subscription source", + "example": "website" + }, + "tags": { + "description": "Topic tags for subscription preferences", + "example": ["updates", "hackathons"], + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["email"] + }, + "UnsubscribeDto": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email address to unsubscribe", + "example": "user@example.com" + } + }, + "required": ["email"] + }, + "UpdatePreferencesDto": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Subscriber email address", + "example": "user@example.com" + }, + "tags": { + "description": "Topic tags to subscribe to. Valid: bounties, hackathons, grants, updates", + "example": ["updates", "hackathons"], + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["email", "tags"] + }, + "CreateNewsletterCampaignDto": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "description": "Campaign email subject line", + "example": "Boundless Weekly: New Hackathon Announced!" + }, + "content": { + "type": "string", + "description": "Campaign HTML content. Supports {{name}} placeholder.", + "example": "

Hello {{name}}

Check out our latest hackathon!

" + }, + "previewText": { + "type": "string", + "description": "Preview text shown in email clients", + "example": "New hackathon with $10k in prizes" + }, + "tags": { + "description": "Target subscriber tags — only subscribers with matching tags receive the campaign", + "example": ["hackathons", "updates"], + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["subject", "content"] + }, + "User": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "email": { "type": "string" }, + "emailVerified": { + "type": "boolean", + "default": false, + "readOnly": true + }, + "image": { "type": "string" }, + "createdAt": { + "type": "string", + "format": "date-time", + "default": "Generated at runtime" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "default": "Generated at runtime" + }, + "username": { "type": "string" }, + "displayUsername": { "type": "string" }, + "twoFactorEnabled": { + "type": "boolean", + "default": false, + "readOnly": true + }, + "lastLoginMethod": { "type": "string", "readOnly": true }, + "role": { "type": "string", "readOnly": true }, + "banned": { "type": "boolean", "default": false, "readOnly": true }, + "banReason": { "type": "string", "readOnly": true }, + "banExpires": { + "type": "string", + "format": "date-time", + "readOnly": true + } + }, + "required": ["name", "email", "createdAt", "updatedAt"] + }, + "Session": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "expiresAt": { "type": "string", "format": "date-time" }, + "token": { "type": "string" }, + "createdAt": { + "type": "string", + "format": "date-time", + "default": "Generated at runtime" + }, + "updatedAt": { "type": "string", "format": "date-time" }, + "ipAddress": { "type": "string" }, + "userAgent": { "type": "string" }, + "userId": { "type": "string" }, + "activeOrganizationId": { "type": "string" }, + "impersonatedBy": { "type": "string" } + }, + "required": ["expiresAt", "token", "createdAt", "updatedAt", "userId"] + }, + "Account": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "accountId": { "type": "string" }, + "providerId": { "type": "string" }, + "userId": { "type": "string" }, + "accessToken": { "type": "string" }, + "refreshToken": { "type": "string" }, + "idToken": { "type": "string" }, + "accessTokenExpiresAt": { "type": "string", "format": "date-time" }, + "refreshTokenExpiresAt": { "type": "string", "format": "date-time" }, + "scope": { "type": "string" }, + "password": { "type": "string" }, + "createdAt": { + "type": "string", + "format": "date-time", + "default": "Generated at runtime" + }, + "updatedAt": { "type": "string", "format": "date-time" } + }, + "required": [ + "accountId", + "providerId", + "userId", + "createdAt", + "updatedAt" + ] + }, + "Verification": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "identifier": { "type": "string" }, + "value": { "type": "string" }, + "expiresAt": { "type": "string", "format": "date-time" }, + "createdAt": { + "type": "string", + "format": "date-time", + "default": "Generated at runtime" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "default": "Generated at runtime" + } + }, + "required": [ + "identifier", + "value", + "expiresAt", + "createdAt", + "updatedAt" + ] + }, + "TwoFactor": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "secret": { "type": "string" }, + "backupCodes": { "type": "string" }, + "userId": { "type": "string" } + }, + "required": ["secret", "backupCodes", "userId"] + }, + "Organization": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "slug": { "type": "string" }, + "logo": { "type": "string" }, + "createdAt": { "type": "string", "format": "date-time" }, + "metadata": { "type": "string" } + }, + "required": ["name", "slug", "createdAt"] + }, + "Member": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "organizationId": { "type": "string" }, + "userId": { "type": "string" }, + "role": { "type": "string", "default": "member" }, + "createdAt": { "type": "string", "format": "date-time" } + }, + "required": ["organizationId", "userId", "role", "createdAt"] + }, + "Invitation": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "organizationId": { "type": "string" }, + "email": { "type": "string" }, + "role": { "type": "string" }, + "status": { "type": "string", "default": "pending" }, + "expiresAt": { "type": "string", "format": "date-time" }, + "createdAt": { + "type": "string", + "format": "date-time", + "default": "Generated at runtime" + }, + "inviterId": { "type": "string" } + }, + "required": [ + "organizationId", + "email", + "status", + "expiresAt", + "createdAt", + "inviterId" + ] + }, + "Passkey": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "publicKey": { "type": "string" }, + "userId": { "type": "string" }, + "credentialID": { "type": "string" }, + "counter": { "type": "number" }, + "deviceType": { "type": "string" }, + "backedUp": { "type": "boolean" }, + "transports": { "type": "string" }, + "createdAt": { "type": "string", "format": "date-time" }, + "aaguid": { "type": "string" } + }, + "required": [ + "publicKey", + "userId", + "credentialID", + "counter", + "deviceType", + "backedUp" + ] + } + } + } +} diff --git a/package-lock.json b/package-lock.json index 501b4fb3c..8d4b3b816 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "dependencies": { "@countrystatecity/countries": "^1.0.4", + "@creit.tech/stellar-wallets-kit": "^2.3.0", "@didit-protocol/sdk-web": "^0.1.8", "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", @@ -47,7 +48,6 @@ "@radix-ui/react-tooltip": "^1.2.8", "@react-three/drei": "^10.7.6", "@react-three/fiber": "^9.3.0", - "@sentry/nextjs": "^10.42.0", "@stellar/freighter-api": "^4.1.0", "@stellar/stellar-sdk": "^13.3.0", "@tabler/icons-react": "^3.36.1", @@ -111,6 +111,7 @@ "next-mdx-remote": "^6.0.0", "next-themes": "^0.4.6", "nextjs-toploader": "^3.9.17", + "openapi-fetch": "^0.17.0", "p-limit": "^7.3.0", "qrcode.react": "^4.2.0", "radix-ui": "^1.4.3", @@ -152,6 +153,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "husky": "^9.1.7", "lint-staged": "^16.1.2", + "openapi-typescript": "^7.13.0", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.6.14", "tailwindcss": "^4", @@ -161,6 +163,18 @@ "usb": "*" } }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "license": "MIT" + }, + "node_modules/@albedo-link/intent": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@albedo-link/intent/-/intent-0.12.0.tgz", + "integrity": "sha512-UlGBhi0qASDYOjLrOL4484vQ26Ee3zTK2oAgvPMClOs+1XNk3zbs3dECKZv+wqeSI8SkHow8mXLTa16eVh+dQA==", + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -233,6 +247,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -242,6 +257,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -272,6 +288,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -281,6 +298,7 @@ "version": "7.29.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -297,6 +315,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -313,6 +332,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -322,6 +342,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -331,6 +352,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", @@ -344,6 +366,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -361,6 +384,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -379,6 +403,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -388,6 +413,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -401,6 +427,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -425,6 +452,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -439,6 +467,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -457,6 +486,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -466,6 +496,95 @@ "node": ">=6.9.0" } }, + "node_modules/@base-org/account": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@base-org/account/-/account-2.4.0.tgz", + "integrity": "sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@coinbase/cdp-sdk": "^1.0.0", + "@noble/hashes": "1.4.0", + "clsx": "1.2.1", + "eventemitter3": "5.0.1", + "idb-keyval": "6.2.1", + "ox": "0.6.9", + "preact": "10.24.2", + "viem": "^2.31.7", + "zustand": "5.0.3" + } + }, + "node_modules/@base-org/account/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@base-org/account/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@base-org/account/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT", + "optional": true + }, + "node_modules/@base-org/account/node_modules/preact": { + "version": "10.24.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz", + "integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==", + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@base-org/account/node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, "node_modules/@better-auth/core": { "version": "1.6.11", "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.11.tgz", @@ -604,18 +723,267 @@ "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", "license": "MIT" }, + "node_modules/@bufbuild/protobuf": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.0.tgz", + "integrity": "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, "node_modules/@chevrotain/types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "license": "Apache-2.0" }, + "node_modules/@coinbase/cdp-sdk": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/@coinbase/cdp-sdk/-/cdp-sdk-1.51.0.tgz", + "integrity": "sha512-XK8+OXDER1jirYpuiOct4ij65ODQ31LsmyRrZi/J7zF4GB89qxWZ0KPfAdsqJMP7VvE4no+Q++MKkQtAJUBoyg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana-program/system": "^0.10.0", + "@solana-program/token": "^0.9.0", + "@solana/kit": "^5.5.1", + "abitype": "1.0.6", + "axios": "1.16.0", + "axios-retry": "^4.5.0", + "bs58": "^6.0.0", + "jose": "^6.2.0", + "md5": "^2.3.0", + "uncrypto": "^0.1.3", + "viem": "^2.47.0", + "zod": "^3.25.76" + } + }, + "node_modules/@coinbase/cdp-sdk/node_modules/abitype": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.6.tgz", + "integrity": "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.22.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@coinbase/cdp-sdk/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@countrystatecity/countries": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@countrystatecity/countries/-/countries-1.0.5.tgz", "integrity": "sha512-AsxLm46eYTnP+lLKKk8o2ShJslVX4pAh762Kjux/40sVBEVH152PSgevlBEUxRawNXrccCbA8CQYLAJj5s9Tyw==", "license": "ODbL-1.0" }, + "node_modules/@creit.tech/stellar-wallets-kit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@creit.tech/stellar-wallets-kit/-/stellar-wallets-kit-2.3.0.tgz", + "integrity": "sha512-BT21egwJE+zcKeGXPVAy5w6dhhUhoV1v7j5Eh7MG5L2QkvoFvd4ftgT3gMigEZ0e9U5cgIDKGFuVNLDhUePmxw==", + "license": "MIT", + "dependencies": { + "@albedo-link/intent": "0.12.0", + "@creit.tech/xbull-wallet-connect": "0.4.0", + "@hot-wallet/sdk": "1.0.11", + "@ledgerhq/hw-app-str": "7.2.8", + "@ledgerhq/hw-transport": "6.31.12", + "@ledgerhq/hw-transport-webusb": "6.29.12", + "@lobstrco/signer-extension-api": "2.0.0", + "@preact/signals": "2.9.0", + "@reown/appkit": "1.8.19", + "@stellar/freighter-api": "6.0.0", + "@stellar/stellar-base": "14.0.1", + "@trezor/connect-plugin-stellar": "10.0.0-alpha.1", + "@trezor/connect-web": "10.0.0-alpha.1", + "@twind/core": "1.1.3", + "@twind/preset-autoprefix": "1.0.7", + "@twind/preset-tailwind": "1.1.4", + "@walletconnect/sign-client": "2.23.0", + "@walletconnect/types": "2.23.9", + "htm": "3.1.1", + "preact": "^10.29.0" + } + }, + "node_modules/@creit.tech/stellar-wallets-kit/node_modules/@preact/signals": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-2.9.0.tgz", + "integrity": "sha512-hYrY0KyUqkDgOl1qba/JGn6y81pXnurn21PMaxfcMwdncdZ3M/oVdmpTvEnsGjh48dIwDVc7bjWHqIsngSjYug==", + "license": "MIT", + "dependencies": { + "@preact/signals-core": "^1.14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact": ">= 10.25.0 || >=11.0.0-0" + } + }, + "node_modules/@creit.tech/stellar-wallets-kit/node_modules/@stellar/freighter-api": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-6.0.0.tgz", + "integrity": "sha512-8CTQcKQmTq/wL715ZUzn1x1POpR0eYhYPKEiaeA7AT0WYBOauOGTxfWPFtSidX3ohAlJZP5HFXy1kG29cVjqxw==", + "license": "Apache-2.0", + "dependencies": { + "buffer": "6.0.3", + "semver": "7.7.1" + } + }, + "node_modules/@creit.tech/stellar-wallets-kit/node_modules/@twind/core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@twind/core/-/core-1.1.3.tgz", + "integrity": "sha512-/B/aNFerMb2IeyjSJy3SJxqVxhrT77gBDknLMiZqXIRr4vNJqiuhx7KqUSRzDCwUmyGuogkamz+aOLzN6MeSLw==", + "funding": [ + { + "type": "Open Collective", + "url": "https://opencollective.com/twind" + }, + { + "type": "Github Sponsor", + "url": "https://github.com/sponsors/tw-in-js" + }, + { + "type": "Ko-fi", + "url": "https://ko-fi.com/twind" + } + ], + "license": "MIT", + "dependencies": { + "csstype": "^3.1.1" + }, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "typescript": "^4.8.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@creit.tech/stellar-wallets-kit/node_modules/@twind/preset-autoprefix": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@twind/preset-autoprefix/-/preset-autoprefix-1.0.7.tgz", + "integrity": "sha512-3wmHO0pG/CVxYBNZUV0tWcL7CP0wD5KpyWAQE/KOalWmOVBj+nH6j3v6Y3I3pRuMFaG5DC78qbYbhA1O11uG3w==", + "funding": [ + { + "type": "Open Collective", + "url": "https://opencollective.com/twind" + }, + { + "type": "Github Sponsor", + "url": "https://github.com/sponsors/tw-in-js" + }, + { + "type": "Ko-fi", + "url": "https://ko-fi.com/twind" + } + ], + "license": "MIT", + "dependencies": { + "style-vendorizer": "^2.2.3" + }, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "@twind/core": "^1.1.0", + "typescript": "^4.8.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@creit.tech/stellar-wallets-kit/node_modules/@twind/preset-tailwind": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@twind/preset-tailwind/-/preset-tailwind-1.1.4.tgz", + "integrity": "sha512-zv85wrP/DW4AxgWrLfH7kyGn/KJF3K04FMLVl2AjoxZGYdCaoZDkL8ma3hzaKQ+WGgBFRubuB/Ku2Rtv/wjzVw==", + "funding": [ + { + "type": "Open Collective", + "url": "https://opencollective.com/twind" + }, + { + "type": "Github Sponsor", + "url": "https://github.com/sponsors/tw-in-js" + }, + { + "type": "Ko-fi", + "url": "https://ko-fi.com/twind" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "@twind/core": "^1.1.0", + "typescript": "^4.8.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@creit.tech/stellar-wallets-kit/node_modules/preact": { + "version": "10.29.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.2.tgz", + "integrity": "sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@creit.tech/stellar-wallets-kit/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@creit.tech/xbull-wallet-connect": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@creit.tech/xbull-wallet-connect/-/xbull-wallet-connect-0.4.0.tgz", + "integrity": "sha512-LrCUIqUz50SkZ4mv2hTqSmwews8CNRYVoZ9+VjLsK/1U8PByzXTxv1vZyenj6avRTG86ifpoeihz7D3D5YIDrQ==", + "dependencies": { + "rxjs": "^7.5.5", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@date-fns/tz": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", @@ -714,6 +1082,20 @@ "tslib": "^2.4.0" } }, + "node_modules/@emurgo/cardano-serialization-lib-browser": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-13.2.1.tgz", + "integrity": "sha512-7RfX1gI16Vj2DgCp/ZoXqyLAakWo6+X95ku/rYGbVzuS/1etrlSiJmdbmdm+eYmszMlGQjrtOJQeVLXoj4L/Ag==", + "license": "MIT", + "peer": true + }, + "node_modules/@emurgo/cardano-serialization-lib-nodejs": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-13.2.0.tgz", + "integrity": "sha512-Bz1zLGEqBQ0BVkqt1OgMxdBOE3BdUWUd7Ly9Ecr/aUwkA8AV1w1XzBMe4xblmJHnB1XXNlPH4SraXCvO+q0Mig==", + "license": "MIT", + "peer": true + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -845,106 +1227,103 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@fastify/otel": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@fastify/otel/-/otel-0.18.0.tgz", - "integrity": "sha512-3TASCATfw+ctICSb4ymrv7iCm0qJ0N9CarB+CZ7zIJ7KqNbwI5JjyDL1/sxoC0ccTO1Zyd1iQ+oqncPg5FJXaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], + "node_modules/@ethereumjs/common": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-10.1.2.tgz", + "integrity": "sha512-whWnhqAxwpDy4zWkM6rqMzb8nioZJpiys01N57+HDyanvK5IRzodV5tdMRDt66PD5vDjl2c9K5UcB039gU2Oyw==", "license": "MIT", + "peer": true, "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.212.0", - "@opentelemetry/semantic-conventions": "^1.28.0", - "minimatch": "^10.2.4" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0" + "@ethereumjs/util": "^10.1.2", + "eventemitter3": "^5.0.1" } }, - "node_modules/@fastify/otel/node_modules/@opentelemetry/api-logs": { - "version": "0.212.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.212.0.tgz", - "integrity": "sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" + "node_modules/@ethereumjs/rlp": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-10.1.2.tgz", + "integrity": "sha512-T5Zt6C2pd02Wd88Q9A5/UX+He1Q2Y1LntHxz/038tfbUMiqby4fYSSTLEDx+TEfJqw1BsJSBY/TSu6goUzlk+w==", + "license": "MPL-2.0", + "peer": true, + "bin": { + "rlp": "bin/rlp.cjs" }, "engines": { - "node": ">=8.0.0" + "node": ">=20" } }, - "node_modules/@fastify/otel/node_modules/@opentelemetry/instrumentation": { - "version": "0.212.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.212.0.tgz", - "integrity": "sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg==", - "license": "Apache-2.0", + "node_modules/@ethereumjs/tx": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-10.1.2.tgz", + "integrity": "sha512-bAYK3YaYkk+auzxGfZSRVDbLHvboJNTx8/tV6jaqgPVlrA1QKEEADDEp/EGz+KI4NQmTGxEtXZ8tV/WjniRNww==", + "license": "MPL-2.0", + "peer": true, "dependencies": { - "@opentelemetry/api-logs": "0.212.0", - "import-in-the-middle": "^2.0.6", - "require-in-the-middle": "^8.0.0" + "@ethereumjs/common": "^10.1.2", + "@ethereumjs/rlp": "^10.1.2", + "@ethereumjs/util": "^10.1.2", + "@noble/curves": "^2.0.1", + "@noble/hashes": "^2.0.1" }, "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">=20" } }, - "node_modules/@fastify/otel/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/@ethereumjs/tx/node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "2.2.0" + }, "engines": { - "node": "18 || 20 || >=22" + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@fastify/otel/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "license": "MIT", + "node_modules/@ethereumjs/util": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-10.1.2.tgz", + "integrity": "sha512-UPBgXtHHfQugoXOSAoeG3jdmPbl37cwV9y3XqTPAnw8tJj8np14TPV2uc5lOs7C2LMF9Ubn66zyaiYxgwGppng==", + "license": "MPL-2.0", + "peer": true, "dependencies": { - "balanced-match": "^4.0.2" + "@ethereumjs/rlp": "^10.1.2", + "@noble/curves": "^2.0.1", + "@noble/hashes": "^2.0.1" }, "engines": { - "node": "18 || 20 || >=22" + "node": ">=20" } }, - "node_modules/@fastify/otel/node_modules/import-in-the-middle": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", - "integrity": "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.15.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^2.2.0", - "module-details-from-path": "^1.0.4" - } - }, - "node_modules/@fastify/otel/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "license": "BlueOak-1.0.0", + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "license": "MIT", + "peer": true, "dependencies": { - "brace-expansion": "^5.0.5" + "@noble/hashes": "2.2.0" }, "engines": { - "node": "18 || 20 || >=22" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@fivebinaries/coin-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@fivebinaries/coin-selection/-/coin-selection-3.0.0.tgz", + "integrity": "sha512-h25Pn1ZA7oqQBQDodGAgIsQt66T2wDge9onBKNqE66WNWL0KJiKJbpij8YOLo5AAlEIg5IS7EB1QjBgDOIg6DQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@emurgo/cardano-serialization-lib-browser": "^13.2.0", + "@emurgo/cardano-serialization-lib-nodejs": "13.2.0" } }, "node_modules/@floating-ui/core": { @@ -1007,6 +1386,22 @@ "react-hook-form": "^7.55.0" } }, + "node_modules/@hot-wallet/sdk": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@hot-wallet/sdk/-/sdk-1.0.11.tgz", + "integrity": "sha512-qRDH/4yqnRCnk7L/Qd0/LDOKDUKWcFgvf6eRELJkP0OgxIe65i/iXaG+u2lL0mLbTGkiWYk67uAvEerNUv2gzA==", + "dependencies": { + "@near-js/crypto": "^1.4.0", + "@near-js/utils": "^1.0.0", + "@near-wallet-selector/core": "^8.9.13", + "@solana/wallet-adapter-base": "^0.9.23", + "@solana/web3.js": "^1.95.0", + "borsh": "^2.0.0", + "js-sha256": "^0.11.0", + "sha1": "^1.1.1", + "uuid4": "^2.0.3" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1571,17 +1966,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -1598,6 +1982,96 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@ledgerhq/devices": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-8.6.1.tgz", + "integrity": "sha512-PQR2fyWz7P/wMFHY9ZLz17WgFdxC/Im0RVDcWXpp24+iRQRyxhQeX2iG4mBKUzfaAW6pOIEiWt+vmJh88QP9rQ==", + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/errors": "^6.26.0", + "@ledgerhq/logs": "^6.13.0", + "rxjs": "^7.8.1", + "semver": "^7.3.5" + } + }, + "node_modules/@ledgerhq/errors": { + "version": "6.35.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.35.0.tgz", + "integrity": "sha512-qk9PbqIvze7NXGogVxNCsz60rNo5FrGj8gKqs7pcyDk+em5L6s70G7cRxR+1HTXdam4WoPfntUq+WX9zQUynkg==", + "license": "Apache-2.0" + }, + "node_modules/@ledgerhq/hw-app-str": { + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-app-str/-/hw-app-str-7.2.8.tgz", + "integrity": "sha512-VHICY9jyZW5LM/8zc/mSbW7fS2bAC1OTVOtRwdQLEDn6Gv9UaNcCWjaHI1UKAnDUqYX7DUQuIPiTP1b4O+mtUQ==", + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/errors": "^6.26.0", + "@ledgerhq/hw-transport": "^6.31.12", + "bip32-path": "^0.4.2" + } + }, + "node_modules/@ledgerhq/hw-transport": { + "version": "6.31.12", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.31.12.tgz", + "integrity": "sha512-FO5LRIXYC8ELtaohlO8qK0b3TfHUNBZ3+CXKPHiHj2jJwrxPf4s5kcgBYrmzuf1C/1vfrMOjzyty6OgrMIbU6Q==", + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/devices": "8.6.1", + "@ledgerhq/errors": "^6.26.0", + "@ledgerhq/logs": "^6.13.0", + "events": "^3.3.0" + } + }, + "node_modules/@ledgerhq/hw-transport-webusb": { + "version": "6.29.12", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-webusb/-/hw-transport-webusb-6.29.12.tgz", + "integrity": "sha512-mMGKPYAUz9MNcURe+hSTSHwqPwCli6D0lCl15Z4hDOpcqhZ26vwoeWVKeQp53NNCetHOl0lauPkN43Gt9pIggg==", + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/devices": "8.6.1", + "@ledgerhq/errors": "^6.26.0", + "@ledgerhq/hw-transport": "^6.31.12", + "@ledgerhq/logs": "^6.13.0" + } + }, + "node_modules/@ledgerhq/logs": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/logs/-/logs-6.17.0.tgz", + "integrity": "sha512-yra33g5q/AU7+PwAws+GaVpQGUuxnDREjVBnviJjcaJLVKuLzI4pnj8Bd3nY3fypM5k1yZEYKEXfUuGFUjP2+w==", + "license": "Apache-2.0" + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.6.0.tgz", + "integrity": "sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/react": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@lit/react/-/react-1.0.8.tgz", + "integrity": "sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==", + "license": "BSD-3-Clause", + "optional": true, + "peerDependencies": { + "@types/react": "17 || 18 || 19" + } + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", + "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0" + } + }, + "node_modules/@lobstrco/signer-extension-api": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lobstrco/signer-extension-api/-/signer-extension-api-2.0.0.tgz", + "integrity": "sha512-jwlVyzMFF296iaNgMWn1lu+EU6BeUD4mgPurEsy8EygYNCrjA8igLpsDlXhfvXhst9tX5w4wRuTDX+FZtpfCug==", + "license": "GPL-3.0" + }, "node_modules/@lottiefiles/dotlottie-react": { "version": "0.17.15", "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-react/-/dotlottie-react-0.17.15.tgz", @@ -1691,6 +2165,16 @@ "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", "license": "BSD-2-Clause" }, + "node_modules/@mobily/ts-belt": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@mobily/ts-belt/-/ts-belt-3.13.1.tgz", + "integrity": "sha512-K5KqIhPI/EoCTbA6CGbrenM9s41OouyK8A03fGJJcla/zKucsgLbz8HNbeseoLarRPgyWJsUyCYqFhI7t3Ra9Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10.*" + } + }, "node_modules/@monogrid/gainmap-js": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", @@ -1703,6 +2187,293 @@ "three": ">= 0.159.0" } }, + "node_modules/@msgpack/msgpack": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.1.2.tgz", + "integrity": "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==", + "license": "ISC", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@near-js/accounts": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@near-js/accounts/-/accounts-1.4.1.tgz", + "integrity": "sha512-ni3QT9H3NdrbVVKyx56yvz93r89Dvpc/vgVtiIK2OdXjkK6jcj+UKMDRQ6F7rd9qJOInLkHZbVBtcR6j1CXLjw==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/crypto": "1.4.2", + "@near-js/providers": "1.0.3", + "@near-js/signers": "0.2.2", + "@near-js/transactions": "1.3.3", + "@near-js/types": "0.3.1", + "@near-js/utils": "1.1.0", + "@noble/hashes": "1.7.1", + "borsh": "1.0.0", + "depd": "2.0.0", + "is-my-json-valid": "^2.20.6", + "lru_map": "0.4.1", + "near-abi": "0.2.0" + } + }, + "node_modules/@near-js/accounts/node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@near-js/accounts/node_modules/borsh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz", + "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@near-js/crypto": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@near-js/crypto/-/crypto-1.4.2.tgz", + "integrity": "sha512-GRfchsyfWvSAPA1gI9hYhw5FH94Ac1BUo+Cmp5rSJt/V0K3xVzCWgOQxvv4R3kDnWjaXJEuAmpEEnr4Bp3FWrA==", + "license": "ISC", + "dependencies": { + "@near-js/types": "0.3.1", + "@near-js/utils": "1.1.0", + "@noble/curves": "1.8.1", + "borsh": "1.0.0", + "randombytes": "2.1.0", + "secp256k1": "5.0.1" + } + }, + "node_modules/@near-js/crypto/node_modules/borsh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz", + "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==", + "license": "Apache-2.0" + }, + "node_modules/@near-js/keystores": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@near-js/keystores/-/keystores-0.2.2.tgz", + "integrity": "sha512-DLhi/3a4qJUY+wgphw2Jl4S+L0AKsUYm1mtU0WxKYV5OBwjOXvbGrXNfdkheYkfh3nHwrQgtjvtszX6LrRXLLw==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/crypto": "1.4.2", + "@near-js/types": "0.3.1" + } + }, + "node_modules/@near-js/keystores-browser": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@near-js/keystores-browser/-/keystores-browser-0.2.2.tgz", + "integrity": "sha512-Pxqm7WGtUu6zj32vGCy9JcEDpZDSB5CCaLQDTQdF3GQyL0flyRv2I/guLAgU5FLoYxU7dJAX9mslJhPW7P2Bfw==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/crypto": "1.4.2", + "@near-js/keystores": "0.2.2" + } + }, + "node_modules/@near-js/keystores-node": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@near-js/keystores-node/-/keystores-node-0.1.2.tgz", + "integrity": "sha512-MWLvTszZOVziiasqIT/LYNhUyWqOJjDGlsthOsY6dTL4ZcXjjmhmzrbFydIIeQr+CcEl5wukTo68ORI9JrHl6g==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/crypto": "1.4.2", + "@near-js/keystores": "0.2.2" + } + }, + "node_modules/@near-js/providers": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@near-js/providers/-/providers-1.0.3.tgz", + "integrity": "sha512-VJMboL14R/+MGKnlhhE3UPXCGYvMd1PpvF9OqZ9yBbulV7QVSIdTMfY4U1NnDfmUC2S3/rhAEr+3rMrIcNS7Fg==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/transactions": "1.3.3", + "@near-js/types": "0.3.1", + "@near-js/utils": "1.1.0", + "borsh": "1.0.0", + "exponential-backoff": "^3.1.2" + }, + "optionalDependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/@near-js/providers/node_modules/borsh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz", + "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@near-js/providers/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@near-js/signers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@near-js/signers/-/signers-0.2.2.tgz", + "integrity": "sha512-M6ib+af9zXAPRCjH2RyIS0+RhCmd9gxzCeIkQ+I2A3zjgGiEDkBZbYso9aKj8Zh2lPKKSH7h+u8JGymMOSwgyw==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/crypto": "1.4.2", + "@near-js/keystores": "0.2.2", + "@noble/hashes": "1.3.3" + } + }, + "node_modules/@near-js/signers/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@near-js/transactions": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@near-js/transactions/-/transactions-1.3.3.tgz", + "integrity": "sha512-1AXD+HuxlxYQmRTLQlkVmH+RAmV3HwkAT8dyZDu+I2fK/Ec9BQHXakOJUnOBws3ihF+akQhamIBS5T0EXX/Ylw==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/crypto": "1.4.2", + "@near-js/signers": "0.2.2", + "@near-js/types": "0.3.1", + "@near-js/utils": "1.1.0", + "@noble/hashes": "1.7.1", + "borsh": "1.0.0" + } + }, + "node_modules/@near-js/transactions/node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@near-js/transactions/node_modules/borsh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz", + "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@near-js/types": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@near-js/types/-/types-0.3.1.tgz", + "integrity": "sha512-8qIA7ynAEAuVFNAQc0cqz2xRbfyJH3PaAG5J2MgPPhD18lu/tCGd6pzYg45hjhtiJJRFDRjh/FUWKS+ZiIIxUw==", + "license": "ISC" + }, + "node_modules/@near-js/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@near-js/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-5XWRq7xpu8Wud9pRXe2U347KXyi0mXofedUY2DQ9TaqiZUcMIaN9xj7DbCs2v6dws3pJyYrT1KWxeNp5fSaY3w==", + "license": "ISC", + "dependencies": { + "@near-js/types": "0.3.1", + "@scure/base": "^1.2.0", + "depd": "2.0.0", + "mustache": "4.0.0" + } + }, + "node_modules/@near-js/wallet-account": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@near-js/wallet-account/-/wallet-account-1.3.3.tgz", + "integrity": "sha512-GDzg/Kz0GBYF7tQfyQQQZ3vviwV8yD+8F2lYDzsWJiqIln7R1ov0zaXN4Tii86TeS21KPn2hHAsVu3Y4txa8OQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "@near-js/accounts": "1.4.1", + "@near-js/crypto": "1.4.2", + "@near-js/keystores": "0.2.2", + "@near-js/providers": "1.0.3", + "@near-js/signers": "0.2.2", + "@near-js/transactions": "1.3.3", + "@near-js/types": "0.3.1", + "@near-js/utils": "1.1.0", + "borsh": "1.0.0" + } + }, + "node_modules/@near-js/wallet-account/node_modules/borsh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz", + "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@near-wallet-selector/core": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/@near-wallet-selector/core/-/core-8.10.2.tgz", + "integrity": "sha512-MH8sg6XHyylq2ZXxnOjrKHMCmuRgFfpfdC816fW0R8hctZiXZ0lmfLvgG1xfA2BAxrVytiU1g3dcE97/P5cZqg==", + "dependencies": { + "borsh": "1.0.0", + "events": "3.3.0", + "js-sha256": "0.9.0", + "rxjs": "7.8.1" + }, + "peerDependencies": { + "near-api-js": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@near-wallet-selector/core/node_modules/borsh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz", + "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==", + "license": "Apache-2.0" + }, + "node_modules/@near-wallet-selector/core/node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==", + "license": "MIT" + }, + "node_modules/@near-wallet-selector/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/@next/env": { "version": "16.2.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", @@ -1849,6 +2620,33 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@noble/curves": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.1" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@noble/hashes": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", @@ -1861,524 +2659,389 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", "license": "Apache-2.0", "engines": { - "node": ">=8.0.0" + "node": ">=14" } }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.214.0.tgz", - "integrity": "sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" + "node_modules/@panva/hkdf": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", + "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" } }, - "node_modules/@opentelemetry/core": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", - "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", - "license": "Apache-2.0", + "node_modules/@phosphor-icons/webcomponents": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@phosphor-icons/webcomponents/-/webcomponents-2.1.5.tgz", + "integrity": "sha512-JcvQkZxvcX2jK+QCclm8+e8HXqtdFW9xV4/kk2aL9Y3dJA2oQVt+pzbv1orkumz3rfx4K9mn9fDoMr1He1yr7Q==", + "license": "MIT", "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "lit": "^3" } }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.214.0.tgz", - "integrity": "sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.214.0", - "import-in-the-middle": "^3.0.0", - "require-in-the-middle": "^8.0.0" - }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", "engines": { - "node": "^18.19.0 || >=20.6.0" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "funding": { + "url": "https://opencollective.com/pkgr" } }, - "node_modules/@opentelemetry/instrumentation-amqplib": { - "version": "0.61.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.61.0.tgz", - "integrity": "sha512-mCKoyTGfRNisge4br0NpOFSy2Z1NnEW8hbCJdUDdJFHrPqVzc4IIBPA/vX0U+LUcQqrQvJX+HMIU0dbDRe0i0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.33.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node_modules/@preact/signals-core": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.14.2.tgz", + "integrity": "sha512-RZHdBj9ZF4n40Rp4jS052EHHjBWf96P9oNdXPfhQTovCuWY9iQn3Gq+gOTJSgBO9A/JBuPfMOWsSX/lIU9Pc/A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" } }, - "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.57.0.tgz", - "integrity": "sha512-FMEBChnI4FLN5TE9DHwfH7QpNir1JzXno1uz/TAucVdLCyrG0jTrKIcNHt/i30A0M2AunNBCkcd8Ei26dIPKdg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/connect": "3.4.38" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause", + "peer": true }, - "node_modules/@opentelemetry/instrumentation-dataloader": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.31.0.tgz", - "integrity": "sha512-f654tZFQXS5YeLDNb9KySrwtg7SnqZN119FauD7acBoTzuLduaiGTNz88ixcVSOOMGZ+EjJu/RFtx5klObC95g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause", + "peer": true }, - "node_modules/@opentelemetry/instrumentation-fs": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.33.0.tgz", - "integrity": "sha512-sCZWXGalQ01wr3tAhSR9ucqFJ0phidpAle6/17HVjD6gN8FLmZMK/8sKxdXYHy3PbnlV1P4zeiSVFNKpbFMNLA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.214.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause", + "peer": true }, - "node_modules/@opentelemetry/instrumentation-generic-pool": { - "version": "0.57.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.57.0.tgz", - "integrity": "sha512-orhmlaK+ZIW9hKU+nHTbXrCSXZcH83AescTqmpamHRobRmYSQwRbD0a1odc0yAzuzOtxYiHiXAnpnIpaSSY7Ow==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "license": "BSD-3-Clause", + "peer": true }, - "node_modules/@opentelemetry/instrumentation-graphql": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.62.0.tgz", - "integrity": "sha512-3YNuLVPUxafXkH1jBAbGsKNsP3XVzcFDhCDCE3OqBwCwShlqQbLMRMFh1T/d5jaVZiGVmSsfof+ICKD2iOV8xg==", - "license": "Apache-2.0", + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", + "peer": true, "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@protobufjs/aspromise": "^1.1.1" } }, - "node_modules/@opentelemetry/instrumentation-hapi": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.60.0.tgz", - "integrity": "sha512-aNljZKYrEa7obLAxd1bCEDxF7kzCLGXTuTJZ8lMR9rIVEjmuKBXN1gfqpm/OB//Zc2zP4iIve1jBp7sr3mQV6w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause", + "peer": true }, - "node_modules/@opentelemetry/instrumentation-http": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.214.0.tgz", - "integrity": "sha512-FlkDhZDRjDJDcO2LcSCtjRpkal1NJ8y0fBqBhTvfAR3JSYY2jAIj1kSS5IjmEBt4c3aWv+u/lqLuoCDrrKCSKg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/instrumentation": "0.214.0", - "@opentelemetry/semantic-conventions": "^1.29.0", - "forwarded-parse": "2.1.2" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } + "node_modules/@protobufjs/inquire": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", + "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", + "license": "BSD-3-Clause", + "peer": true }, - "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.1.tgz", - "integrity": "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==", - "license": "Apache-2.0", + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", + "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", + "license": "MIT", "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@opentelemetry/instrumentation-kafkajs": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.23.0.tgz", - "integrity": "sha512-4K+nVo+zI+aDz0Z85SObwbdixIbzS9moIuKJaYsdlzcHYnKOPtB7ya8r8Ezivy/GVIBHiKJVq4tv+BEkgOMLaQ==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.30.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@opentelemetry/instrumentation-knex": { - "version": "0.58.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.58.0.tgz", - "integrity": "sha512-Hc/o8fSsaWxZ8r1Yw4rNDLwTpUopTf4X32y4W6UhlHmW8Wizz8wfhgOKIelSeqFVTKBBPIDUOsQWuIMxBmu8Bw==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "license": "MIT", "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.33.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@opentelemetry/instrumentation-koa": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.62.0.tgz", - "integrity": "sha512-uVip0VuGUQXZ+vFxkKxAUNq8qNl+VFlyHDh/U6IQ8COOEDfbEchdaHnpFrMYF3psZRUuoSIgb7xOeXj00RdwDA==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.36.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { - "@opentelemetry/api": "^1.9.0" + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@opentelemetry/instrumentation-lru-memoizer": { - "version": "0.58.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.58.0.tgz", - "integrity": "sha512-6grM3TdMyHzlGY1cUA+mwoPueB1F3dYKgKtZIH6jOFXqfHAByyLTc+6PFjGM9tKh52CFBJaDwodNlL/Td39z7Q==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@opentelemetry/instrumentation-mongodb": { - "version": "0.67.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.67.0.tgz", - "integrity": "sha512-1WJp5N1lYfHq2IhECOTewFs5Tf2NfUOwQRqs/rZdXKTezArMlucxgzAaqcgp3A3YREXopXTpXHsxZTGHjNhMdQ==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.8.tgz", + "integrity": "sha512-5nZrJTF7gH+e0nZS7/QxFz6tJV4VimhQb1avEgtsJxvvIp5JilL+c58HICsKzPxghdwaDt48hEfPM1au4zGy+w==", + "license": "MIT", "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.33.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@opentelemetry/instrumentation-mongoose": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.60.0.tgz", - "integrity": "sha512-8BahAZpKsOoc+lrZGb7Ofn4g3z8qtp5IxDfvAVpKXsEheQN7ONMH5djT5ihy6yf8yyeQJGS0gXFfpEAEeEHqQg==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.33.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.60.0.tgz", - "integrity": "sha512-08pO8GFPEIz2zquKDGteBZDNmwketdgH8hTe9rVYgW9kCJXq1Psj3wPQGx+VaX4ZJKCfPeoLMYup9+cxHvZyVQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.33.0", - "@types/mysql": "2.15.27" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql2": { - "version": "0.60.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.60.0.tgz", - "integrity": "sha512-m/5d3bxQALllCzezYDk/6vajh0tj5OijMMvOZGr+qN1NMXm1dzMNwyJ0gNZW7Fo3YFRyj/jJMxIw+W7d525dlw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.33.0", - "@opentelemetry/sql-common": "^0.41.2" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pg": { - "version": "0.66.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.66.0.tgz", - "integrity": "sha512-KxfLGXBb7k2ueaPJfq2GXBDXBly8P+SpR/4Mj410hhNgmQF3sCqwXvUBQxZQkDAmsdBAoenM+yV1LhtsMRamcA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.34.0", - "@opentelemetry/sql-common": "^0.41.2", - "@types/pg": "8.15.6", - "@types/pg-pool": "2.0.7" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@opentelemetry/instrumentation-tedious": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.33.0.tgz", - "integrity": "sha512-Q6WQwAD01MMTub31GlejoiFACYNw26J426wyjvU7by7fDIr2nZXNW4vhTGs7i7F0TnXBO3xN688g1tdUgYwJ5w==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "license": "MIT", "dependencies": { - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/semantic-conventions": "^1.33.0", - "@types/tedious": "^4.0.14" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.1.tgz", - "integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.1.tgz", - "integrity": "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.7.1", - "@opentelemetry/resources": "2.7.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.41.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", - "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/sql-common": { - "version": "0.41.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.41.2.tgz", - "integrity": "sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" - } - }, - "node_modules/@panva/hkdf": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", - "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/@prisma/instrumentation": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-7.6.0.tgz", - "integrity": "sha512-ZPW2gRiwpPzEfgeZgaekhqXrbW+Y2RJKHVqUmlhZhKzRNCcvR6DykzylDrynpArKKRQtLxoZy36fK7U0p3pdgQ==", - "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.207.0" + "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { - "@opentelemetry/api": "^1.8" - } - }, - "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/api-logs": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.207.0.tgz", - "integrity": "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.207.0.tgz", - "integrity": "sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.207.0", - "import-in-the-middle": "^2.0.0", - "require-in-the-middle": "^8.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@prisma/instrumentation/node_modules/import-in-the-middle": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", - "integrity": "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.15.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^2.2.0", - "module-details-from-path": "^1.0.4" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", - "license": "MIT" - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-accessible-icon": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", - "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", "license": "MIT", "dependencies": { - "@radix-ui/react-visually-hidden": "1.2.3" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -2395,21 +3058,20 @@ } } }, - "node_modules/@radix-ui/react-accordion": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", - "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collapsible": "1.1.12", - "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -2426,16 +3088,14 @@ } } }, - "node_modules/@radix-ui/react-alert-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", - "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, @@ -2454,7 +3114,7 @@ } } }, - "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", @@ -2472,278 +3132,40 @@ } } }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-aspect-ratio": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.8.tgz", - "integrity": "sha512-5nZrJTF7gH+e0nZS7/QxFz6tJV4VimhQb1avEgtsJxvvIp5JilL+c58HICsKzPxghdwaDt48hEfPM1au4zGy+w==", + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", - "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-context": "1.1.3", - "@radix-ui/react-primitive": "2.1.4", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", - "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", - "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", - "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context-menu": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", - "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -4281,986 +4703,1699 @@ } } }, - "node_modules/@remirror/core-constants": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", - "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", - "license": "MIT" - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "28.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz", - "integrity": "sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==", + "node_modules/@redocly/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", + "dev": true, "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "fdir": "^6.2.0", - "is-reference": "1.2.1", - "magic-string": "^0.30.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=16.0.0 || 14 >= 14.17" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js-replace": "^1.0.1" }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "node_modules/@redocly/ajv/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT" }, - "node_modules/@rollup/plugin-commonjs/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/@redocly/config": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz", + "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.34.15", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.15.tgz", + "integrity": "sha512-HAwCnNyKcs5XGQqms+9t7OdAPM/5TDstmhF+0i7tdCFato2QKuYIlyWETwkXd8c5zbltr1oB+6y9NTeQLr2d6Q==", + "dev": true, "license": "MIT", + "dependencies": { + "@redocly/ajv": "8.11.2", + "@redocly/config": "0.22.0", + "colorette": "1.4.0", + "https-proxy-agent": "7.0.6", + "js-levenshtein": "1.1.6", + "js-yaml": "4.1.1", + "minimatch": "5.1.9", + "pluralize": "8.0.0", + "yaml-ast-parser": "0.0.43" + }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "node": ">=18.17.0", + "npm": ">=9.5.0" } }, - "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "node_modules/@redocly/openapi-core/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">= 14" } }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" + "balanced-match": "^1.0.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" }, "engines": { - "node": ">=14.0.0" + "node": ">= 14" + } + }, + "node_modules/@redocly/openapi-core/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "engines": { + "node": ">=10" + } + }, + "node_modules/@remirror/core-constants": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", + "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", + "license": "MIT" + }, + "node_modules/@reown/appkit": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.8.19.tgz", + "integrity": "sha512-wB+xatkRbOy0AY1cZxxtcKzzPk3l3CTFulDbaISLVmZI6ZnQrOFuLnYc285zGsC6DB4d6bmwYUh89zcMLa4PvQ==", + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.19", + "@reown/appkit-controllers": "1.8.19", + "@reown/appkit-pay": "1.8.19", + "@reown/appkit-polyfills": "1.8.19", + "@reown/appkit-scaffold-ui": "1.8.19", + "@reown/appkit-ui": "1.8.19", + "@reown/appkit-utils": "1.8.19", + "@reown/appkit-wallet": "1.8.19", + "@walletconnect/universal-provider": "2.23.7", + "bs58": "6.0.0", + "semver": "7.7.2", + "valtio": "2.1.7", + "viem": ">=2.45.0" }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "optionalDependencies": { + "@lit/react": "1.0.8" } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "node_modules/@reown/appkit-common": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.19.tgz", + "integrity": "sha512-z5wDrYjUGY7YbM4b14NHVo54WKZ5++PQtGkcsXhiOP39yAVijubBQD8BfHs/Pu2fSFqnqLIFoCVvIEfNWWccRw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "big.js": "6.2.2", + "dayjs": "1.11.13", + "viem": ">=2.45.0" + } + }, + "node_modules/@reown/appkit-common/node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "license": "MIT" }, - "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "license": "MIT", - "engines": { - "node": ">=12" + "node_modules/@reown/appkit-controllers": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.8.19.tgz", + "integrity": "sha512-JFNT8CfAVit9FJXh596Ye4U8A/oIapW+Y0KQqjB59DXyTCDZbxZDB32rULBQrSkZ6PufTEa239Dil4kABCQKtg==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.19", + "@reown/appkit-wallet": "1.8.19", + "@walletconnect/universal-provider": "2.23.7", + "valtio": "2.1.7", + "viem": ">=2.45.0" + } + }, + "node_modules/@reown/appkit-pay": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-pay/-/appkit-pay-1.8.19.tgz", + "integrity": "sha512-HO/tQT0TbTQO3eONxNNPJAOZAOzUiHvjM0Mty1rFFeRBH68auiqQxQi2YFNMs014gNkRN+cb84VYau7+MCC0fQ==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.19", + "@reown/appkit-controllers": "1.8.19", + "@reown/appkit-ui": "1.8.19", + "@reown/appkit-utils": "1.8.19", + "lit": "3.3.0", + "valtio": "2.1.7" + } + }, + "node_modules/@reown/appkit-polyfills": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.19.tgz", + "integrity": "sha512-PSoetRSuZg7f2YFPzdfs4BayQl51zcGqYr7frwOe6td0XEsspLrrVFn/zk5QFbFHZVsMdfRZ+TTunt84ozRdnQ==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/@reown/appkit-scaffold-ui": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.8.19.tgz", + "integrity": "sha512-Ak767x0VzeDIXb0wbzkl19kx6udw7vkb1EU0SAweG3iKc9BunW87Rfcd48/YimzMZycJaYmlbtfmqQQDYs6Few==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.19", + "@reown/appkit-controllers": "1.8.19", + "@reown/appkit-pay": "1.8.19", + "@reown/appkit-ui": "1.8.19", + "@reown/appkit-utils": "1.8.19", + "@reown/appkit-wallet": "1.8.19", + "lit": "3.3.0" + } + }, + "node_modules/@reown/appkit-ui": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.8.19.tgz", + "integrity": "sha512-fCAwW8yyyC3JcgKLBPvCtYuDGC4H8anO7u4LTaAXGEzdcU5H+IrCgNFSPNK7NuTSmgXm1TnoYxPxRFKNiNwFdA==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@phosphor-icons/webcomponents": "2.1.5", + "@reown/appkit-common": "1.8.19", + "@reown/appkit-controllers": "1.8.19", + "@reown/appkit-wallet": "1.8.19", + "lit": "3.3.0", + "qrcode": "1.5.3" + } + }, + "node_modules/@reown/appkit-utils": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.8.19.tgz", + "integrity": "sha512-VQPgUMTFqoh4UD3EDZSw9wyMkyZsmIVmu8CdQ2FUxIuqYW4fLd0VIpkDeO64MMhSv8b0X8Vd6m4+eGcqSwlUAg==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.19", + "@reown/appkit-controllers": "1.8.19", + "@reown/appkit-polyfills": "1.8.19", + "@reown/appkit-wallet": "1.8.19", + "@wallet-standard/wallet": "1.1.0", + "@walletconnect/logger": "3.0.2", + "@walletconnect/universal-provider": "2.23.7", + "valtio": "2.1.7", + "viem": ">=2.45.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "optionalDependencies": { + "@base-org/account": "2.4.0", + "@safe-global/safe-apps-provider": "0.18.6", + "@safe-global/safe-apps-sdk": "9.1.0" + }, + "peerDependencies": { + "valtio": "2.1.7" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", - "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", - "cpu": [ - "arm" - ], + "node_modules/@reown/appkit-wallet": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.19.tgz", + "integrity": "sha512-NVdIKceUhkXYtsG32925ctmVn0QJFNyDlr+mWheMLCEZ/IUPn+6aA53vTVaSUquhyeFxUXtrCOh3ln6v1tup5w==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.19", + "@reown/appkit-polyfills": "1.8.19", + "@walletconnect/logger": "3.0.2", + "zod": "3.22.4" + } + }, + "node_modules/@reown/appkit-wallet/node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", - "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", - "cpu": [ - "arm64" - ], + "node_modules/@reown/appkit/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@safe-global/safe-apps-provider": { + "version": "0.18.6", + "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.6.tgz", + "integrity": "sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==", "license": "MIT", "optional": true, - "os": [ - "android" - ] + "dependencies": { + "@safe-global/safe-apps-sdk": "^9.1.0", + "events": "^3.3.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", - "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", - "cpu": [ - "arm64" - ], + "node_modules/@safe-global/safe-apps-sdk": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-sdk/-/safe-apps-sdk-9.1.0.tgz", + "integrity": "sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==", "license": "MIT", "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@safe-global/safe-gateway-typescript-sdk": "^3.5.3", + "viem": "^2.1.1" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", - "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", - "cpu": [ - "x64" - ], + "node_modules/@safe-global/safe-gateway-typescript-sdk": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.23.1.tgz", + "integrity": "sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT", "optional": true, - "os": [ - "darwin" - ] + "engines": { + "node": ">=16" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", - "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", - "cpu": [ - "arm64" - ], + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", - "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", - "cpu": [ - "x64" - ], + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", - "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", - "cpu": [ - "arm" - ], + "node_modules/@scure/bip32/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", - "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", - "cpu": [ - "arm" - ], + "node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", - "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", - "cpu": [ - "arm64" - ], + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", - "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", - "cpu": [ - "arm64" - ], + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", - "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", - "cpu": [ - "loong64" - ], + "node_modules/@sinclair/typebox": { + "version": "0.33.22", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.33.22.tgz", + "integrity": "sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ==", "license": "MIT", + "peer": true + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@solana-program/system": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@solana-program/system/-/system-0.10.0.tgz", + "integrity": "sha512-Go+LOEZmqmNlfr+Gjy5ZWAdY5HbYzk2RBewD9QinEU/bBSzpFfzqDRT55JjFRBGJUvMgf3C2vfXEGT4i8DSI4g==", + "license": "Apache-2.0", "optional": true, - "os": [ - "linux" - ] + "peerDependencies": { + "@solana/kit": "^5.0" + } }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", - "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", - "cpu": [ - "loong64" - ], - "license": "MIT", + "node_modules/@solana-program/token": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.9.0.tgz", + "integrity": "sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==", + "license": "Apache-2.0", "optional": true, - "os": [ - "linux" - ] + "peerDependencies": { + "@solana/kit": "^5.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", - "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", - "cpu": [ - "ppc64" - ], + "node_modules/@solana/accounts": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-5.5.1.tgz", + "integrity": "sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-types": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", - "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", - "cpu": [ - "ppc64" - ], + "node_modules/@solana/addresses": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-5.5.1.tgz", + "integrity": "sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@solana/assertions": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/nominal-types": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", - "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", - "cpu": [ - "riscv64" - ], + "node_modules/@solana/assertions": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-5.5.1.tgz", + "integrity": "sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@solana/errors": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", - "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", - "cpu": [ - "riscv64" - ], + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", - "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", - "cpu": [ - "s390x" - ], + "node_modules/@solana/codecs": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-5.5.1.tgz", + "integrity": "sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/options": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", - "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", - "cpu": [ - "x64" - ], + "node_modules/@solana/codecs-core": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-5.5.1.tgz", + "integrity": "sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@solana/errors": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", - "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", - "cpu": [ - "x64" - ], + "node_modules/@solana/codecs-data-structures": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-5.5.1.tgz", + "integrity": "sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==", "license": "MIT", "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@solana/codecs-core": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/errors": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", - "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", - "cpu": [ - "x64" - ], + "node_modules/@solana/codecs-numbers": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-5.5.1.tgz", + "integrity": "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==", "license": "MIT", "optional": true, - "os": [ - "openbsd" - ] + "dependencies": { + "@solana/codecs-core": "5.5.1", + "@solana/errors": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", - "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", - "cpu": [ - "arm64" - ], + "node_modules/@solana/codecs-strings": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-5.5.1.tgz", + "integrity": "sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==", "license": "MIT", "optional": true, - "os": [ - "openharmony" - ] + "dependencies": { + "@solana/codecs-core": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/errors": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "fastestsmallesttextencoderdecoder": { + "optional": true + }, + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", - "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", - "cpu": [ - "arm64" - ], + "node_modules/@solana/errors": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-5.5.1.tgz", + "integrity": "sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==", "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "chalk": "5.6.2", + "commander": "14.0.2" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", - "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", - "cpu": [ - "ia32" - ], + "node_modules/@solana/errors/node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">=20" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", - "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", - "cpu": [ - "x64" - ], + "node_modules/@solana/fast-stable-stringify": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-5.5.1.tgz", + "integrity": "sha512-Ni7s2FN33zTzhTFgRjEbOVFO+UAmK8qi3Iu0/GRFYK4jN696OjKHnboSQH/EacQ+yGqS54bfxf409wU5dsLLCw==", "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", - "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", - "cpu": [ - "x64" - ], + "node_modules/@solana/functional": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-5.5.1.tgz", + "integrity": "sha512-tTHoJcEQq3gQx5qsdsDJ0LEJeFzwNpXD80xApW9o/PPoCNimI3SALkZl+zNW8VnxRrV3l3yYvfHWBKe/X3WG3w==", "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/@sentry-internal/browser-utils": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.53.1.tgz", - "integrity": "sha512-X4d6y8sBMjmNhcDW4eMBU3ASsNIMz8dqaFkhyIMN/dkYr/yZKnbRZPaVuVUGvHKjnlficPpIH0/HK9KBjrYxPw==", + "node_modules/@solana/instruction-plans": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/instruction-plans/-/instruction-plans-5.5.1.tgz", + "integrity": "sha512-7z3CB7YMcFKuVvgcnNY8bY6IsZ8LG61Iytbz7HpNVGX2u1RthOs1tRW8luTzSG1MPL0Ox7afyAVMYeFqSPHnaQ==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry/core": "10.53.1" + "@solana/errors": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry-internal/feedback": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.53.1.tgz", - "integrity": "sha512-vVpTI/aEYN5d9IgZeYJWMqVaN0+iFgidSrYNAsZTh1US5sJUzF/wrl+68KdpmCtFROrN3jiAn1oPSwL5CKvEJA==", + "node_modules/@solana/instructions": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-5.5.1.tgz", + "integrity": "sha512-h0G1CG6S+gUUSt0eo6rOtsaXRBwCq1+Js2a+Ps9Bzk9q7YHNFA75/X0NWugWLgC92waRp66hrjMTiYYnLBoWOQ==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry/core": "10.53.1" + "@solana/codecs-core": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry-internal/replay": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.53.1.tgz", - "integrity": "sha512-wZNzTBYkgGUPWMuUQv7L64+OJmoCnz7GQNiTrTFK6EVAjJXFBCSsPp/nhif0bLhbk8+0g4xz633uOhpXuQbFdw==", + "node_modules/@solana/keys": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-5.5.1.tgz", + "integrity": "sha512-KRD61cL7CRL+b4r/eB9dEoVxIf/2EJ1Pm1DmRYhtSUAJD2dJ5Xw8QFuehobOGm9URqQ7gaQl+Fkc1qvDlsWqKg==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry-internal/browser-utils": "10.53.1", - "@sentry/core": "10.53.1" + "@solana/assertions": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/nominal-types": "5.5.1" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry-internal/replay-canvas": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.53.1.tgz", - "integrity": "sha512-aueLaf/2prExwA76BGU5/bOXCKWqtt6jQXWA6WJQNrmKpPEtZJB4ypnpsou0McXQCF8tur2Y8U0TEkwQP13yJQ==", + "node_modules/@solana/kit": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-5.5.1.tgz", + "integrity": "sha512-irKUGiV2yRoyf+4eGQ/ZeCRxa43yjFEL1DUI5B0DkcfZw3cr0VJtVJnrG8OtVF01vT0OUfYOcUn6zJW5TROHvQ==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry-internal/replay": "10.53.1", - "@sentry/core": "10.53.1" + "@solana/accounts": "5.5.1", + "@solana/addresses": "5.5.1", + "@solana/codecs": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/instruction-plans": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/offchain-messages": "5.5.1", + "@solana/plugin-core": "5.5.1", + "@solana/programs": "5.5.1", + "@solana/rpc": "5.5.1", + "@solana/rpc-api": "5.5.1", + "@solana/rpc-parsed-types": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-subscriptions": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/signers": "5.5.1", + "@solana/sysvars": "5.5.1", + "@solana/transaction-confirmation": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" }, - "engines": { - "node": ">=18" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/babel-plugin-component-annotate": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-5.3.0.tgz", - "integrity": "sha512-p4q8gn8wcFqZGP/s2MnJCAAd8fTikaU6A0mM97RDHQgStcrYiaS0Sc5zUNfb1V+UOLPuvdEdL6MwyxfzjYJQTA==", + "node_modules/@solana/nominal-types": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-5.5.1.tgz", + "integrity": "sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ==", "license": "MIT", + "optional": true, "engines": { - "node": ">= 18" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/browser": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.53.1.tgz", - "integrity": "sha512-zXF373hzUOGzUOrqd8xb1U3LQi5uYC3mwv+z5OMKUUinQlu30tTWBs7ypy6YTchtix9QlYaHWlayUF8vBZ5UjA==", + "node_modules/@solana/offchain-messages": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/offchain-messages/-/offchain-messages-5.5.1.tgz", + "integrity": "sha512-g+xHH95prTU+KujtbOzj8wn+C7ZNoiLhf3hj6nYq3MTyxOXtBEysguc97jJveUZG0K97aIKG6xVUlMutg5yxhw==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry-internal/browser-utils": "10.53.1", - "@sentry-internal/feedback": "10.53.1", - "@sentry-internal/replay": "10.53.1", - "@sentry-internal/replay-canvas": "10.53.1", - "@sentry/core": "10.53.1" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/nominal-types": "5.5.1" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/bundler-plugin-core": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-5.3.0.tgz", - "integrity": "sha512-L5T60sWdAI3qWwdg3Ptwek/0TY59PERrxyqp4XMUkroayQvGd9r5dIW9Q1kSeXX9iJ442nXbFZKAOyCKV4Z13Q==", + "node_modules/@solana/options": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-5.5.1.tgz", + "integrity": "sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==", "license": "MIT", + "optional": true, "dependencies": { - "@babel/core": "^7.18.5", - "@sentry/babel-plugin-component-annotate": "5.3.0", - "@sentry/cli": "^2.58.5", - "dotenv": "^16.3.1", - "find-up": "^5.0.0", - "glob": "^13.0.6", - "magic-string": "~0.30.8" + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1" }, "engines": { - "node": ">= 18" - } - }, - "node_modules/@sentry/cli": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.58.6.tgz", - "integrity": "sha512-baBcNPLLfUi9WuL+Tpri9BFaAdvugZIKelC5X0tt0Zdy+K0K+PCVSrnNmwMWU/HyaF/SEv6b6UHnXIdqanBlcg==", - "hasInstallScript": true, - "license": "FSL-1.1-MIT", - "dependencies": { - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.7", - "progress": "^2.0.3", - "proxy-from-env": "^1.1.0", - "which": "^2.0.2" - }, - "bin": { - "sentry-cli": "bin/sentry-cli" + "node": ">=20.18.0" }, - "engines": { - "node": ">= 10" + "peerDependencies": { + "typescript": "^5.0.0" }, - "optionalDependencies": { - "@sentry/cli-darwin": "2.58.6", - "@sentry/cli-linux-arm": "2.58.6", - "@sentry/cli-linux-arm64": "2.58.6", - "@sentry/cli-linux-i686": "2.58.6", - "@sentry/cli-linux-x64": "2.58.6", - "@sentry/cli-win32-arm64": "2.58.6", - "@sentry/cli-win32-i686": "2.58.6", - "@sentry/cli-win32-x64": "2.58.6" - } - }, - "node_modules/@sentry/cli-darwin": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.58.6.tgz", - "integrity": "sha512-udAVvcyfNa0R+95GvPz/+43/N3TC0TYKdkQ7D7jhPSzbcMc7l2fxRNN5yB3UpCA5fWFnW4toeaqwDBhb/Wh3LA==", - "license": "FSL-1.1-MIT", + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/plugin-core": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/plugin-core/-/plugin-core-5.5.1.tgz", + "integrity": "sha512-VUZl30lDQFJeiSyNfzU1EjYt2QZvoBFKEwjn1lilUJw7KgqD5z7mbV7diJhT+dLFs36i0OsjXvq5kSygn8YJ3A==", + "license": "MIT", "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/cli-linux-arm": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.58.6.tgz", - "integrity": "sha512-pD0LAt5PcUzAinBwvDqc66x9+2CabHEv486yP0gRjWO7SakbaxmfVq/EXd8VLq/Tzi39LAu422UYK1lpW3MILw==", - "cpu": [ - "arm" - ], - "license": "FSL-1.1-MIT", + "node_modules/@solana/programs": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-5.5.1.tgz", + "integrity": "sha512-7U9kn0Jsx1NuBLn5HRTFYh78MV4XN145Yc3WP/q5BlqAVNlMoU9coG5IUTJIG847TUqC1lRto3Dnpwm6T4YRpA==", + "license": "MIT", "optional": true, - "os": [ - "linux", - "freebsd", - "android" - ], + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/errors": "5.5.1" + }, "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/cli-linux-arm64": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.58.6.tgz", - "integrity": "sha512-q8mEcNNmeXMy5i+jWT30TVpH7LcP4HD21CD5XRSPAd/a912HF6EpK0ybf/1USO14WOhoXbAGi9txwaWabSe33g==", - "cpu": [ - "arm64" - ], - "license": "FSL-1.1-MIT", + "node_modules/@solana/promises": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-5.5.1.tgz", + "integrity": "sha512-T9lfuUYkGykJmppEcssNiCf6yiYQxJkhiLPP+pyAc2z84/7r3UVIb2tNJk4A9sucS66pzJnVHZKcZVGUUp6wzA==", + "license": "MIT", "optional": true, - "os": [ - "linux", - "freebsd", - "android" - ], "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/cli-linux-i686": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.58.6.tgz", - "integrity": "sha512-q8vNJi1eOV/4vxAFWBsEwLHoSYapaZHIf4j76KJGJXFKTkEbsjCOOsKbwUIBTQQhRgV4DFWh3ryfsPS/que4Kg==", - "cpu": [ - "x86", - "ia32" - ], - "license": "FSL-1.1-MIT", + "node_modules/@solana/rpc": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-5.5.1.tgz", + "integrity": "sha512-ku8zTUMrkCWci66PRIBC+1mXepEnZH/q1f3ck0kJZ95a06bOTl5KU7HeXWtskkyefzARJ5zvCs54AD5nxjQJ+A==", + "license": "MIT", "optional": true, - "os": [ - "linux", - "freebsd", - "android" - ], + "dependencies": { + "@solana/errors": "5.5.1", + "@solana/fast-stable-stringify": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/rpc-api": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-transport-http": "5.5.1", + "@solana/rpc-types": "5.5.1" + }, "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/cli-linux-x64": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.58.6.tgz", - "integrity": "sha512-DZu956Mhi3ZRjTBe1WdbGV46ldVbA8d2rgp/fh51GsI25zjBHah4wZnPTSzpc+YqxU6pJpg579B/r3jrIK530Q==", - "cpu": [ - "x64" - ], - "license": "FSL-1.1-MIT", + "node_modules/@solana/rpc-api": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-5.5.1.tgz", + "integrity": "sha512-XWOQQPhKl06Vj0xi3RYHAc6oEQd8B82okYJ04K7N0Vvy3J4PN2cxeK7klwkjgavdcN9EVkYCChm2ADAtnztKnA==", + "license": "MIT", "optional": true, - "os": [ - "linux", - "freebsd", - "android" - ], + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/rpc-parsed-types": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" + }, "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/cli-win32-arm64": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.58.6.tgz", - "integrity": "sha512-nj0Ff/kmAB73EPDhR8B4O9r+NUHK5GkPCkGWC+kXVemqAJWL5jcJ5KdxG0l/S0z6RoEoltID8/43/B+TaMlT7A==", - "cpu": [ - "arm64" - ], - "license": "FSL-1.1-MIT", + "node_modules/@solana/rpc-parsed-types": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-5.5.1.tgz", + "integrity": "sha512-HEi3G2nZqGEsa3vX6U0FrXLaqnUCg4SKIUrOe8CezD+cSFbRTOn3rCLrUmJrhVyXlHoQVaRO9mmeovk31jWxJg==", + "license": "MIT", "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/cli-win32-i686": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.58.6.tgz", - "integrity": "sha512-WNZiDzPbgsEMQWq4avsQ391v/xWKJDIWWWo9GYl+N/w5qcYKkoDW7wQG7T9FasI6ENn68phChTOAPXXxbfAdOg==", - "cpu": [ - "x86", - "ia32" - ], - "license": "FSL-1.1-MIT", + "node_modules/@solana/rpc-spec": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-5.5.1.tgz", + "integrity": "sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q==", + "license": "MIT", "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@solana/errors": "5.5.1", + "@solana/rpc-spec-types": "5.5.1" + }, "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/cli-win32-x64": { - "version": "2.58.6", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.58.6.tgz", - "integrity": "sha512-R35WJ17oF4D2eqI1DR2sQQqr0fjRTt5xoP16WrTu91XM2lndRMFsnjh+/GttbxapLCBNlrjzia99MJ0PZHZpgA==", - "cpu": [ - "x64" - ], - "license": "FSL-1.1-MIT", + "node_modules/@solana/rpc-spec-types": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-5.5.1.tgz", + "integrity": "sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw==", + "license": "MIT", "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=10" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/core": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.53.1.tgz", - "integrity": "sha512-XG4ezlkyuAPjBC5+9kXC94rXXuqYTw9NRhfaDHssbTFaGnqBR8vQX2UUgZfY7ucbeelRDGfBu1sywoU+mB04uA==", + "node_modules/@solana/rpc-subscriptions": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-5.5.1.tgz", + "integrity": "sha512-CTMy5bt/6mDh4tc6vUJms9EcuZj3xvK0/xq8IQ90rhkpYvate91RjBP+egvjgSayUg9yucU9vNuUpEjz4spM7w==", "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "5.5.1", + "@solana/fast-stable-stringify": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-subscriptions-api": "5.5.1", + "@solana/rpc-subscriptions-channel-websocket": "5.5.1", + "@solana/rpc-subscriptions-spec": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/subscribable": "5.5.1" + }, "engines": { - "node": ">=18" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/nextjs": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/nextjs/-/nextjs-10.53.1.tgz", - "integrity": "sha512-pkwqrpAG//LtW5W1Odud0PLLT+rnjDjodUEbScULHVaZE6/Gt+WGBMZmtzpNM+UwhsN19/4PyO7ocLTx/IFrkQ==", + "node_modules/@solana/rpc-subscriptions-api": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-5.5.1.tgz", + "integrity": "sha512-5Oi7k+GdeS8xR2ly1iuSFkAv6CZqwG0Z6b1QZKbEgxadE1XGSDrhM2cn59l+bqCozUWCqh4c/A2znU/qQjROlw==", "license": "MIT", + "optional": true, "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/semantic-conventions": "^1.40.0", - "@rollup/plugin-commonjs": "28.0.1", - "@sentry-internal/browser-utils": "10.53.1", - "@sentry/bundler-plugin-core": "^5.3.0", - "@sentry/core": "10.53.1", - "@sentry/node": "10.53.1", - "@sentry/opentelemetry": "10.53.1", - "@sentry/react": "10.53.1", - "@sentry/vercel-edge": "10.53.1", - "@sentry/webpack-plugin": "^5.3.0", - "rollup": "^4.60.3", - "stacktrace-parser": "^0.1.11" + "@solana/addresses": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/rpc-subscriptions-spec": "5.5.1", + "@solana/rpc-transformers": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" }, "peerDependencies": { - "next": "^13.2.0 || ^14.0 || ^15.0.0-rc.0 || ^16.0.0-0" - } - }, - "node_modules/@sentry/node": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.53.1.tgz", - "integrity": "sha512-rxHVil0tJAmz+keFcZCj1LaUdgdkK66E/l0gqh2p1209PNCGoD3lnClFr6vusy1aF3zF8O9JPtuMEJzXOKhs+w==", - "license": "MIT", - "dependencies": { - "@fastify/otel": "0.18.0", - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/core": "^2.6.1", - "@opentelemetry/instrumentation": "^0.214.0", - "@opentelemetry/instrumentation-amqplib": "0.61.0", - "@opentelemetry/instrumentation-connect": "0.57.0", - "@opentelemetry/instrumentation-dataloader": "0.31.0", - "@opentelemetry/instrumentation-fs": "0.33.0", - "@opentelemetry/instrumentation-generic-pool": "0.57.0", - "@opentelemetry/instrumentation-graphql": "0.62.0", - "@opentelemetry/instrumentation-hapi": "0.60.0", - "@opentelemetry/instrumentation-http": "0.214.0", - "@opentelemetry/instrumentation-kafkajs": "0.23.0", - "@opentelemetry/instrumentation-knex": "0.58.0", - "@opentelemetry/instrumentation-koa": "0.62.0", - "@opentelemetry/instrumentation-lru-memoizer": "0.58.0", - "@opentelemetry/instrumentation-mongodb": "0.67.0", - "@opentelemetry/instrumentation-mongoose": "0.60.0", - "@opentelemetry/instrumentation-mysql": "0.60.0", - "@opentelemetry/instrumentation-mysql2": "0.60.0", - "@opentelemetry/instrumentation-pg": "0.66.0", - "@opentelemetry/instrumentation-tedious": "0.33.0", - "@opentelemetry/sdk-trace-base": "^2.6.1", - "@opentelemetry/semantic-conventions": "^1.40.0", - "@prisma/instrumentation": "7.6.0", - "@sentry/core": "10.53.1", - "@sentry/node-core": "10.53.1", - "@sentry/opentelemetry": "10.53.1", - "import-in-the-middle": "^3.0.0" + "typescript": "^5.0.0" }, - "engines": { - "node": ">=18" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/node-core": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.53.1.tgz", - "integrity": "sha512-iH7SMcM/7jPbN+t7+7ussQOiIqI4BMOGt4VYWlV71/z7k0pY+YPaSvlfVkNXfISiDzFAKv0ecCY3BmsLMu1xDQ==", + "node_modules/@solana/rpc-subscriptions-channel-websocket": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-5.5.1.tgz", + "integrity": "sha512-7tGfBBrYY8TrngOyxSHoCU5shy86iA9SRMRrPSyBhEaZRAk6dnbdpmUTez7gtdVo0BCvh9nzQtUycKWSS7PnFQ==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry/core": "10.53.1", - "@sentry/opentelemetry": "10.53.1", - "import-in-the-middle": "^3.0.0" + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/rpc-subscriptions-spec": "5.5.1", + "@solana/subscribable": "5.5.1", + "ws": "^8.19.0" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", - "@opentelemetry/instrumentation": ">=0.57.1 <1", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", - "@opentelemetry/semantic-conventions": "^1.39.0" + "typescript": "^5.0.0" }, "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@opentelemetry/core": { - "optional": true - }, - "@opentelemetry/exporter-trace-otlp-http": { - "optional": true - }, - "@opentelemetry/instrumentation": { - "optional": true - }, - "@opentelemetry/sdk-trace-base": { - "optional": true - }, - "@opentelemetry/semantic-conventions": { + "typescript": { "optional": true } } }, - "node_modules/@sentry/opentelemetry": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.53.1.tgz", - "integrity": "sha512-Zok6UXla0mFOjd1YnVb1TZtQNOry9v93fXUqx8jmDaygwWM2BwvP8rBQabLz0/OZXo8+35oge+Vmw+QY5aesnA==", + "node_modules/@solana/rpc-subscriptions-spec": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-5.5.1.tgz", + "integrity": "sha512-iq+rGq5fMKP3/mKHPNB6MC8IbVW41KGZg83Us/+LE3AWOTWV1WT20KT2iH1F1ik9roi42COv/TpoZZvhKj45XQ==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry/core": "10.53.1" + "@solana/errors": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/subscribable": "5.5.1" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", - "@opentelemetry/semantic-conventions": "^1.39.0" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/react": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.53.1.tgz", - "integrity": "sha512-lrwNq5T/zW84l60894TpKHPcvFuc1I/Hnohecc0TfYVpIcYYuw2orCHoU4v4wgkFaJUpegVetbgdOphViyLVjA==", + "node_modules/@solana/rpc-transformers": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-5.5.1.tgz", + "integrity": "sha512-OsWqLCQdcrRJKvHiMmwFhp9noNZ4FARuMkHT5us3ustDLXaxOjF0gfqZLnMkulSLcKt7TGXqMhBV+HCo7z5M8Q==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry/browser": "10.53.1", - "@sentry/core": "10.53.1" + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "@solana/rpc-types": "5.5.1" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" }, "peerDependencies": { - "react": "^16.14.0 || 17.x || 18.x || 19.x" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/vercel-edge": { - "version": "10.53.1", - "resolved": "https://registry.npmjs.org/@sentry/vercel-edge/-/vercel-edge-10.53.1.tgz", - "integrity": "sha512-waIOoLfhi1V3xEBJ1s1hpmvvgvcorYfsfm7fQGye0PgVjcBsZUqz32N5iEwkZ2Gz3n4ZOQYibDUqARJi9tOBcw==", + "node_modules/@solana/rpc-transport-http": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-5.5.1.tgz", + "integrity": "sha512-yv8GoVSHqEV0kUJEIhkdOVkR2SvJ6yoWC51cJn2rSV7plr6huLGe0JgujCmB7uZhhaLbcbP3zxXxu9sOjsi7Fg==", "license": "MIT", + "optional": true, "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/resources": "^2.6.1", - "@sentry/core": "10.53.1" + "@solana/errors": "5.5.1", + "@solana/rpc-spec": "5.5.1", + "@solana/rpc-spec-types": "5.5.1", + "undici-types": "^7.19.2" }, "engines": { - "node": ">=18" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sentry/webpack-plugin": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-5.3.0.tgz", - "integrity": "sha512-i3OQUrS0FZlXLgq57RIKDp+vHHzuvYKPCKewAPXULWKMsBXFGhP6veGRQ+6To/pmZkkXjEX5ofVNDy9C3jEPKQ==", + "node_modules/@solana/rpc-types": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-5.5.1.tgz", + "integrity": "sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA==", "license": "MIT", + "optional": true, "dependencies": { - "@sentry/bundler-plugin-core": "5.3.0" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/nominal-types": "5.5.1" }, "engines": { - "node": ">= 18" + "node": ">=20.18.0" }, "peerDependencies": { - "webpack": ">=5.0.0" - } - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "license": "MIT" - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@standard-schema/utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", - "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", - "license": "MIT" - }, - "node_modules/@stellar/freighter-api": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-4.1.0.tgz", - "integrity": "sha512-5iaENUG8AoSlBr771XVou4wjYxfcl+SRyFZydwwGEuHm1XGDu/HLXFifXbRFoU14/5rZYouycnv1uJCuFIeBxg==", - "license": "Apache-2.0", - "dependencies": { - "buffer": "^6.0.3", - "semver": "^7.6.3" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stellar/js-xdr": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", - "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==", - "license": "Apache-2.0" - }, - "node_modules/@stellar/stellar-sdk": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-13.3.0.tgz", - "integrity": "sha512-8+GHcZLp+mdin8gSjcgfb/Lb6sSMYRX6Nf/0LcSJxvjLQR0XHpjGzOiRbYb2jSXo51EnA6kAV5j+4Pzh5OUKUg==", - "license": "Apache-2.0", + "node_modules/@solana/signers": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-5.5.1.tgz", + "integrity": "sha512-FY0IVaBT2kCAze55vEieR6hag4coqcuJ31Aw3hqRH7mv6sV8oqwuJmUrx+uFwOp1gwd5OEAzlv6N4hOOple4sQ==", + "license": "MIT", + "optional": true, "dependencies": { - "@stellar/stellar-base": "^13.1.0", - "axios": "^1.8.4", - "bignumber.js": "^9.3.0", - "eventsource": "^2.0.2", - "feaxios": "^0.0.23", - "randombytes": "^2.1.0", - "toml": "^3.0.0", - "urijs": "^1.19.1" + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/offchain-messages": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stellar/stellar-sdk/node_modules/@stellar/stellar-base": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-13.1.0.tgz", - "integrity": "sha512-90EArG+eCCEzDGj3OJNoCtwpWDwxjv+rs/RNPhvg4bulpjN/CSRj+Ys/SalRcfM4/WRC5/qAfjzmJBAuquWhkA==", - "license": "Apache-2.0", + "node_modules/@solana/subscribable": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-5.5.1.tgz", + "integrity": "sha512-9K0PsynFq0CsmK1CDi5Y2vUIJpCqkgSS5yfDN0eKPgHqEptLEaia09Kaxc90cSZDZU5mKY/zv1NBmB6Aro9zQQ==", + "license": "MIT", + "optional": true, "dependencies": { - "@stellar/js-xdr": "^3.1.2", - "base32.js": "^0.1.0", - "bignumber.js": "^9.1.2", - "buffer": "^6.0.3", - "sha.js": "^2.3.6", - "tweetnacl": "^1.0.3" + "@solana/errors": "5.5.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.18.0" }, - "optionalDependencies": { - "sodium-native": "^4.3.3" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@tabler/icons": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.36.1.tgz", - "integrity": "sha512-f4Jg3Fof/Vru5ioix/UO4GX+sdDsF9wQo47FbtvG+utIYYVQ/QVAC0QYgcBbAjQGfbdOh2CCf0BgiFOF9Ixtjw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/codecalm" + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@tabler/icons-react": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.36.1.tgz", - "integrity": "sha512-/8nOXeNeMoze9xY/QyEKG65wuvRhkT3q9aytaur6Gj8bYU2A98YVJyLc9MRmc5nVvpy+bRlrrwK/Ykr8WGyUWg==", + "node_modules/@solana/sysvars": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-5.5.1.tgz", + "integrity": "sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA==", "license": "MIT", + "optional": true, "dependencies": { - "@tabler/icons": "" + "@solana/accounts": "5.5.1", + "@solana/codecs": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/rpc-types": "5.5.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/codecalm" + "engines": { + "node": ">=20.18.0" }, "peerDependencies": { - "react": ">= 16" + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@tailwindcss/node": { + "node_modules/@solana/transaction-confirmation": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-5.5.1.tgz", + "integrity": "sha512-j4mKlYPHEyu+OD7MBt3jRoX4ScFgkhZC6H65on4Fux6LMScgivPJlwnKoZMnsgxFgWds0pl+BYzSiALDsXlYtw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/promises": "5.5.1", + "@solana/rpc": "5.5.1", + "@solana/rpc-subscriptions": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1", + "@solana/transactions": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/transaction-messages": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-5.5.1.tgz", + "integrity": "sha512-aXyhMCEaAp3M/4fP0akwBBQkFPr4pfwoC5CLDq999r/FUwDax2RE/h4Ic7h2Xk+JdcUwsb+rLq85Y52hq84XvQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/rpc-types": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/transactions": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-5.5.1.tgz", + "integrity": "sha512-8hHtDxtqalZ157pnx6p8k10D7J/KY/biLzfgh9R09VNLLY3Fqi7kJvJCr7M2ik3oRll56pxhraAGCC9yIT6eOA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "5.5.1", + "@solana/codecs-core": "5.5.1", + "@solana/codecs-data-structures": "5.5.1", + "@solana/codecs-numbers": "5.5.1", + "@solana/codecs-strings": "5.5.1", + "@solana/errors": "5.5.1", + "@solana/functional": "5.5.1", + "@solana/instructions": "5.5.1", + "@solana/keys": "5.5.1", + "@solana/nominal-types": "5.5.1", + "@solana/rpc-types": "5.5.1", + "@solana/transaction-messages": "5.5.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/wallet-adapter-base": { + "version": "0.9.27", + "resolved": "https://registry.npmjs.org/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.27.tgz", + "integrity": "sha512-kXjeNfNFVs/NE9GPmysBRKQ/nf+foSaq3kfVSeMcO/iVgigyRmB551OjU3WyAolLG/1jeEfKLqF9fKwMCRkUqg==", + "license": "Apache-2.0", + "dependencies": { + "@solana/wallet-standard-features": "^1.3.0", + "@wallet-standard/base": "^1.1.0", + "@wallet-standard/features": "^1.1.0", + "eventemitter3": "^5.0.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@solana/web3.js": "^1.98.0" + } + }, + "node_modules/@solana/wallet-standard-features": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-features/-/wallet-standard-features-1.3.0.tgz", + "integrity": "sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0", + "@wallet-standard/features": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@solana/web3.js/node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@stellar/freighter-api": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-4.1.0.tgz", + "integrity": "sha512-5iaENUG8AoSlBr771XVou4wjYxfcl+SRyFZydwwGEuHm1XGDu/HLXFifXbRFoU14/5rZYouycnv1uJCuFIeBxg==", + "license": "Apache-2.0", + "dependencies": { + "buffer": "^6.0.3", + "semver": "^7.6.3" + } + }, + "node_modules/@stellar/js-xdr": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", + "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==", + "license": "Apache-2.0" + }, + "node_modules/@stellar/stellar-base": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.0.1.tgz", + "integrity": "sha512-mI6Kjh9hGWDA1APawQTtCbR7702dNT/8Te1uuRFPqqdoAKBk3WpXOQI3ZSZO+5olW7BSHpmVG5KBPZpIpQxIvw==", + "license": "Apache-2.0", + "dependencies": { + "@noble/curves": "^1.9.6", + "@stellar/js-xdr": "^3.1.2", + "base32.js": "^0.1.0", + "bignumber.js": "^9.3.1", + "buffer": "^6.0.3", + "sha.js": "^2.4.12" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@stellar/stellar-base/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@stellar/stellar-base/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@stellar/stellar-sdk": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-13.3.0.tgz", + "integrity": "sha512-8+GHcZLp+mdin8gSjcgfb/Lb6sSMYRX6Nf/0LcSJxvjLQR0XHpjGzOiRbYb2jSXo51EnA6kAV5j+4Pzh5OUKUg==", + "license": "Apache-2.0", + "dependencies": { + "@stellar/stellar-base": "^13.1.0", + "axios": "^1.8.4", + "bignumber.js": "^9.3.0", + "eventsource": "^2.0.2", + "feaxios": "^0.0.23", + "randombytes": "^2.1.0", + "toml": "^3.0.0", + "urijs": "^1.19.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@stellar/stellar-sdk/node_modules/@stellar/stellar-base": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-13.1.0.tgz", + "integrity": "sha512-90EArG+eCCEzDGj3OJNoCtwpWDwxjv+rs/RNPhvg4bulpjN/CSRj+Ys/SalRcfM4/WRC5/qAfjzmJBAuquWhkA==", + "license": "Apache-2.0", + "dependencies": { + "@stellar/js-xdr": "^3.1.2", + "base32.js": "^0.1.0", + "bignumber.js": "^9.1.2", + "buffer": "^6.0.3", + "sha.js": "^2.3.6", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "sodium-native": "^4.3.3" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tabler/icons": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.36.1.tgz", + "integrity": "sha512-f4Jg3Fof/Vru5ioix/UO4GX+sdDsF9wQo47FbtvG+utIYYVQ/QVAC0QYgcBbAjQGfbdOh2CCf0BgiFOF9Ixtjw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.36.1.tgz", + "integrity": "sha512-/8nOXeNeMoze9xY/QyEKG65wuvRhkT3q9aytaur6Gj8bYU2A98YVJyLc9MRmc5nVvpy+bRlrrwK/Ykr8WGyUWg==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, + "node_modules/@tailwindcss/node": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", @@ -6115,1238 +7250,3915 @@ "url": "https://github.com/sponsors/ueberdosis" } }, - "node_modules/@trustless-work/escrow": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@trustless-work/escrow/-/escrow-3.0.5.tgz", - "integrity": "sha512-IFvu/4K5rYJzucQvIfiAVSdt8QeBjHLDiWcxlmKCQN36gJ8906QMBssSyug/BuBA1ShGTWk1Yn9BfcPUSEQhhw==", - "license": "MIT", + "node_modules/@trezor/analytics": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@trezor/analytics/-/analytics-1.5.0.tgz", + "integrity": "sha512-evILW5XJEmfPlf0TY1duOLtGJ47pdGeSKVE3P75ODEUsRNxtPVqlkOUBPmYpCxPnzS8XDmkatT8lf9/DF0G6nA==", + "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { - "axios": "^1.9.0" + "@trezor/env-utils": "1.5.0", + "@trezor/utils": "9.5.0" }, "peerDependencies": { - "react": ">=18.0.0 <20.0.0", - "react-dom": ">=18.0.0 <20.0.0" + "tslib": "^2.6.2" } }, - "node_modules/@tweenjs/tween.js": { - "version": "23.1.3", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", - "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", - "license": "MIT" - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "license": "MIT", + "node_modules/@trezor/blockchain-link": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@trezor/blockchain-link/-/blockchain-link-2.6.2.tgz", + "integrity": "sha512-HMz+Dm6nMflqRkaebMqpv3uNnVkRrb6lD2HKTHNBGhjVbqf0wRzJ8JoQ08wn/sF00ljJZz8pGnpcMYHJNxE+wQ==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "dependencies": { - "@types/node": "*" + "@solana-program/compute-budget": "^0.8.0", + "@solana-program/stake": "^0.2.1", + "@solana-program/token": "^0.5.1", + "@solana-program/token-2022": "^0.4.2", + "@solana/kit": "^2.3.0", + "@solana/rpc-types": "^2.3.0", + "@stellar/stellar-sdk": "14.2.0", + "@trezor/blockchain-link-types": "1.5.1", + "@trezor/blockchain-link-utils": "1.5.2", + "@trezor/env-utils": "1.5.0", + "@trezor/utils": "9.5.0", + "@trezor/utxo-lib": "2.5.0", + "@trezor/websocket-client": "1.3.0", + "@types/web": "^0.0.197", + "crypto-browserify": "3.12.0", + "socks-proxy-agent": "8.0.5", + "stream-browserify": "^3.0.0", + "xrpl": "4.4.3" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/blockchain-link-types": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-types/-/blockchain-link-types-1.5.1.tgz", + "integrity": "sha512-Idavz6LwLBW8sXc69fh5AJEnl666EDl2Nt3io7updvBgOR0/P12I900DgjNhCKtiWuv66A33/5RE7zLcj3lfnw==", + "license": "See LICENSE.md in repo root", + "peer": true, + "dependencies": { + "@trezor/utils": "9.5.0", + "@trezor/utxo-lib": "2.5.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" } }, - "node_modules/@types/d3": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", - "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", - "license": "MIT", + "node_modules/@trezor/blockchain-link-utils": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-utils/-/blockchain-link-utils-1.5.2.tgz", + "integrity": "sha512-OSS5OEE98FMnYfjoEALPjBt7ebjC/FKnq3HOolHdEWXBpVlXZNN2+Vo1R9J6WbZUU087sHuUTJJy/GJYWY13Tg==", + "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { - "@types/d3-array": "*", - "@types/d3-axis": "*", - "@types/d3-brush": "*", - "@types/d3-chord": "*", - "@types/d3-color": "*", - "@types/d3-contour": "*", - "@types/d3-delaunay": "*", - "@types/d3-dispatch": "*", - "@types/d3-drag": "*", - "@types/d3-dsv": "*", - "@types/d3-ease": "*", - "@types/d3-fetch": "*", - "@types/d3-force": "*", - "@types/d3-format": "*", - "@types/d3-geo": "*", - "@types/d3-hierarchy": "*", - "@types/d3-interpolate": "*", - "@types/d3-path": "*", - "@types/d3-polygon": "*", - "@types/d3-quadtree": "*", - "@types/d3-random": "*", - "@types/d3-scale": "*", - "@types/d3-scale-chromatic": "*", - "@types/d3-selection": "*", - "@types/d3-shape": "*", - "@types/d3-time": "*", - "@types/d3-time-format": "*", - "@types/d3-timer": "*", - "@types/d3-transition": "*", - "@types/d3-zoom": "*" + "@mobily/ts-belt": "^3.13.1", + "@stellar/stellar-sdk": "14.2.0", + "@trezor/env-utils": "1.5.0", + "@trezor/protobuf": "1.5.2", + "@trezor/utils": "9.5.0", + "xrpl": "4.4.3" + }, + "peerDependencies": { + "tslib": "^2.6.2" } }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "license": "MIT" - }, - "node_modules/@types/d3-axis": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", - "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", - "license": "MIT", + "node_modules/@trezor/blockchain-link-utils/node_modules/@stellar/stellar-sdk": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-14.2.0.tgz", + "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@types/d3-selection": "*" + "@stellar/stellar-base": "^14.0.1", + "axios": "^1.12.2", + "bignumber.js": "^9.3.1", + "eventsource": "^2.0.2", + "feaxios": "^0.0.23", + "randombytes": "^2.1.0", + "toml": "^3.0.0", + "urijs": "^1.19.1" + }, + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@types/d3-brush": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", - "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", - "license": "MIT", + "node_modules/@trezor/blockchain-link-utils/node_modules/@trezor/protobuf": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.2.tgz", + "integrity": "sha512-zViaL1jKue8DUTVEDg0C/lMipqNMd/Z3kr29/+MeZOoupjaXIQ2Lqp3WAMe8hvNTKKX8aNQH9JrbapJ6w9FMXw==", + "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { - "@types/d3-selection": "*" + "@trezor/schema-utils": "1.4.0", + "long": "5.2.5", + "protobufjs": "7.4.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" } }, - "node_modules/@types/d3-chord": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", - "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" - }, - "node_modules/@types/d3-contour": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", - "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", - "license": "MIT", + "node_modules/@trezor/blockchain-link-utils/node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "peer": true, "dependencies": { - "@types/d3-array": "*", - "@types/geojson": "*" + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" } }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", - "license": "MIT" - }, - "node_modules/@types/d3-dispatch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", - "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana-program/compute-budget": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.8.0.tgz", + "integrity": "sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0" + } }, - "node_modules/@types/d3-drag": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", - "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "node_modules/@trezor/blockchain-link/node_modules/@solana-program/stake": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@solana-program/stake/-/stake-0.2.1.tgz", + "integrity": "sha512-ssNPsJv9XHaA+L7ihzmWGYcm/+XYURQ8UA3wQMKf6ccEHyHOUgoglkkDU/BoA0+wul6HxZUN0tHFymC0qFw6sg==", "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0" } }, - "node_modules/@types/d3-dsv": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana-program/token": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.5.1.tgz", + "integrity": "sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0" + } }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana-program/token-2022": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.4.2.tgz", + "integrity": "sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0", + "@solana/sysvars": "^2.1.0" + } }, - "node_modules/@types/d3-fetch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", - "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/accounts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-2.3.0.tgz", + "integrity": "sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==", "license": "MIT", + "peer": true, "dependencies": { - "@types/d3-dsv": "*" + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/d3-force": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", - "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", - "license": "MIT" - }, - "node_modules/@types/d3-format": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", - "license": "MIT" - }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/addresses": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-2.3.0.tgz", + "integrity": "sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==", "license": "MIT", + "peer": true, "dependencies": { - "@types/geojson": "*" + "@solana/assertions": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/nominal-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/d3-hierarchy": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", - "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/assertions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-2.3.0.tgz", + "integrity": "sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==", "license": "MIT", + "peer": true, "dependencies": { - "@types/d3-color": "*" + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-polygon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", - "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", - "license": "MIT" - }, - "node_modules/@types/d3-quadtree": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", - "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", - "license": "MIT" - }, - "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.3.0.tgz", + "integrity": "sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==", "license": "MIT", + "peer": true, "dependencies": { - "@types/d3-time": "*" + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/options": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", - "license": "MIT" - }, - "node_modules/@types/d3-selection": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", - "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", - "license": "MIT" - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", "license": "MIT", + "peer": true, "dependencies": { - "@types/d3-path": "*" + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" - }, - "node_modules/@types/d3-time-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" - }, - "node_modules/@types/d3-transition": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", - "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-data-structures": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.3.0.tgz", + "integrity": "sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==", "license": "MIT", + "peer": true, "dependencies": { - "@types/d3-selection": "*" + "@solana/codecs-core": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/d3-zoom": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", "license": "MIT", + "peer": true, "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-strings": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.3.0.tgz", + "integrity": "sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==", "license": "MIT", + "peer": true, "dependencies": { - "@types/ms": "*" + "@solana/codecs-core": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5.3.3" } }, - "node_modules/@types/draco3d": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", - "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", - "license": "MIT" - }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, + "node_modules/@trezor/blockchain-link/node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", "license": "MIT", - "optional": true, "peer": true, "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/fast-stable-stringify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-2.3.0.tgz", + "integrity": "sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==", "license": "MIT", - "dependencies": { - "@types/estree": "*" + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/functional": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-2.3.0.tgz", + "integrity": "sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==", "license": "MIT", - "dependencies": { - "@types/unist": "*" + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/js-cookie": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", - "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT" - }, - "node_modules/@types/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", - "license": "MIT" - }, - "node_modules/@types/lodash.debounce": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.9.tgz", - "integrity": "sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/instructions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-2.3.0.tgz", + "integrity": "sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==", "license": "MIT", + "peer": true, "dependencies": { - "@types/lodash": "*" + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/markdown-it": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", - "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/keys": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-2.3.0.tgz", + "integrity": "sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==", "license": "MIT", + "peer": true, "dependencies": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" + "@solana/assertions": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/nominal-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/marked": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.2.tgz", - "integrity": "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg==", - "license": "MIT" - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/kit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-2.3.0.tgz", + "integrity": "sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ==", "license": "MIT", + "peer": true, "dependencies": { - "@types/unist": "*" + "@solana/accounts": "2.3.0", + "@solana/addresses": "2.3.0", + "@solana/codecs": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/programs": "2.3.0", + "@solana/rpc": "2.3.0", + "@solana/rpc-parsed-types": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-subscriptions": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/signers": "2.3.0", + "@solana/sysvars": "2.3.0", + "@solana/transaction-confirmation": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "license": "MIT" - }, - "node_modules/@types/mdx": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", - "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana/nominal-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-2.3.0.tgz", + "integrity": "sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } }, - "node_modules/@types/mysql": { - "version": "2.15.27", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.27.tgz", - "integrity": "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/options": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.3.0.tgz", + "integrity": "sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==", "license": "MIT", + "peer": true, "dependencies": { - "@types/node": "*" + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/node": { - "version": "20.19.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", - "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/programs": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-2.3.0.tgz", + "integrity": "sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==", "license": "MIT", + "peer": true, "dependencies": { - "undici-types": "~6.21.0" + "@solana/addresses": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/node/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/@types/offscreencanvas": { - "version": "2019.7.3", - "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", - "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", - "license": "MIT" - }, - "node_modules/@types/p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-qorhClbttP1axgmbMP3rozj6WF6TPAOeKmW3qyC3I7hAgPMvH76Avt/F3seqEciacgLWk8pQxP9Rtde4BnBEpA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/pg": { - "version": "8.15.6", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.6.tgz", - "integrity": "sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/promises": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-2.3.0.tgz", + "integrity": "sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==", "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/pg-pool": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.7.tgz", - "integrity": "sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-2.3.0.tgz", + "integrity": "sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==", "license": "MIT", + "peer": true, "dependencies": { - "@types/pg": "*" + "@solana/errors": "2.3.0", + "@solana/fast-stable-stringify": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/rpc-api": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-transport-http": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/prismjs": { - "version": "1.26.6", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", - "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", - "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-api": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-2.3.0.tgz", + "integrity": "sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==", "license": "MIT", + "peer": true, "dependencies": { - "csstype": "^3.2.2" + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/rpc-parsed-types": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-parsed-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-2.3.0.tgz", + "integrity": "sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==", "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, "peerDependencies": { - "@types/react": "^19.2.0" + "typescript": ">=5.3.3" } }, - "node_modules/@types/react-dropzone": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/react-dropzone/-/react-dropzone-4.2.2.tgz", - "integrity": "sha512-okO6HY+w7V0uHoy6JpLY6BwY/s/oObtXZmUQdX0ycjPeLhK8Af/xf79CFkLA1fM6oVp16n1d962ejdkEXk375Q==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-spec": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-2.3.0.tgz", + "integrity": "sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==", "license": "MIT", + "peer": true, "dependencies": { - "@types/react": "*" + "@solana/errors": "2.3.0", + "@solana/rpc-spec-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/react-reconciler": { - "version": "0.28.9", - "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", - "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-spec-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-2.3.0.tgz", + "integrity": "sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==", "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, "peerDependencies": { - "@types/react": "*" + "typescript": ">=5.3.3" } }, - "node_modules/@types/stats.js": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", - "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", - "license": "MIT" - }, - "node_modules/@types/tedious": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", - "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-2.3.0.tgz", + "integrity": "sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==", "license": "MIT", + "peer": true, "dependencies": { - "@types/node": "*" + "@solana/errors": "2.3.0", + "@solana/fast-stable-stringify": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/promises": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-subscriptions-api": "2.3.0", + "@solana/rpc-subscriptions-channel-websocket": "2.3.0", + "@solana/rpc-subscriptions-spec": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/subscribable": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/three": { - "version": "0.182.0", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.182.0.tgz", - "integrity": "sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions-api": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-2.3.0.tgz", + "integrity": "sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==", "license": "MIT", + "peer": true, "dependencies": { - "@dimforge/rapier3d-compat": "~0.12.0", - "@tweenjs/tween.js": "~23.1.3", - "@types/stats.js": "*", - "@types/webxr": ">=0.5.17", - "@webgpu/types": "*", - "fflate": "~0.8.2", - "meshoptimizer": "~0.22.0" + "@solana/addresses": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/rpc-subscriptions-spec": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions-channel-websocket": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-2.3.0.tgz", + "integrity": "sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==", "license": "MIT", - "optional": true + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/rpc-subscriptions-spec": "2.3.0", + "@solana/subscribable": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3", + "ws": "^8.18.0" + } }, - "node_modules/@types/turndown": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.6.tgz", - "integrity": "sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg==", - "dev": true, - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions-spec": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-2.3.0.tgz", + "integrity": "sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/promises": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/subscribable": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-transformers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-2.3.0.tgz", + "integrity": "sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", - "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-transport-http": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-2.3.0.tgz", + "integrity": "sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "undici-types": "^7.11.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } }, - "node_modules/@types/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true, - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-2.3.0.tgz", + "integrity": "sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/nominal-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } }, - "node_modules/@types/w3c-web-usb": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.13.tgz", - "integrity": "sha512-N2nSl3Xsx8mRHZBvMSdNGtzMyeleTvtlEw+ujujgXalPqOjIA6UtrqcB6OzyUjkTbDm3J7P1RNK1lgoO7jxtsw==", + "node_modules/@trezor/blockchain-link/node_modules/@solana/signers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-2.3.0.tgz", + "integrity": "sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==", "license": "MIT", - "optional": true + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } }, - "node_modules/@types/webxr": { - "version": "0.5.24", - "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", - "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", - "license": "MIT" + "node_modules/@trezor/blockchain-link/node_modules/@solana/subscribable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-2.3.0.tgz", + "integrity": "sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", - "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", - "dev": true, + "node_modules/@trezor/blockchain-link/node_modules/@solana/sysvars": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-2.3.0.tgz", + "integrity": "sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA==", "license": "MIT", + "peer": true, "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/type-utils": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "@solana/accounts": "2.3.0", + "@solana/codecs": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/rpc-types": "2.3.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=20.18.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/blockchain-link/node_modules/@solana/transaction-confirmation": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-2.3.0.tgz", + "integrity": "sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/promises": "2.3.0", + "@solana/rpc": "2.3.0", + "@solana/rpc-subscriptions": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.56.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=5.3.3" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, + "node_modules/@trezor/blockchain-link/node_modules/@solana/transaction-messages": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-2.3.0.tgz", + "integrity": "sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==", "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, "engines": { - "node": ">= 4" + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", - "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", - "dev": true, + "node_modules/@trezor/blockchain-link/node_modules/@solana/transactions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-2.3.0.tgz", + "integrity": "sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==", "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3" + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=20.18.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/blockchain-link/node_modules/@stellar/stellar-sdk": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-14.2.0.tgz", + "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@stellar/stellar-base": "^14.0.1", + "axios": "^1.12.2", + "bignumber.js": "^9.3.1", + "eventsource": "^2.0.2", + "feaxios": "^0.0.23", + "randombytes": "^2.1.0", + "toml": "^3.0.0", + "urijs": "^1.19.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@trezor/connect": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@trezor/connect/-/connect-9.7.3.tgz", + "integrity": "sha512-oAOfvJHT8tPqOXTmCOhn8uTZcoqSDuWAiWXQegx7C46tq+NLg+enkYXxUYEHq/9PmfZAOrUT9VMxZDsXM2thkA==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, + "dependencies": { + "@ethereumjs/common": "^10.1.0", + "@ethereumjs/tx": "^10.1.0", + "@fivebinaries/coin-selection": "3.0.0", + "@mobily/ts-belt": "^3.13.1", + "@noble/hashes": "^1.6.1", + "@scure/bip39": "^1.5.1", + "@solana-program/compute-budget": "^0.8.0", + "@solana-program/system": "^0.7.0", + "@solana-program/token": "^0.5.1", + "@solana-program/token-2022": "^0.4.2", + "@solana/kit": "^2.3.0", + "@trezor/blockchain-link": "2.6.2", + "@trezor/blockchain-link-types": "1.5.1", + "@trezor/blockchain-link-utils": "1.5.2", + "@trezor/connect-analytics": "1.4.0", + "@trezor/connect-common": "0.5.1", + "@trezor/crypto-utils": "1.2.0", + "@trezor/device-authenticity": "1.1.2", + "@trezor/device-utils": "1.2.0", + "@trezor/env-utils": "^1.5.0", + "@trezor/protobuf": "1.5.3", + "@trezor/protocol": "1.3.1", + "@trezor/schema-utils": "1.4.0", + "@trezor/transport": "1.6.3", + "@trezor/type-utils": "1.2.0", + "@trezor/utils": "9.5.0", + "@trezor/utxo-lib": "2.5.0", + "blakejs": "^1.2.1", + "bs58": "^6.0.0", + "bs58check": "^4.0.0", + "cbor": "^10.0.10", + "cross-fetch": "^4.0.0", + "jws": "^4.0.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-analytics": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@trezor/connect-analytics/-/connect-analytics-1.4.0.tgz", + "integrity": "sha512-hy2J2oeIhRC/e1bOWXo5dsVMVnDwO2UKnxhR6FD8PINR3jgM6PWAXc6k33WJsBcyiTzwMP7/xPysLcgNJH5o4w==", + "license": "See LICENSE.md in repo root", + "peer": true, + "dependencies": { + "@trezor/analytics": "1.5.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-common": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@trezor/connect-common/-/connect-common-0.5.1.tgz", + "integrity": "sha512-wdpVCwdylBh4SBO5Ys40tB/d59UlfjmxgBHDkkLgaR+JcqkthCfiw5VlUrV9wu65lquejAZhA5KQL4mUUUhCow==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, + "dependencies": { + "@trezor/env-utils": "1.5.0", + "@trezor/type-utils": "1.2.0", + "@trezor/utils": "9.5.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-plugin-stellar": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/connect-plugin-stellar/-/connect-plugin-stellar-10.0.0-alpha.1.tgz", + "integrity": "sha512-v4lMnnBPxLoV/Yf8F0WmtkZGNsqurpxK62kqvaDeVoAtn5Ud+l6POQkLeQRiGsJYVm0vSDc4LHb5vLMrZTH/KA==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@trezor/utils": "10.0.0-alpha.1" + }, + "peerDependencies": { + "@stellar/stellar-sdk": "^13.3.0", + "@trezor/connect": "9.x.x", + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-plugin-stellar/node_modules/@trezor/utils": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-10.0.0-alpha.1.tgz", + "integrity": "sha512-A+txzREoeX2MO1AqocDBsMNe+R21jTx5kungXGuzeTRRevARLsYh8MPes0170uMjq4qNSgopBnYZK18WyksOmQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.3.1" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-web": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/connect-web/-/connect-web-10.0.0-alpha.1.tgz", + "integrity": "sha512-CW1ZXzXNVYrJ2WuYneLK2LznkRAfKxRPB3vJyv1U2gia5Q7hsblImITsutLOztO0C2xO1sfETTCyVzfRkRVJEA==", + "license": "MIT", + "dependencies": { + "@trezor/connect-common": "10.0.0-alpha.1", + "@trezor/utils": "10.0.0-alpha.1", + "@trezor/websocket-client": "10.0.0-alpha.1" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-web/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "license": "MIT" + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/connect-common": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/connect-common/-/connect-common-10.0.0-alpha.1.tgz", + "integrity": "sha512-tuvM72XHACogT/fkp9D8wyzTE8h4X9emYUhvFs2pdTyIfTFs5RHDbcHQWFsvJgJoTK0H44XSSJb8pORijRfn9A==", + "license": "MIT", + "dependencies": { + "@trezor/device-utils": "10.0.0-alpha.1", + "@trezor/protobuf": "10.0.0-alpha.1", + "@trezor/protocol": "^10.0.0-alpha.1", + "@trezor/schema-utils": "10.0.0-alpha.1", + "@trezor/type-utils": "10.0.0-alpha.1", + "@trezor/utils": "10.0.0-alpha.1" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/device-utils": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/device-utils/-/device-utils-10.0.0-alpha.1.tgz", + "integrity": "sha512-93LhEqH8uKCZHLtF+62uxd3/PXCfqpK4Z98ztfGu5vrtmoONb9dV8Falha0b3KXPDrQ10TUKasFGKLg570Z/Ew==", + "license": "MIT" + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/protobuf": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-10.0.0-alpha.1.tgz", + "integrity": "sha512-aCUyqAr7Sho9TequaNAjnf27mgae6qzesNrOgB19bUrDrhaDDd/2eyr2SrrY1G4hPYkTyBC0jymvQnozn9f/kA==", + "license": "MIT", + "dependencies": { + "@bufbuild/protobuf": "^2.11.0", + "@trezor/schema-utils": "10.0.0-alpha.1" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/protocol": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/protocol/-/protocol-10.0.0-alpha.1.tgz", + "integrity": "sha512-f+rXjtmAdHD93vaLq/QofLJlMP/ZQM4iJqTrcjkUgXKzu8/Jz03tttodBib8A6g9ruGcxLr2smWaRMwwreb8Pg==", + "license": "MIT", + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/schema-utils": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/schema-utils/-/schema-utils-10.0.0-alpha.1.tgz", + "integrity": "sha512-0beYv0b0De3Z60sZzM1T+IrYwXeNL+7RKfLokTvqEFDzsQkwxhYrIX47FsBhGsOmGWx9x4+65dxDbnyd4wZT6g==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.49", + "@trezor/type-utils": "10.0.0-alpha.1", + "ts-mixer": "^6.0.4" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/type-utils": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/type-utils/-/type-utils-10.0.0-alpha.1.tgz", + "integrity": "sha512-wK75rrwlyXFgPfdHQFRbeKCoj+orQLXKj7rliMK30z+F1y+rEcfv/MW2VP48Q9mL5pea+ZX1nRnb4hYx1v38Ow==", + "license": "MIT" + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/utils": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-10.0.0-alpha.1.tgz", + "integrity": "sha512-A+txzREoeX2MO1AqocDBsMNe+R21jTx5kungXGuzeTRRevARLsYh8MPes0170uMjq4qNSgopBnYZK18WyksOmQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.3.1" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect-web/node_modules/@trezor/websocket-client": { + "version": "10.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@trezor/websocket-client/-/websocket-client-10.0.0-alpha.1.tgz", + "integrity": "sha512-129Ot1m+fDodRFBvav2d6v8nLxZLAl/udQP5l5W6jxQZcWUuviphDceT/juF8EvNGdw+L6OIu6fH+yCXARpFWQ==", + "license": "MIT", + "dependencies": { + "@trezor/utils": "10.0.0-alpha.1", + "ws": "^8.20.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/connect/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@trezor/connect/node_modules/@solana-program/compute-budget": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.8.0.tgz", + "integrity": "sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0" + } + }, + "node_modules/@trezor/connect/node_modules/@solana-program/system": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@solana-program/system/-/system-0.7.0.tgz", + "integrity": "sha512-FKTBsKHpvHHNc1ATRm7SlC5nF/VdJtOSjldhcyfMN9R7xo712Mo2jHIzvBgn8zQO5Kg0DcWuKB7268Kv1ocicw==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0" + } + }, + "node_modules/@trezor/connect/node_modules/@solana-program/token": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.5.1.tgz", + "integrity": "sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0" + } + }, + "node_modules/@trezor/connect/node_modules/@solana-program/token-2022": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.4.2.tgz", + "integrity": "sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@solana/kit": "^2.1.0", + "@solana/sysvars": "^2.1.0" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/accounts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-2.3.0.tgz", + "integrity": "sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/addresses": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-2.3.0.tgz", + "integrity": "sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/assertions": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/nominal-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/assertions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-2.3.0.tgz", + "integrity": "sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/codecs": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.3.0.tgz", + "integrity": "sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/options": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/codecs-data-structures": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.3.0.tgz", + "integrity": "sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/codecs-strings": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.3.0.tgz", + "integrity": "sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/fast-stable-stringify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-2.3.0.tgz", + "integrity": "sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/functional": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-2.3.0.tgz", + "integrity": "sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/instructions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-2.3.0.tgz", + "integrity": "sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/keys": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-2.3.0.tgz", + "integrity": "sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/assertions": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/nominal-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/kit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-2.3.0.tgz", + "integrity": "sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/accounts": "2.3.0", + "@solana/addresses": "2.3.0", + "@solana/codecs": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/programs": "2.3.0", + "@solana/rpc": "2.3.0", + "@solana/rpc-parsed-types": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-subscriptions": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/signers": "2.3.0", + "@solana/sysvars": "2.3.0", + "@solana/transaction-confirmation": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/nominal-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-2.3.0.tgz", + "integrity": "sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/options": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.3.0.tgz", + "integrity": "sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/programs": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-2.3.0.tgz", + "integrity": "sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/promises": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-2.3.0.tgz", + "integrity": "sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-2.3.0.tgz", + "integrity": "sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/fast-stable-stringify": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/rpc-api": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-transport-http": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-api": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-2.3.0.tgz", + "integrity": "sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/rpc-parsed-types": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-parsed-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-2.3.0.tgz", + "integrity": "sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-spec": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-2.3.0.tgz", + "integrity": "sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/rpc-spec-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-spec-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-2.3.0.tgz", + "integrity": "sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-2.3.0.tgz", + "integrity": "sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/fast-stable-stringify": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/promises": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-subscriptions-api": "2.3.0", + "@solana/rpc-subscriptions-channel-websocket": "2.3.0", + "@solana/rpc-subscriptions-spec": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/subscribable": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions-api": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-2.3.0.tgz", + "integrity": "sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/rpc-subscriptions-spec": "2.3.0", + "@solana/rpc-transformers": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions-channel-websocket": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-2.3.0.tgz", + "integrity": "sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/rpc-subscriptions-spec": "2.3.0", + "@solana/subscribable": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3", + "ws": "^8.18.0" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions-spec": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-2.3.0.tgz", + "integrity": "sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/promises": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/subscribable": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-transformers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-2.3.0.tgz", + "integrity": "sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-transport-http": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-2.3.0.tgz", + "integrity": "sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0", + "@solana/rpc-spec": "2.3.0", + "@solana/rpc-spec-types": "2.3.0", + "undici-types": "^7.11.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/rpc-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-2.3.0.tgz", + "integrity": "sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/nominal-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/signers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-2.3.0.tgz", + "integrity": "sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/subscribable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-2.3.0.tgz", + "integrity": "sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/sysvars": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-2.3.0.tgz", + "integrity": "sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/accounts": "2.3.0", + "@solana/codecs": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/transaction-confirmation": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-2.3.0.tgz", + "integrity": "sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/promises": "2.3.0", + "@solana/rpc": "2.3.0", + "@solana/rpc-subscriptions": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0", + "@solana/transactions": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/transaction-messages": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-2.3.0.tgz", + "integrity": "sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/rpc-types": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/connect/node_modules/@solana/transactions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-2.3.0.tgz", + "integrity": "sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/addresses": "2.3.0", + "@solana/codecs-core": "2.3.0", + "@solana/codecs-data-structures": "2.3.0", + "@solana/codecs-numbers": "2.3.0", + "@solana/codecs-strings": "2.3.0", + "@solana/errors": "2.3.0", + "@solana/functional": "2.3.0", + "@solana/instructions": "2.3.0", + "@solana/keys": "2.3.0", + "@solana/nominal-types": "2.3.0", + "@solana/rpc-types": "2.3.0", + "@solana/transaction-messages": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@trezor/crypto-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@trezor/crypto-utils/-/crypto-utils-1.2.0.tgz", + "integrity": "sha512-9i1NrfW1IE6JO910ut7xrx4u5LxE++GETbpJhWLj4P5xpuGDDSDLEn/MXaYisls2DpE897aOrGPaa1qyt8V6tw==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/device-authenticity": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@trezor/device-authenticity/-/device-authenticity-1.1.2.tgz", + "integrity": "sha512-313uSXYR4XKDv3CjtCpgHA+yEe9xxqN7EFl/D68FEn70SPsuWI0+2zUvjPPh6TIOh/EcLv7hCO/QTHUAGd7ZWQ==", + "license": "See LICENSE.md in repo root", + "peer": true, + "dependencies": { + "@noble/curves": "^2.0.1", + "@trezor/crypto-utils": "1.2.0", + "@trezor/protobuf": "1.5.2", + "@trezor/schema-utils": "1.4.0", + "@trezor/utils": "9.5.0" + } + }, + "node_modules/@trezor/device-authenticity/node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@trezor/device-authenticity/node_modules/@trezor/protobuf": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.2.tgz", + "integrity": "sha512-zViaL1jKue8DUTVEDg0C/lMipqNMd/Z3kr29/+MeZOoupjaXIQ2Lqp3WAMe8hvNTKKX8aNQH9JrbapJ6w9FMXw==", + "license": "See LICENSE.md in repo root", + "peer": true, + "dependencies": { + "@trezor/schema-utils": "1.4.0", + "long": "5.2.5", + "protobufjs": "7.4.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/device-authenticity/node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@trezor/device-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@trezor/device-utils/-/device-utils-1.2.0.tgz", + "integrity": "sha512-Aqp7pIooFTx21zRUtTI6i1AS4d9Lrx7cclvksh2nJQF9WJvbzuCXshEGkLoOsHwhQrCl3IXfbGuMdA12yDenPA==", + "license": "See LICENSE.md in repo root", + "peer": true + }, + "node_modules/@trezor/env-utils": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@trezor/env-utils/-/env-utils-1.5.0.tgz", + "integrity": "sha512-u1TN7dMQ5Qhpbae08Z4JJmI9fQrbbJ4yj8eIAsuzMQn6vb+Sg9vbntl+IDsZ1G9WeI73uHTLu1wWMmAgiujH8w==", + "license": "See LICENSE.md in repo root", + "peer": true, + "dependencies": { + "ua-parser-js": "^2.0.4" + }, + "peerDependencies": { + "expo-constants": "*", + "expo-localization": "*", + "react-native": "*", + "tslib": "^2.6.2" + }, + "peerDependenciesMeta": { + "expo-constants": { + "optional": true + }, + "expo-localization": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@trezor/protobuf": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.3.tgz", + "integrity": "sha512-ZYQtapkT2NaiVrAgb91Zprnk3uhl2Wca0bsnJcWgE7vwzqKegjrSorRnkZLqLTKTbCaT6sgkCYtM2hPl4Hqw5Q==", + "license": "See LICENSE.md in repo root", + "peer": true, + "dependencies": { + "@trezor/schema-utils": "1.4.0", + "long": "5.2.5", + "protobufjs": "7.5.5" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/protocol": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@trezor/protocol/-/protocol-1.3.1.tgz", + "integrity": "sha512-uNJ83n38+BM+AJKsWza1ocvQ206d6NXJQ8/g+DelPLTj5c37Rj6hFiY5Nb5zgM7DBnq6T8Aa2K8t4TVCzHT1qg==", + "license": "See LICENSE.md in repo root", + "peer": true, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/schema-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@trezor/schema-utils/-/schema-utils-1.4.0.tgz", + "integrity": "sha512-K7upSeh7VDrORaIC4KAxYVW93XNlohmUnH5if/5GKYmTdQSRp1nBkO6Jm+Z4hzIthdnz/1aLgnbeN3bDxWLRxA==", + "license": "See LICENSE.md in repo root", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.33.7", + "ts-mixer": "^6.0.3" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/transport": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@trezor/transport/-/transport-1.6.3.tgz", + "integrity": "sha512-GEi9KfiJsBgT/MCGNDIn9RDeXceLaAPjJT/GCayirXaCr3KnlpZCs6LGYkrjqapxiBm73nxM+BctKBKhpUl2cQ==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, + "dependencies": { + "@trezor/protobuf": "1.5.3", + "@trezor/protocol": "1.3.1", + "@trezor/type-utils": "1.2.0", + "@trezor/utils": "9.5.0", + "cross-fetch": "^4.0.0", + "usb": "^2.15.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/type-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@trezor/type-utils/-/type-utils-1.2.0.tgz", + "integrity": "sha512-+E2QntxkyQuYfQQyl8RvT01tq2i5Dp/LFUOXuizF+KVOqsZBjBY43j5hewcCO3+MokD7deDiPyekbUEN5/iVlw==", + "license": "See LICENSE.md in repo root", + "peer": true + }, + "node_modules/@trezor/utils": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-9.5.0.tgz", + "integrity": "sha512-kdyMyDbxzvOZmwBNvTjAK+C/kzyOz8T4oUbFvq+KaXn5mBFf1uf8rq5X2HkxgdYRPArtHS3PxLKsfkNCdhCYtQ==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, + "dependencies": { + "bignumber.js": "^9.3.1" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/utxo-lib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@trezor/utxo-lib/-/utxo-lib-2.5.0.tgz", + "integrity": "sha512-Fa2cZh0037oX6AHNLfpFIj65UR/OoX0ZJTocFuQASe77/1PjZHysf6BvvGfmzuFToKfrAQ+DM/1Sx+P/vnyNmA==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, + "dependencies": { + "@trezor/utils": "9.5.0", + "bech32": "^2.0.0", + "bip66": "^2.0.0", + "bitcoin-ops": "^1.4.1", + "blake-hash": "^2.0.0", + "blakejs": "^1.2.1", + "bn.js": "^5.2.2", + "bs58": "^6.0.0", + "bs58check": "^4.0.0", + "cashaddrjs": "0.4.4", + "create-hmac": "^1.1.7", + "int64-buffer": "^1.1.0", + "pushdata-bitcoin": "^1.0.1", + "tiny-secp256k1": "^1.1.7", + "typeforce": "^1.18.0", + "varuint-bitcoin": "2.0.0", + "wif": "^5.0.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trezor/websocket-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@trezor/websocket-client/-/websocket-client-1.3.0.tgz", + "integrity": "sha512-9KQSaVc3NtmM6rFFj1e+9bM0C5mVKVidbnxlfzuBJu7G2YMRdIdLPcAXhvmRZjs40uzDuBeApK+p547kODz2ug==", + "license": "SEE LICENSE IN LICENSE.md", + "peer": true, + "dependencies": { + "@trezor/utils": "9.5.0", + "ws": "^8.18.0" + }, + "peerDependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@trustless-work/escrow": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@trustless-work/escrow/-/escrow-3.0.5.tgz", + "integrity": "sha512-IFvu/4K5rYJzucQvIfiAVSdt8QeBjHLDiWcxlmKCQN36gJ8906QMBssSyug/BuBA1ShGTWk1Yn9BfcPUSEQhhw==", + "license": "MIT", + "dependencies": { + "axios": "^1.9.0" + }, + "peerDependencies": { + "react": ">=18.0.0 <20.0.0", + "react-dom": ">=18.0.0 <20.0.0" + } + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/draco3d": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", + "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", + "license": "MIT" + }, + "node_modules/@types/lodash.debounce": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.9.tgz", + "integrity": "sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/marked": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.2.tgz", + "integrity": "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT" + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", + "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, + "node_modules/@types/p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-qorhClbttP1axgmbMP3rozj6WF6TPAOeKmW3qyC3I7hAgPMvH76Avt/F3seqEciacgLWk8pQxP9Rtde4BnBEpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-dropzone": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dropzone/-/react-dropzone-4.2.2.tgz", + "integrity": "sha512-okO6HY+w7V0uHoy6JpLY6BwY/s/oObtXZmUQdX0ycjPeLhK8Af/xf79CFkLA1fM6oVp16n1d962ejdkEXk375Q==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-reconciler": { + "version": "0.28.9", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", + "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.182.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.182.0.tgz", + "integrity": "sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.22.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/turndown": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.6.tgz", + "integrity": "sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "license": "MIT" + }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.13.tgz", + "integrity": "sha512-N2nSl3Xsx8mRHZBvMSdNGtzMyeleTvtlEw+ujujgXalPqOjIA6UtrqcB6OzyUjkTbDm3J7P1RNK1lgoO7jxtsw==", + "license": "MIT" + }, + "node_modules/@types/web": { + "version": "0.0.197", + "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.197.tgz", + "integrity": "sha512-V4sOroWDADFx9dLodWpKm298NOJ1VJ6zoDVgaP+WBb/utWxqQ6gnMzd9lvVDAr/F3ibiKaxH9i45eS0gQPSTaQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", + "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/type-utils": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", + "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", + "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.0", + "@typescript-eslint/types": "^8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", + "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", + "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", + "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", + "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.0", + "@typescript-eslint/tsconfig-utils": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", + "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", + "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@uiw/copy-to-clipboard": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.20.tgz", + "integrity": "sha512-IFQhS62CLNon1YgYJTEzXR2N3WVXg7V1FaBRDLMlzU6JY5X6Hr3OPAcw4WNoKcz2XcFD6XCgwEjlsmj+JA0mWA==", + "license": "MIT", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/@uiw/react-markdown-preview": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@uiw/react-markdown-preview/-/react-markdown-preview-5.1.5.tgz", + "integrity": "sha512-DNOqx1a6gJR7Btt57zpGEKTfHRlb7rWbtctMRO2f82wWcuoJsxPBrM+JWebDdOD0LfD8oe2CQvW2ICQJKHQhZg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@uiw/copy-to-clipboard": "~1.0.12", + "react-markdown": "~9.0.1", + "rehype-attr": "~3.0.1", + "rehype-autolink-headings": "~7.1.0", + "rehype-ignore": "^2.0.0", + "rehype-prism-plus": "2.0.0", + "rehype-raw": "^7.0.0", + "rehype-rewrite": "~4.0.0", + "rehype-slug": "~6.0.0", + "remark-gfm": "~4.0.0", + "remark-github-blockquote-alert": "^1.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@uiw/react-markdown-preview/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/refractor": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-4.9.0.tgz", + "integrity": "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prismjs": "^1.0.0", + "hastscript": "^7.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz", + "integrity": "sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ==", + "license": "MIT", + "dependencies": { + "hast-util-to-string": "^3.0.0", + "parse-numeric-range": "^1.3.0", + "refractor": "^4.8.0", + "rehype-parse": "^9.0.0", + "unist-util-filter": "^5.0.0", + "unist-util-visit": "^5.0.0" + } + }, + "node_modules/@uiw/react-md-editor": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@uiw/react-md-editor/-/react-md-editor-4.0.11.tgz", + "integrity": "sha512-F0OR5O1v54EkZYvJj3ew0I7UqLiPeU34hMAY4MdXS3hI86rruYi5DHVkG/VuvLkUZW7wIETM2QFtZ459gKIjQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.14.6", + "@uiw/react-markdown-preview": "^5.0.6", + "rehype": "~13.0.0", + "rehype-prism-plus": "~2.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, + "node_modules/@vercel/analytics": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.6.1.tgz", + "integrity": "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==", + "license": "MPL-2.0", + "peerDependencies": { + "@remix-run/react": "^2", + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" + }, + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } + } + }, + "node_modules/@wallet-standard/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wallet-standard/base/-/base-1.1.1.tgz", + "integrity": "sha512-gggIHTtxicF9XFMQ12DkfS6NAG92Ak795JeSA7f2whAQ6Y3AkMWWuCMxSZXG2NIPN42kEaZSNVjqMsJRaJRxMQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, + "node_modules/@wallet-standard/features": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wallet-standard/features/-/features-1.1.1.tgz", + "integrity": "sha512-aCWYmVeSCGViyEU5k7GMoW8zxE4Gs+C1s1Pp2XLesvSNlnZ4PMES9HUnTB3hl0b3RVj7C61yze3IWyrncqg4MA==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.1" }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "engines": { + "node": ">=22" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", - "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", - "dev": true, - "license": "MIT", + "node_modules/@wallet-standard/wallet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/wallet/-/wallet-1.1.0.tgz", + "integrity": "sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg==", + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.0", - "@typescript-eslint/types": "^8.56.0", - "debug": "^4.4.3" + "@wallet-standard/base": "^1.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "node": ">=16" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", - "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", - "dev": true, - "license": "MIT", + "node_modules/@walletconnect/core": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.0.tgz", + "integrity": "sha512-W++xuXf+AsMPrBWn1It8GheIbCTp1ynTQP+aoFB86eUwyCtSiK7UQsn/+vJZdwElrn+Ptp2A0RqQx2onTMVHjQ==", + "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0" + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.0", + "@walletconnect/utils": "2.23.0", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.39.3", + "events": "3.3.0", + "uint8arrays": "3.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=18.20.8" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", - "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", - "dev": true, + "node_modules/@walletconnect/core/node_modules/@walletconnect/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==", "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "dependencies": { + "@walletconnect/safe-json": "^1.0.2", + "pino": "10.0.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", - "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", - "dev": true, - "license": "MIT", + "node_modules/@walletconnect/core/node_modules/@walletconnect/types": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.0.tgz", + "integrity": "sha512-9ZEOJyx/kNVCRncDHh3Qr9eH7Ih1dXBFB4k1J8iEudkv3t4GhYpXhqIt2kNdQWluPb1BBB4wEuckAT96yKuA8g==", + "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "events": "3.3.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", - "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", - "dev": true, + "node_modules/@walletconnect/core/node_modules/es-toolkit": { + "version": "1.39.3", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.39.3.tgz", + "integrity": "sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww==", "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/@walletconnect/environment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/environment/-/environment-1.0.1.tgz", + "integrity": "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", - "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", - "dev": true, + "node_modules/@walletconnect/environment/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz", + "integrity": "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.0", - "@typescript-eslint/tsconfig-utils": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "keyvaluestorage-interface": "^1.0.0", + "tslib": "1.14.1" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", - "dev": true, + "node_modules/@walletconnect/events/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/heartbeat": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz", + "integrity": "sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "@walletconnect/events": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "events": "^3.3.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", + "node_modules/@walletconnect/jsonrpc-http-connection": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz", + "integrity": "sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.1", + "cross-fetch": "^3.1.4", + "events": "^3.3.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", - "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", - "dev": true, + "node_modules/@walletconnect/jsonrpc-http-connection/node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "node-fetch": "^2.7.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", - "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", - "dev": true, + "node_modules/@walletconnect/jsonrpc-provider": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz", + "integrity": "sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@walletconnect/jsonrpc-utils": "^1.0.8", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node_modules/@walletconnect/jsonrpc-types": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz", + "integrity": "sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==", + "license": "MIT", + "dependencies": { + "events": "^3.3.0", + "keyvaluestorage-interface": "^1.0.0" } }, - "node_modules/@uiw/copy-to-clipboard": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.20.tgz", - "integrity": "sha512-IFQhS62CLNon1YgYJTEzXR2N3WVXg7V1FaBRDLMlzU6JY5X6Hr3OPAcw4WNoKcz2XcFD6XCgwEjlsmj+JA0mWA==", + "node_modules/@walletconnect/jsonrpc-utils": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz", + "integrity": "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==", "license": "MIT", - "funding": { - "url": "https://jaywcjlove.github.io/#/sponsor" + "dependencies": { + "@walletconnect/environment": "^1.0.1", + "@walletconnect/jsonrpc-types": "^1.0.3", + "tslib": "1.14.1" } }, - "node_modules/@uiw/react-markdown-preview": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@uiw/react-markdown-preview/-/react-markdown-preview-5.1.5.tgz", - "integrity": "sha512-DNOqx1a6gJR7Btt57zpGEKTfHRlb7rWbtctMRO2f82wWcuoJsxPBrM+JWebDdOD0LfD8oe2CQvW2ICQJKHQhZg==", + "node_modules/@walletconnect/jsonrpc-utils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/jsonrpc-ws-connection": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz", + "integrity": "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.17.2", - "@uiw/copy-to-clipboard": "~1.0.12", - "react-markdown": "~9.0.1", - "rehype-attr": "~3.0.1", - "rehype-autolink-headings": "~7.1.0", - "rehype-ignore": "^2.0.0", - "rehype-prism-plus": "2.0.0", - "rehype-raw": "^7.0.0", - "rehype-rewrite": "~4.0.0", - "rehype-slug": "~6.0.0", - "remark-gfm": "~4.0.0", - "remark-github-blockquote-alert": "^1.0.0", - "unist-util-visit": "^5.0.0" + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0", + "ws": "^7.5.1" + } + }, + "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" }, - "funding": { - "url": "https://jaywcjlove.github.io/#/sponsor" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } } }, - "node_modules/@uiw/react-markdown-preview/node_modules/@types/hast": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", - "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "node_modules/@walletconnect/logger": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.2.tgz", + "integrity": "sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA==", "license": "MIT", "dependencies": { - "@types/unist": "^2" + "@walletconnect/safe-json": "^1.0.2", + "pino": "10.0.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "license": "MIT" + "node_modules/@walletconnect/relay-api": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.11.tgz", + "integrity": "sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-types": "^1.0.2" + } }, - "node_modules/@uiw/react-markdown-preview/node_modules/hast-util-parse-selector": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", - "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "node_modules/@walletconnect/relay-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", + "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@noble/curves": "1.8.0", + "@noble/hashes": "1.7.0", + "@walletconnect/safe-json": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "uint8arrays": "^3.0.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/hastscript": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", - "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "node_modules/@walletconnect/relay-auth/node_modules/@noble/curves": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", + "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" + "@noble/hashes": "1.7.0" + }, + "engines": { + "node": "^14.21.3 || >=16" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "node_modules/@walletconnect/relay-auth/node_modules/@noble/hashes": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/refractor": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-4.9.0.tgz", - "integrity": "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og==", + "node_modules/@walletconnect/safe-json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz", + "integrity": "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "@types/prismjs": "^1.0.0", - "hastscript": "^7.0.0", - "parse-entities": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "tslib": "1.14.1" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz", - "integrity": "sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ==", + "node_modules/@walletconnect/safe-json/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/sign-client": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.0.tgz", + "integrity": "sha512-Nzf5x/LnQgC0Yjk0NmkT8kdrIMcScpALiFm9gP0n3CulL+dkf3HumqWzdoTmQSqGPxwHu/TNhGOaRKZLGQXSqw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/core": "2.23.0", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "3.0.0", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.0", + "@walletconnect/utils": "2.23.0", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/sign-client/node_modules/@walletconnect/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==", "license": "MIT", "dependencies": { - "hast-util-to-string": "^3.0.0", - "parse-numeric-range": "^1.3.0", - "refractor": "^4.8.0", - "rehype-parse": "^9.0.0", - "unist-util-filter": "^5.0.0", - "unist-util-visit": "^5.0.0" + "@walletconnect/safe-json": "^1.0.2", + "pino": "10.0.0" } }, - "node_modules/@uiw/react-md-editor": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@uiw/react-md-editor/-/react-md-editor-4.0.11.tgz", - "integrity": "sha512-F0OR5O1v54EkZYvJj3ew0I7UqLiPeU34hMAY4MdXS3hI86rruYi5DHVkG/VuvLkUZW7wIETM2QFtZ459gKIjQA==", + "node_modules/@walletconnect/sign-client/node_modules/@walletconnect/types": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.0.tgz", + "integrity": "sha512-9ZEOJyx/kNVCRncDHh3Qr9eH7Ih1dXBFB4k1J8iEudkv3t4GhYpXhqIt2kNdQWluPb1BBB4wEuckAT96yKuA8g==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz", + "integrity": "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.14.6", - "@uiw/react-markdown-preview": "^5.0.6", - "rehype": "~13.0.0", - "rehype-prism-plus": "~2.0.0" + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/time/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/types": { + "version": "2.23.9", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.9.tgz", + "integrity": "sha512-IUl1PpD/Dig8IE2OZ9XtjbPohEyOZJ73xs92EDUzoIyzRtfm36g2D340pY3iu3AAdLv1yFiaZafB8Hf8RFze8A==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.2", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/universal-provider": { + "version": "2.23.7", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.7.tgz", + "integrity": "sha512-6UicU/Mhr/1bh7MNoajypz7BhigORbHpP1LFTf8FYLQGDqzmqHMqmMH2GDAImtaY2sFTi2jBvc22tLl8VMze/A==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.2", + "@walletconnect/sign-client": "2.23.7", + "@walletconnect/types": "2.23.7", + "@walletconnect/utils": "2.23.7", + "es-toolkit": "1.44.0", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/@msgpack/msgpack": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.1.3.tgz", + "integrity": "sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==", + "license": "ISC", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" }, "funding": { - "url": "https://jaywcjlove.github.io/#/sponsor" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "license": "ISC" + "node_modules/@walletconnect/universal-provider/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@upsetjs/venn.js": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", - "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "node_modules/@walletconnect/universal-provider/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", - "optionalDependencies": { - "d3-selection": "^3.0.0", - "d3-transition": "^3.0.1" + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@use-gesture/core": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", - "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "node_modules/@walletconnect/universal-provider/node_modules/@walletconnect/core": { + "version": "2.23.7", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.7.tgz", + "integrity": "sha512-yTyymn9mFaDZkUfLfZ3E9VyaSDPeHAXlrPxQRmNx2zFsEt/25GmTU2A848aomimLxZnAG2jNLhxbJ8I0gyNV+w==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.7", + "@walletconnect/utils": "2.23.7", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.44.0", + "events": "3.3.0", + "uint8arrays": "3.1.1" + }, + "engines": { + "node": ">=18.20.8" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/@walletconnect/sign-client": { + "version": "2.23.7", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.7.tgz", + "integrity": "sha512-SX61lzb1bTl/LijlcHQttnoHPBzzoY5mW9ArR6qhFtDNDTS7yr2rcH7rCngxHlYeb4rAYcWLHgbiGSrdKxl/mg==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/core": "2.23.7", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "3.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.7", + "@walletconnect/utils": "2.23.7", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/@walletconnect/types": { + "version": "2.23.7", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.7.tgz", + "integrity": "sha512-6PAKK+iR2IntmlkCFLMAHjYeIaerCJJYRDmdRimhon0u+aNmQT+HyGM6zxDAth0rdpBD7qEvKP5IXZTE7KFUhw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.2", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/@walletconnect/utils": { + "version": "2.23.7", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.7.tgz", + "integrity": "sha512-3p38gNrkVcIiQixVrlsWSa66Gjs5PqHOug2TxDgYUVBW5NcKjwQA08GkC6CKBQUfr5iaCtbfy6uZJW1LKSIvWQ==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@msgpack/msgpack": "3.1.3", + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.7", + "@noble/hashes": "1.8.0", + "@scure/base": "1.2.6", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.7", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "blakejs": "1.2.1", + "detect-browser": "5.3.0", + "ox": "0.9.3", + "uint8arrays": "3.1.1" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/es-toolkit": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz", + "integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/@walletconnect/universal-provider/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, - "node_modules/@use-gesture/react": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", - "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "node_modules/@walletconnect/universal-provider/node_modules/ox": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.9.3.tgz", + "integrity": "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], "license": "MIT", "dependencies": { - "@use-gesture/core": "10.3.1" + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.0.9", + "eventemitter3": "5.0.1" }, "peerDependencies": { - "react": ">= 16.8.0" - } - }, - "node_modules/@vercel/analytics": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.6.1.tgz", - "integrity": "sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==", - "license": "MPL-2.0", - "peerDependencies": { - "@remix-run/react": "^2", - "@sveltejs/kit": "^1 || ^2", - "next": ">= 13", - "react": "^18 || ^19 || ^19.0.0-rc", - "svelte": ">= 4", - "vue": "^3", - "vue-router": "^4" + "typescript": ">=5.4.0" }, "peerDependenciesMeta": { - "@remix-run/react": { - "optional": true - }, - "@sveltejs/kit": { - "optional": true - }, - "next": { - "optional": true - }, - "react": { - "optional": true - }, - "svelte": { - "optional": true - }, - "vue": { - "optional": true - }, - "vue-router": { + "typescript": { "optional": true } } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "node_modules/@walletconnect/universal-provider/node_modules/ox/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", "license": "MIT", - "peer": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "node_modules/@walletconnect/utils": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.0.tgz", + "integrity": "sha512-bVyv4Hl+/wVGueZ6rEO0eYgDy5deSBA4JjpJHAMOdaNoYs05NTE1HymV2lfPQQHuqc7suYexo9jwuW7i3JLuAA==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@msgpack/msgpack": "3.1.2", + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.7", + "@noble/hashes": "1.8.0", + "@scure/base": "1.2.6", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.0", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "blakejs": "1.2.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "ox": "0.9.3", + "uint8arrays": "3.1.1" + } + }, + "node_modules/@walletconnect/utils/node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "license": "MIT", - "peer": true + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "node_modules/@walletconnect/utils/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", - "peer": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "node_modules/@walletconnect/utils/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "node_modules/@walletconnect/utils/node_modules/@walletconnect/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==", "license": "MIT", - "peer": true, "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "@walletconnect/safe-json": "^1.0.2", + "pino": "10.0.0" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "license": "Apache-2.0", - "peer": true, + "node_modules/@walletconnect/utils/node_modules/@walletconnect/types": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.0.tgz", + "integrity": "sha512-9ZEOJyx/kNVCRncDHh3Qr9eH7Ih1dXBFB4k1J8iEudkv3t4GhYpXhqIt2kNdQWluPb1BBB4wEuckAT96yKuA8g==", + "license": "SEE LICENSE IN LICENSE.md", "dependencies": { - "@xtuc/long": "4.2.2" + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "events": "3.3.0" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT", - "peer": true + "node_modules/@walletconnect/utils/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "node_modules/@walletconnect/utils/node_modules/ox": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.9.3.tgz", + "integrity": "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], "license": "MIT", - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.0.9", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "node_modules/@walletconnect/utils/node_modules/ox/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", "license": "MIT", - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "node_modules/@walletconnect/window-getters": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz", + "integrity": "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==", "license": "MIT", - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" + "tslib": "1.14.1" } }, - "node_modules/@webassemblyjs/wasm-parser": { + "node_modules/@walletconnect/window-getters/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/window-metadata": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz", + "integrity": "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==", "license": "MIT", - "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "@walletconnect/window-getters": "^1.0.1", + "tslib": "1.14.1" } }, - "node_modules/@webassemblyjs/wast-printer": { + "node_modules/@walletconnect/window-metadata/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" }, "node_modules/@webgpu/types": { "version": "0.1.69", @@ -7354,20 +11166,60 @@ "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==", "license": "BSD-3-Clause" }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause", - "peer": true + "node_modules/@xrplf/isomorphic": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@xrplf/isomorphic/-/isomorphic-1.0.2.tgz", + "integrity": "sha512-ncZUdMXr6VlSXtdoiDi0jTH+gBrgGxwVeEidhoegII3PmyErbQsyj6e+j7acmR4LW/lvBkPkzb9QzRfJH0n3rA==", + "license": "ISC", + "peer": true, + "dependencies": { + "@noble/hashes": "^2.0.1", + "eventemitter3": "5.0.1", + "ws": "^8.20.0" + }, + "engines": { + "node": ">=18.0.0" + } }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0", + "node_modules/@xrplf/isomorphic/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT", "peer": true }, + "node_modules/@xrplf/secret-numbers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@xrplf/secret-numbers/-/secret-numbers-2.0.0.tgz", + "integrity": "sha512-z3AOibRTE9E8MbjgzxqMpG1RNaBhQ1jnfhNCa1cGf2reZUJzPMYs4TggQTc7j8+0WyV3cr7y/U8Oz99SXIkN5Q==", + "license": "ISC", + "peer": true, + "dependencies": { + "@xrplf/isomorphic": "^1.0.1", + "ripple-keypairs": "^2.0.0" + } + }, + "node_modules/abitype": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.4.tgz", + "integrity": "sha512-dpKH+N27vRjarMVTFFkeY445VTKftzGWpL0FiT7xmVmzQRKazZexzC5uHG0f6XKsVLAuUlndnbGau6lRejClxg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -7380,28 +11232,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -7411,16 +11241,16 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", "license": "MIT", "dependencies": { - "debug": "4" + "humanize-ms": "^1.2.1" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 8.0.0" } }, "node_modules/ajv": { @@ -7440,48 +11270,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "license": "MIT", - "peer": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=6" } }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "peer": true - }, "node_modules/ansi-escapes": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", @@ -7524,6 +11322,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -7680,6 +11491,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT", + "peer": true + }, "node_modules/astring": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", @@ -7705,6 +11535,15 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/attr-accept": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", @@ -7740,6 +11579,32 @@ "proxy-from-env": "^2.1.0" } }, + "node_modules/axios-retry": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.5.0.tgz", + "integrity": "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "is-retry-allowed": "^2.2.0" + }, + "peerDependencies": { + "axios": "0.x || 1.x" + } + }, + "node_modules/axios-retry/node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/axios/node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -7810,6 +11675,12 @@ "license": "Apache-2.0", "optional": true }, + "node_modules/base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", + "license": "MIT" + }, "node_modules/base32.js": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", @@ -7858,6 +11729,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==", + "license": "MIT", + "peer": true + }, "node_modules/better-auth": { "version": "1.6.11", "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.11.tgz", @@ -7992,6 +11870,29 @@ "require-from-string": "^2.0.2" } }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "license": "Unlicense", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, "node_modules/bignumber.js": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", @@ -8001,12 +11902,76 @@ "node": "*" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bip32-path": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/bip32-path/-/bip32-path-0.4.2.tgz", + "integrity": "sha512-ZBMCELjJfcNMkz5bDuJ1WrYvjlhEF5k6mQ8vUr4N7MbVRsXei7ZOg8VhhwMfNiW68NWmLkgkc6WvTickrLGprQ==", + "license": "MIT" + }, + "node_modules/bip66": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-2.0.0.tgz", + "integrity": "sha512-kBG+hSpgvZBrkIm9dt5T1Hd/7xGCPEX2npoxAWZfsK1FvjgaxySEh2WizjyIstWXriKo9K9uJ4u0OnsyLDUPXQ==", + "license": "MIT", + "peer": true + }, + "node_modules/bitcoin-ops": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz", + "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==", + "license": "MIT", + "peer": true + }, + "node_modules/blake-hash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/blake-hash/-/blake-hash-2.0.0.tgz", + "integrity": "sha512-Igj8YowDu1PRkRsxZA7NVkdFNxH5rKv5cpLxQ0CVXSIA77pVYwCPRQJ2sMew/oneUpfuYRyjG6r8SmmmnbZb1w==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "license": "MIT" + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, + "node_modules/borsh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-2.0.0.tgz", + "integrity": "sha512-kc9+BgR3zz9+cjbwM8ODoUB4fs3X3I5A/HtX7LZKxCLaMrEeDFoBpnhZY//DTS1VZBSs6S5v46RZRbZjRFspEg==", + "license": "Apache-2.0" + }, "node_modules/brace-expansion": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", @@ -8018,23 +11983,153 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "license": "MIT", + "peer": true, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.6.tgz", + "integrity": "sha512-sd+Q65fjlWCYWtZKXiKfrUc8d+4jtp/8f0W2NkwzLtoW4bI6UDnWusLWIurHnmurW0XShIRxpwiOX4EoPtXUAg==", + "license": "ISC", + "peer": true, + "dependencies": { + "bn.js": "^5.2.3", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT", + "peer": true + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT", + "peer": true + }, + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", + "peer": true, "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" + "safe-buffer": "~5.1.0" } }, + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT", + "peer": true + }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -8064,6 +12159,39 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/bs58check": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", + "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "^1.2.0", + "bs58": "^6.0.0" + } + }, + "node_modules/bs58check/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -8088,13 +12216,34 @@ "ieee754": "^1.2.1" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "license": "MIT", "peer": true }, + "node_modules/bufferutil": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", + "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -8152,6 +12301,15 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/camera-controls": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.2.tgz", @@ -8185,6 +12343,29 @@ ], "license": "CC-BY-4.0" }, + "node_modules/cashaddrjs": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cashaddrjs/-/cashaddrjs-0.4.4.tgz", + "integrity": "sha512-xZkuWdNOh0uq/mxJIng6vYWfTowZLd9F4GMAlp2DwFHlcCqCm91NtuAc47RuV4L7r4PYcY5p6Cr2OKNb4hnkWA==", + "license": "MIT", + "peer": true, + "dependencies": { + "big-integer": "1.6.36" + } + }, + "node_modules/cbor": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.12.tgz", + "integrity": "sha512-exQDevYd7ZQLP4moMQcZkKCVZsXLAtUSflObr3xTh4xzFIv/xBCdvCd6L259kQOUP2kcTC0jvC6PpZIf/WmRXA==", + "license": "MIT", + "peer": true, + "dependencies": { + "nofilter": "^3.0.2" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -8204,6 +12385,25 @@ "react": ">=17.0.0" } }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -8244,21 +12444,44 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "license": "MIT", - "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, "engines": { - "node": ">=6.0" + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/cjs-module-lexer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", - "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", - "license": "MIT" + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } }, "node_modules/class-variance-authority": { "version": "0.7.1", @@ -8311,6 +12534,90 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -8350,7 +12657,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -8363,7 +12669,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/colorette": { @@ -8399,18 +12704,11 @@ "version": "14.0.3", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, "license": "MIT", "engines": { "node": ">=20" } }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -8428,8 +12726,22 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie-es": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", "license": "MIT" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT", + "peer": true + }, "node_modules/cose-base": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", @@ -8439,6 +12751,53 @@ "layout-base": "^1.0.0" } }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT", + "peer": true + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", + "peer": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", + "peer": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "node_modules/crelt": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", @@ -8463,6 +12822,16 @@ "yarn": ">=1" } }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "peer": true, + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -8477,6 +12846,47 @@ "node": ">= 8" } }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "license": "MIT", + "peer": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, "node_modules/css-selector-parser": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz", @@ -9121,6 +13531,15 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decimal.js-light": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", @@ -9197,6 +13616,18 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -9206,14 +13637,67 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", - "engines": { - "node": ">=6" - } + "engines": { + "node": ">=6" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "license": "MIT" + }, + "node_modules/detect-europe-js": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/detect-europe-js/-/detect-europe-js-0.1.2.tgz", + "integrity": "sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "license": "MIT", + "peer": true }, "node_modules/detect-gpu": { "version": "5.0.70", @@ -9252,6 +13736,31 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT", + "peer": true + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, "node_modules/direction": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", @@ -9297,18 +13806,6 @@ "@types/trusted-types": "^2.0.7" } }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/draco3d": { "version": "1.5.7", "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", @@ -9329,12 +13826,44 @@ "node": ">= 0.4" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true, "license": "ISC" }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, "node_modules/embla-carousel": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", @@ -9372,6 +13901,18 @@ "embla-carousel": "8.6.0" } }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", + "license": "MIT" + }, "node_modules/engine.io-client": { "version": "6.6.5", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.5.tgz", @@ -9547,13 +14088,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", - "license": "MIT", - "peer": true - }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -9622,6 +14156,21 @@ "benchmarks" ] }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, "node_modules/esast-util-from-estree": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", @@ -9658,6 +14207,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -9982,6 +14532,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -9994,6 +14545,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -10104,7 +14656,6 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, "license": "MIT" }, "node_modules/events": { @@ -10112,7 +14663,6 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.x" } @@ -10126,6 +14676,24 @@ "node": ">=12.0.0" } }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "license": "MIT", + "peer": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -10144,10 +14712,19 @@ "node": ">=0.10.0" } }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-diff": { @@ -10170,7 +14747,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -10180,21 +14756,17 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause", + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT" + }, + "node_modules/fastestsmallesttextencoderdecoder": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "license": "CC0-1.0", "peer": true }, "node_modules/feaxios": { @@ -10237,6 +14809,13 @@ "node": ">= 12" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT", + "peer": true + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -10254,6 +14833,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -10338,12 +14918,6 @@ "node": ">= 6" } }, - "node_modules/forwarded-parse": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", - "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", - "license": "MIT" - }, "node_modules/framer-motion": { "version": "12.35.2", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.35.2.tgz", @@ -10371,20 +14945,6 @@ } } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -10425,6 +14985,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-property": "^1.0.0" + } + }, "node_modules/generator-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", @@ -10439,11 +15019,21 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-east-asian-width": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", @@ -10527,23 +15117,6 @@ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, - "node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -10557,49 +15130,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/glob/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -10697,6 +15227,23 @@ "integrity": "sha512-P8/mMxVLU7o4+55+1TCnQrPmgjPKnwkzkXOK1asnR9Jg2lna4tEY5qBJjMmAaOBDDZWtlRjBXjLa0w53G/uBLA==", "license": "Standard 'no charge' license: https://gsap.com/standard-license." }, + "node_modules/h3": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.3", + "crossws": "^0.3.5", + "defu": "^6.1.6", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.4", + "radix3": "^1.1.2", + "ufo": "^1.6.3", + "uncrypto": "^0.1.3" + } + }, "node_modules/hachure-fill": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", @@ -10720,6 +15267,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10780,6 +15328,79 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/hash-base/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT", + "peer": true + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hash-base/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT", + "peer": true + }, + "node_modules/hash-base/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/hash-base/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT", + "peer": true + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -11097,6 +15718,23 @@ "integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==", "license": "Apache-2.0" }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/htm": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/htm/-/htm-3.1.1.tgz", + "integrity": "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==", + "license": "Apache-2.0" + }, "node_modules/html-url-attributes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", @@ -11117,17 +15755,47 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "license": "MIT", + "peer": true, "dependencies": { - "agent-base": "6", - "debug": "4" + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC", + "peer": true + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" } }, "node_modules/husky": { @@ -11158,6 +15826,12 @@ "node": ">=0.10.0" } }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", + "license": "Apache-2.0" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -11207,23 +15881,8 @@ "engines": { "node": ">=6" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-in-the-middle": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.0.1.tgz", - "integrity": "sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.15.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^2.2.0", - "module-details-from-path": "^1.0.4" - }, - "engines": { - "node": ">=18" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/imurmurhash": { @@ -11236,6 +15895,19 @@ "node": ">=0.8.19" } }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -11258,6 +15930,13 @@ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, + "node_modules/int64-buffer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-1.1.0.tgz", + "integrity": "sha512-94smTCQOvigN4d/2R/YDjz8YVG0Sufvv2aAh8P5m42gwhCsDAJqnbNOrxJsrADuAFAA69Q/ptGzxvNcNuIJcvw==", + "license": "MIT", + "peer": true + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -11282,6 +15961,25 @@ "node": ">=12" } }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -11377,6 +16075,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT", + "optional": true + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -11557,6 +16262,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-my-ip-valid": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", + "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "license": "MIT", + "peer": true + }, + "node_modules/is-my-json-valid": { + "version": "2.20.6", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", + "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", + "license": "MIT", + "peer": true, + "dependencies": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^5.0.0", + "xtend": "^4.0.0" + } + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -11615,14 +16341,12 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "license": "MIT" }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", "license": "MIT", - "dependencies": { - "@types/estree": "*" - } + "peer": true }, "node_modules/is-regex": { "version": "1.2.1", @@ -11684,6 +16408,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-standalone-pwa": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-standalone-pwa/-/is-standalone-pwa-0.1.1.tgz", + "integrity": "sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "license": "MIT", + "peer": true + }, "node_modules/is-string": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", @@ -11792,6 +16537,30 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/iterator.prototype": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", @@ -11822,35 +16591,73 @@ "react": "^19.0.0" } }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "node_modules/jayson": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.3.0.tgz", + "integrity": "sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ==", + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" }, "engines": { - "node": ">= 10.13.0" + "node": ">=8" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/jayson/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/jayson/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=8.3.0" }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/jiti": { @@ -11863,9 +16670,9 @@ } }, "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -11880,6 +16687,22 @@ "node": ">=20" } }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-sha256": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.1.tgz", + "integrity": "sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg==", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11903,6 +16726,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -11932,10 +16756,17 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -11944,6 +16775,16 @@ "node": ">=6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -11960,6 +16801,29 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "peer": true, + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/katex": { "version": "0.16.33", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.33.tgz", @@ -11995,6 +16859,12 @@ "json-buffer": "3.0.1" } }, + "node_modules/keyvaluestorage-interface": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz", + "integrity": "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==", + "license": "MIT" + }, "node_modules/khroma": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", @@ -12354,24 +17224,42 @@ "node": ">=20.0.0" } }, - "node_modules/loader-runner": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", - "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.11.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node_modules/lit": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.0.tgz", + "integrity": "sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", + "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.5.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.3.tgz", + "integrity": "sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" } }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -12428,6 +17316,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/long": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.5.tgz", + "integrity": "sha512-e0r9YBBgNCq1D1o5Dp8FMH0N5hsFtXDBiVa0qoJPHpakvZkmDKPRoGffZJII/XsHvj9An9blm+cRJ01yQqU+Dw==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -12450,10 +17345,18 @@ "loose-envify": "cli.js" } }, + "node_modules/lru_map": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.4.1.tgz", + "integrity": "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==", + "license": "MIT", + "peer": true + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -12547,6 +17450,30 @@ "node": ">= 0.4" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", + "peer": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -12861,13 +17788,6 @@ "ce-la-react": "^0.3.2" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT", - "peer": true - }, "node_modules/mermaid": { "version": "11.15.0", "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", @@ -13643,6 +18563,27 @@ "node": ">=8.6" } }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT", + "peer": true + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -13677,6 +18618,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "license": "MIT" + }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -13690,15 +18643,6 @@ "node": "*" } }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/mlly": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", @@ -13711,12 +18655,6 @@ "ufo": "^1.6.1" } }, - "node_modules/module-details-from-path": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", - "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", - "license": "MIT" - }, "node_modules/motion": { "version": "12.35.2", "resolved": "https://registry.npmjs.org/motion/-/motion-12.35.2.tgz", @@ -13764,6 +18702,31 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", + "license": "(Apache-2.0 AND MIT)" + }, + "node_modules/mustache": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.0.0.tgz", + "integrity": "sha512-FJgjyX/IVkbXBXYUwH+OYwQKqWpFPLaLVESd70yHjSDunwzV2hZOoTBvPf4KLoxesUzzyfTH6F784Uqd7Wm5yA==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + }, + "engines": { + "npm": ">=1.4.0" + } + }, + "node_modules/nan": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.27.0.tgz", + "integrity": "sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==", + "license": "MIT", + "peer": true + }, "node_modules/nano-spawn": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", @@ -13817,13 +18780,70 @@ "dev": true, "license": "MIT" }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT", + "node_modules/near-abi": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/near-abi/-/near-abi-0.2.0.tgz", + "integrity": "sha512-kCwSf/3fraPU2zENK18sh+kKG4uKbEUEQdyWQkmW8ZofmLarObIz2+zAYjA1teDZLeMvEQew3UysnPDXgjneaA==", + "license": "(MIT AND Apache-2.0)", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.11" + } + }, + "node_modules/near-api-js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-5.1.1.tgz", + "integrity": "sha512-h23BGSKxNv8ph+zU6snicstsVK1/CTXsQz4LuGGwoRE24Hj424nSe4+/1tzoiC285Ljf60kPAqRCmsfv9etF2g==", + "license": "(MIT AND Apache-2.0)", + "peer": true, + "dependencies": { + "@near-js/accounts": "1.4.1", + "@near-js/crypto": "1.4.2", + "@near-js/keystores": "0.2.2", + "@near-js/keystores-browser": "0.2.2", + "@near-js/keystores-node": "0.1.2", + "@near-js/providers": "1.0.3", + "@near-js/signers": "0.2.2", + "@near-js/transactions": "1.3.3", + "@near-js/types": "0.3.1", + "@near-js/utils": "1.1.0", + "@near-js/wallet-account": "1.3.3", + "@noble/curves": "1.8.1", + "borsh": "1.0.0", + "depd": "2.0.0", + "http-errors": "1.7.2", + "near-abi": "0.2.0", + "node-fetch": "2.6.7" + } + }, + "node_modules/near-api-js/node_modules/borsh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz", + "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==", + "license": "Apache-2.0", "peer": true }, + "node_modules/near-api-js/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/next": { "version": "16.2.6", "resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz", @@ -13982,6 +19002,13 @@ "react-dom": ">= 16.0.0" } }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "license": "MIT", + "peer": true + }, "node_modules/node-exports-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", @@ -14031,24 +19058,55 @@ } } }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, "node_modules/node-gyp-build": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "license": "MIT", - "optional": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-mock-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", + "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", + "license": "MIT" + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, "license": "MIT" }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/nprogress": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", @@ -14183,6 +19241,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/onetime": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", @@ -14199,6 +19277,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-fetch": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.17.0.tgz", + "integrity": "sha512-PsbZR1wAPcG91eEthKhN+Zn92FMHxv+/faECIwjXdxfTODGSGegYv0sc1Olz+HYPvKOuoXfp+0pA2XVt2cI0Ig==", + "license": "MIT", + "dependencies": { + "openapi-typescript-helpers": "^0.1.0" + } + }, + "node_modules/openapi-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz", + "integrity": "sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "^1.34.6", + "ansi-colors": "^4.1.3", + "change-case": "^5.4.4", + "parse-json": "^8.3.0", + "supports-color": "^10.2.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "openapi-typescript": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.x" + } + }, + "node_modules/openapi-typescript-helpers": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.1.0.tgz", + "integrity": "sha512-OKTGPthhivLw/fHz6c3OPtg72vi86qaMlqbJuVJ23qOvQ+53uw1n7HdmkJFibloF7QEjDrDkzJiOJuockM/ljw==", + "license": "MIT" + }, + "node_modules/openapi-typescript/node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -14241,6 +19368,56 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT", + "optional": true + }, "node_modules/p-limit": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.0.tgz", @@ -14260,6 +19437,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -14275,6 +19453,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -14290,6 +19469,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -14298,6 +19478,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/package-manager-detector": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", @@ -14317,6 +19506,23 @@ "node": ">=6" } }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "license": "ISC", + "peer": true, + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse-entities": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", @@ -14342,6 +19548,37 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-numeric-range": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", @@ -14403,66 +19640,28 @@ "dev": true, "license": "MIT" }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.0.tgz", - "integrity": "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "license": "MIT" }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.14.0.tgz", - "integrity": "sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "node_modules/pbkdf2": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.6.tgz", + "integrity": "sha512-BT6eelPB1EyGHo8pC0o9Bl6k6SYVhKO1jEbd3lcTrtr7XHdjP8BW1YpfCV3G9Kwkxgattk+S5q2/RvuttCsS1g==", "license": "MIT", + "peer": true, "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.2" }, "engines": { - "node": ">=4" + "node": ">= 0.10" } }, "node_modules/picocolors": { @@ -14475,7 +19674,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -14497,6 +19695,43 @@ "node": ">=0.10" } }, + "node_modules/pino": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.0.0.tgz", + "integrity": "sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "slow-redact": "^0.3.0", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, "node_modules/pkg-types": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", @@ -14508,6 +19743,25 @@ "pathe": "^2.0.1" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/points-on-curve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", @@ -14574,45 +19828,6 @@ "node": ">=4" } }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/potpack": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", @@ -14764,14 +19979,28 @@ } } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT", - "engines": { - "node": ">=0.4.0" - } + "peer": true + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" }, "node_modules/promise-worker-transferable": { "version": "1.0.4", @@ -14999,12 +20228,59 @@ "prosemirror-transform": "^1.1.0" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "node_modules/protobufjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.1.tgz", + "integrity": "sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==", "license": "MIT" }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT", + "peer": true + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -15021,7 +20297,35 @@ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=6" + } + }, + "node_modules/pushdata-bitcoin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", + "integrity": "sha512-hw7rcYTJRAl4olM8Owe8x0fBuJJ+WGbMhQuLWOXEMN3PxPCKQHRkhfL+XG0+iXUmSHjkMmb3Ba55Mt21cZc9kQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "bitcoin-ops": "^1.3.0" + } + }, + "node_modules/qrcode": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", + "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" } }, "node_modules/qrcode.react": { @@ -15033,6 +20337,12 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, "node_modules/radix-ui": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", @@ -15248,6 +20558,12 @@ } } }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -15257,6 +20573,17 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "license": "MIT", + "peer": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "node_modules/react": { "version": "19.2.1", "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", @@ -15499,6 +20826,43 @@ } } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/recharts": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", @@ -15968,6 +21332,15 @@ "bare": ">=1.10.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -15977,18 +21350,11 @@ "node": ">=0.10.0" } }, - "node_modules/require-in-the-middle": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", - "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3" - }, - "engines": { - "node": ">=9.3.0 || >=8.10.0 <9.0.0" - } + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" }, "node_modules/resolve": { "version": "2.0.0-next.6", @@ -16048,56 +21414,87 @@ "dev": true, "license": "MIT" }, - "node_modules/robust-predicates": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", - "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", - "license": "Unlicense" - }, - "node_modules/rollup": { - "version": "4.60.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", - "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "license": "MIT", + "peer": true, "dependencies": { - "@types/estree": "1.0.8" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" }, - "bin": { - "rollup": "dist/bin/rollup" + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripple-address-codec": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-5.0.1.tgz", + "integrity": "sha512-JQHLKuVJV8lv9Qobmn4aUM2Dpv9WRRLKnNWfM8tN02fAbUtG8mUPsu9q9UYX8P76G4qzytEc5ZKMp/3JggNYmw==", + "license": "ISC", + "peer": true, + "dependencies": { + "@scure/base": "^2.0.0", + "@xrplf/isomorphic": "^1.0.2" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": ">= 18" + } + }, + "node_modules/ripple-address-codec/node_modules/@scure/base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.2.0.tgz", + "integrity": "sha512-b8XEupJibegiXV+tDUseI8oLQc8ei3d/4Jkb2RpbHh3MfE054ov3uIz2dhFkB3FI8iwYkEh0gGCApkrYggkPNg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ripple-binary-codec": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-2.8.0.tgz", + "integrity": "sha512-+NKnOi3hdzjm5dDpoZLUEaYon1jahPlSGnp3YrDoNMSR09ICEqgupN5wpEkPuqJvV75PF/g+W1QUwIXVzbEe7w==", + "license": "ISC", + "peer": true, + "dependencies": { + "@xrplf/isomorphic": "^1.0.2", + "bignumber.js": "^10.0.2", + "ripple-address-codec": "^5.0.1" }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.4", - "@rollup/rollup-android-arm64": "4.60.4", - "@rollup/rollup-darwin-arm64": "4.60.4", - "@rollup/rollup-darwin-x64": "4.60.4", - "@rollup/rollup-freebsd-arm64": "4.60.4", - "@rollup/rollup-freebsd-x64": "4.60.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", - "@rollup/rollup-linux-arm-musleabihf": "4.60.4", - "@rollup/rollup-linux-arm64-gnu": "4.60.4", - "@rollup/rollup-linux-arm64-musl": "4.60.4", - "@rollup/rollup-linux-loong64-gnu": "4.60.4", - "@rollup/rollup-linux-loong64-musl": "4.60.4", - "@rollup/rollup-linux-ppc64-gnu": "4.60.4", - "@rollup/rollup-linux-ppc64-musl": "4.60.4", - "@rollup/rollup-linux-riscv64-gnu": "4.60.4", - "@rollup/rollup-linux-riscv64-musl": "4.60.4", - "@rollup/rollup-linux-s390x-gnu": "4.60.4", - "@rollup/rollup-linux-x64-gnu": "4.60.4", - "@rollup/rollup-linux-x64-musl": "4.60.4", - "@rollup/rollup-openbsd-x64": "4.60.4", - "@rollup/rollup-openharmony-arm64": "4.60.4", - "@rollup/rollup-win32-arm64-msvc": "4.60.4", - "@rollup/rollup-win32-ia32-msvc": "4.60.4", - "@rollup/rollup-win32-x64-gnu": "4.60.4", - "@rollup/rollup-win32-x64-msvc": "4.60.4", - "fsevents": "~2.3.2" + "engines": { + "node": ">= 18" + } + }, + "node_modules/ripple-binary-codec/node_modules/bignumber.js": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-10.0.2.tgz", + "integrity": "sha512-E8Wp9O06QA6lneJ4aRUXKYf/1GIomqUEmUMwtIOMtDxf1U52ffJY+y7JBk/8wRafA8qOIqLnXQGqonYXZdBnFQ==", + "license": "MIT", + "peer": true + }, + "node_modules/ripple-keypairs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-2.0.0.tgz", + "integrity": "sha512-b5rfL2EZiffmklqZk1W+dvSy97v3V/C7936WxCCgDynaGPp7GE6R2XO7EU9O2LlM/z95rj870IylYnOQs+1Rag==", + "license": "ISC", + "peer": true, + "dependencies": { + "@noble/curves": "^1.0.0", + "@xrplf/isomorphic": "^1.0.0", + "ripple-address-codec": "^5.0.0" + }, + "engines": { + "node": ">= 16" } }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, "node_modules/rope-sequence": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", @@ -16122,12 +21519,66 @@ "points-on-path": "^0.2.1" } }, + "node_modules/rpc-websockets": { + "version": "9.3.9", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.9.tgz", + "integrity": "sha512-2iQDaTB4g5fDB2ihrTFSJSibCEuxaRi1q7qTW7ZO9/M5/TC+ToHA4D9/ffNLEbAoHNNrcdeP05oATNk44SKZXA==", + "license": "LGPL-3.0-only", + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^10.0.0", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^14.0.0", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^6.0.0" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/uuid": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", "license": "BSD-3-Clause" }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -16203,6 +21654,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -16215,62 +21675,26 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, - "node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/secp256k1": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.1.tgz", + "integrity": "sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==", + "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "elliptic": "^6.5.7", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.2.0" }, "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "node": ">=18.0.0" } }, - "node_modules/schema-utils/node_modules/ajv-keywords": { + "node_modules/secp256k1/node_modules/node-addon-api": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "peer": true + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" }, "node_modules/section-matter": { "version": "1.0.0", @@ -16297,6 +21721,12 @@ "node": ">=10" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/set-cookie-parser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", @@ -16351,6 +21781,13 @@ "node": ">= 0.4" } }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "license": "ISC", + "peer": true + }, "node_modules/sha.js": { "version": "2.4.12", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", @@ -16371,6 +21808,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/sharp": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", @@ -16543,6 +21993,23 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/slow-redact": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/slow-redact/-/slow-redact-0.3.2.tgz", + "integrity": "sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==", + "license": "MIT" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/socket.io-client": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", @@ -16571,6 +22038,46 @@ "node": ">=10.0.0" } }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "license": "MIT", + "peer": true, + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/sodium-native": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.3.3.tgz", @@ -16581,6 +22088,15 @@ "require-addon": "^1.1.0" } }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/sonner": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", @@ -16609,27 +22125,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/space-separated-tokens": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", @@ -16640,24 +22135,21 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, - "node_modules/stacktrace-parser": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", - "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", - "license": "MIT", - "dependencies": { - "type-fest": "^0.7.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/stats-gl": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz", @@ -16684,6 +22176,16 @@ "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", "license": "MIT" }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -16698,6 +22200,42 @@ "node": ">= 0.4" } }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -16893,6 +22431,12 @@ "inline-style-parser": "0.2.7" } }, + "node_modules/style-vendorizer": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/style-vendorizer/-/style-vendorizer-2.2.3.tgz", + "integrity": "sha512-/VDRsWvQAgspVy9eATN3z6itKTuyg+jW1q6UoTCQCFRqPDw8bi3E1hXIKnGw5LvXS2AQPuJ7Af4auTLYeBOLEg==", + "license": "MIT" + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -16922,6 +22466,15 @@ "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", "license": "MIT" }, + "node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -17002,93 +22555,20 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/terser": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", - "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" }, - "node_modules/terser-webpack-plugin": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz", - "integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==", + "node_modules/thread-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.2.0.tgz", + "integrity": "sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==", "license": "MIT", - "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@minify-html/node": { - "optional": true - }, - "@swc/core": { - "optional": true - }, - "@swc/css": { - "optional": true - }, - "@swc/html": { - "optional": true - }, - "clean-css": { - "optional": true - }, - "cssnano": { - "optional": true - }, - "csso": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "html-minifier-terser": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "postcss": { - "optional": true - }, - "uglify-js": { - "optional": true - } + "real-require": "^0.2.0" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true - }, "node_modules/three": { "version": "0.180.0", "resolved": "https://registry.npmjs.org/three/-/three-0.180.0.tgz", @@ -17133,6 +22613,31 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tiny-secp256k1": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.7.tgz", + "integrity": "sha512-eb+F6NabSnjbLwNoC+2o5ItbmP1kg7HliWue71JgLegQt6A5mTN8YbvTLCazdlg6e5SV6A+r8OGvZYskdlmhqQ==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/tiny-secp256k1/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT", + "peer": true + }, "node_modules/tinyexec": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", @@ -17217,6 +22722,16 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/toml": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", @@ -17301,6 +22816,12 @@ "node": ">=6.10" } }, + "node_modules/ts-mixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==", + "license": "MIT" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -17368,6 +22889,12 @@ "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", "license": "Unlicense" }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "license": "Unlicense" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -17381,15 +22908,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", - "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -17467,11 +22985,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typeforce": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==", + "license": "MIT", + "peer": true + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -17481,6 +23005,59 @@ "node": ">=14.17" } }, + "node_modules/ua-is-frozen": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz", + "integrity": "sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "license": "MIT", + "peer": true + }, + "node_modules/ua-parser-js": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-2.0.10.tgz", + "integrity": "sha512-t+3Ktbq0Ies2vaSezfOaWiolH4OigQIO1dk+1xDpOydB1COVPocVYOrEV5rqZ0kFY9XYG1v9LutCyMgYBpABcw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "AGPL-3.0-or-later", + "peer": true, + "dependencies": { + "detect-europe-js": "^0.1.2", + "is-standalone-pwa": "^0.1.1", + "ua-is-frozen": "^0.1.2" + }, + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", @@ -17493,6 +23070,25 @@ "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", "license": "MIT" }, + "node_modules/uint8array-tools": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", + "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.4.2" + } + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -17512,6 +23108,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.27.2.tgz", + "integrity": "sha512-cH9f42mHuljpNuoS47sWDDWXVxWnJgYCzHVUlr3tn7+HVx0L6QSO+VG5qgzT4kXkR2K8ZsReaT5bupam6RNAEQ==", + "license": "MIT" + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -17638,10 +23246,116 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unstorage": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.10", + "lru-cache": "^11.2.7", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.3" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1 || ^2 || ^3", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/unstorage/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, "funding": [ { "type": "opencollective", @@ -17678,6 +23392,13 @@ "punycode": "^2.1.0" } }, + "node_modules/uri-js-replace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz", + "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", + "dev": true, + "license": "MIT" + }, "node_modules/urijs": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", @@ -17690,7 +23411,6 @@ "integrity": "sha512-UuFgrlglgDn5ll6d5l7kl3nDb2Yx43qLUGcDq+7UNLZLtbNug0HZBb2Xodhgx2JZB1LqvU+dOGqLEeYUeZqsHg==", "hasInstallScript": true, "license": "MIT", - "optional": true, "dependencies": { "@types/w3c-web-usb": "^1.0.6", "node-addon-api": "^8.0.0", @@ -17705,7 +23425,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", "license": "MIT", - "optional": true, "engines": { "node": "^18 || ^20 || >= 21" } @@ -17762,6 +23481,20 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/utf-8-validate": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz", + "integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -17777,17 +23510,57 @@ "node": ">= 4" } }, - "node_modules/uuid": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.2.tgz", - "integrity": "sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], + "node_modules/uuid": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.2.tgz", + "integrity": "sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/uuid4": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid4/-/uuid4-2.0.3.tgz", + "integrity": "sha512-CTpAkEVXMNJl2ojgtpLXHgz23dh8z81u6/HEPiQFOvBc/c2pde6TVHmH4uwY0d/GLF3tb7+VDAj4+2eJaQSdZQ==", + "license": "ISC" + }, + "node_modules/valtio": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-2.1.7.tgz", + "integrity": "sha512-DwJhCDpujuQuKdJ2H84VbTjEJJteaSmqsuUltsfbfdbotVfNeTE4K/qc/Wi57I9x8/2ed4JNdjEna7O6PfavRg==", + "license": "MIT", + "dependencies": { + "proxy-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "react": ">=18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/varuint-bitcoin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-2.0.0.tgz", + "integrity": "sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==", "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" + "peer": true, + "dependencies": { + "uint8array-tools": "^0.0.8" } }, "node_modules/vaul": { @@ -17881,26 +23654,138 @@ "d3-timer": "^3.0.1" } }, - "node_modules/w3c-keyname": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" + "node_modules/viem": { + "version": "2.52.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.52.2.tgz", + "integrity": "sha512-HSU12p5aD/kAPZfrlbCUqdiP4P/c6hQ9AhfTS51VbLUQIjkWd1d5EjrCx/SCxZ0zhZVRn4Iv5X5WDqXPG8Ubew==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.9.1", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0", + "abitype": "1.2.3", + "isows": "1.0.7", + "ox": "0.14.29", + "ws": "8.20.1" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, - "node_modules/watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "node_modules/viem/node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", "license": "MIT", - "peer": true, "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "@noble/hashes": "1.8.0" }, "engines": { - "node": ">=10.13.0" + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/abitype": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", + "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/viem/node_modules/ox": { + "version": "0.14.29", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.29.tgz", + "integrity": "sha512-M5j87Ec4V99MQdRct/g09eWXW60g6zhHTUs1lr4deUtrPDnezBdCJTgKd7pxqTpSZBFveV0ALi9jMMuT1qKyNg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.2.3", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/web-namespaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", @@ -17928,97 +23813,6 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "license": "BSD-2-Clause" }, - "node_modules/webpack": { - "version": "5.107.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.1.tgz", - "integrity": "sha512-mvdIWxj/H6QsfgDdH9djne3a5dYcmEmtsXGESkypaGN5jXjF/b+9KDlmTDQ2TKlFUeA2fI9Y65kihD30JOdB+Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.16.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.28.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.21.4", - "es-module-lexer": "^2.1.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "loader-runner": "^4.3.2", - "mime-db": "^1.54.0", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.3", - "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.5.0", - "watchpack": "^2.5.1", - "webpack-sources": "^3.4.1" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-sources": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz", - "integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/webpack/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -18111,6 +23905,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, "node_modules/which-typed-array": { "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", @@ -18132,6 +23932,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wif": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/wif/-/wif-5.0.0.tgz", + "integrity": "sha512-iFzrC/9ne740qFbNjTZ2FciSRJlHIXoxqk/Y5EnE08QOXu1WjJyCCswwDTYbohAOEnlCtLaAAQBhyaLRFh2hMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "bs58check": "^4.0.0" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -18214,19 +24024,49 @@ "node": ">=0.4.0" } }, + "node_modules/xrpl": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/xrpl/-/xrpl-4.4.3.tgz", + "integrity": "sha512-vi2OjuNkiaP8nv1j+nqHp8GZwwEjO6Y8+j/OuVMg6M4LwXEwyHdIj33dlg7cyY1Lw5+jb9HqFOQvABhaywVbTQ==", + "license": "ISC", + "peer": true, + "dependencies": { + "@scure/bip32": "^1.3.1", + "@scure/bip39": "^1.2.1", + "@xrplf/isomorphic": "^1.0.1", + "@xrplf/secret-numbers": "^2.0.0", + "bignumber.js": "^9.0.0", + "eventemitter3": "^5.0.1", + "fast-json-stable-stringify": "^2.1.0", + "ripple-address-codec": "^5.0.0", + "ripple-binary-codec": "^2.5.0", + "ripple-keypairs": "^2.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.4" } }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -18244,6 +24084,154 @@ "url": "https://github.com/sponsors/eemeli" } }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", diff --git a/package.json b/package.json index cc710eb06..6ea180c5a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "start": "next start", "lint": "eslint .", "type-check": "tsc --noEmit", + "codegen": "openapi-typescript ${OPENAPI_URL:-http://localhost:8000/openapi.json} -o lib/api/generated/schema.d.ts", + "codegen:snapshot": "openapi-typescript openapi.snapshot.json -o lib/api/generated/schema.d.ts", "format": "prettier --write .", "format:check": "prettier --check .", "lint:fix": "eslint --fix .", @@ -26,6 +28,7 @@ }, "dependencies": { "@countrystatecity/countries": "^1.0.4", + "@creit.tech/stellar-wallets-kit": "^2.3.0", "@didit-protocol/sdk-web": "^0.1.8", "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", @@ -63,7 +66,6 @@ "@radix-ui/react-tooltip": "^1.2.8", "@react-three/drei": "^10.7.6", "@react-three/fiber": "^9.3.0", - "@sentry/nextjs": "^10.42.0", "@stellar/freighter-api": "^4.1.0", "@stellar/stellar-sdk": "^13.3.0", "@tabler/icons-react": "^3.36.1", @@ -127,6 +129,7 @@ "next-mdx-remote": "^6.0.0", "next-themes": "^0.4.6", "nextjs-toploader": "^3.9.17", + "openapi-fetch": "^0.17.0", "p-limit": "^7.3.0", "qrcode.react": "^4.2.0", "radix-ui": "^1.4.3", @@ -168,6 +171,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "husky": "^9.1.7", "lint-staged": "^16.1.2", + "openapi-typescript": "^7.13.0", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.6.14", "tailwindcss": "^4", diff --git a/sentry.edge.config.ts b/sentry.edge.config.ts deleted file mode 100644 index 3455f01d1..000000000 --- a/sentry.edge.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as Sentry from '@sentry/nextjs'; - -const dsn = process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN; - -if (dsn) { - Sentry.init({ - dsn, - sendDefaultPii: false, - tracesSampleRate: process.env.NODE_ENV === 'development' ? 1.0 : 0.1, - environment: process.env.NODE_ENV, - }); -} diff --git a/sentry.server.config.ts b/sentry.server.config.ts deleted file mode 100644 index 3455f01d1..000000000 --- a/sentry.server.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as Sentry from '@sentry/nextjs'; - -const dsn = process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN; - -if (dsn) { - Sentry.init({ - dsn, - sendDefaultPii: false, - tracesSampleRate: process.env.NODE_ENV === 'development' ? 1.0 : 0.1, - environment: process.env.NODE_ENV, - }); -} diff --git a/types/earnings.ts b/types/earnings.ts index 70b733ebb..87b606f83 100644 --- a/types/earnings.ts +++ b/types/earnings.ts @@ -1,23 +1,13 @@ +import type { Schemas } from '@/lib/api/openapi'; + export type EarningSource = | 'hackathons' | 'grants' | 'crowdfunding' | 'bounties'; -export interface EarningActivity { - source: EarningSource; - title: string; - amount: number; - currency: string; - occurredAt: string; -} +export type EarningActivity = Schemas['PublicEarningActivityDto']; -export type EarningsBreakdown = Record; +export type EarningsBreakdown = Schemas['EarningsBreakdownDto']; -export interface PublicEarningsResponse { - summary: { - totalEarned: number; - }; - breakdown: EarningsBreakdown; - activities: EarningActivity[]; -} +export type PublicEarningsResponse = Schemas['PublicEarningsResponseDto']; diff --git a/types/hackathon/core.ts b/types/hackathon/core.ts index 82cdd2a06..1bb5cc679 100644 --- a/types/hackathon/core.ts +++ b/types/hackathon/core.ts @@ -207,6 +207,8 @@ export type Hackathon = { status: | 'DRAFT' + // Between escrow publish-request and on-chain create_event settling. + | 'DRAFT_AWAITING_FUNDING' | 'UPCOMING' | 'ACTIVE' | 'JUDGING' diff --git a/types/hackathon/draft.ts b/types/hackathon/draft.ts index a9ad857ba..c76751248 100644 --- a/types/hackathon/draft.ts +++ b/types/hackathon/draft.ts @@ -21,7 +21,10 @@ export interface HackathonDraftData { export interface HackathonDraft { id: string; - status: 'draft'; + // The backend returns the real Hackathon status. A draft is normally DRAFT, + // but a hackathon mid-publish stays in the drafts list as + // DRAFT_AWAITING_FUNDING until its escrow op settles. + status: 'DRAFT' | 'DRAFT_AWAITING_FUNDING'; currentStep: number; completedSteps: string[]; data: HackathonDraftData; diff --git a/types/hackathon/rewards.ts b/types/hackathon/rewards.ts index 512eeef58..0c7c0955b 100644 --- a/types/hackathon/rewards.ts +++ b/types/hackathon/rewards.ts @@ -19,57 +19,3 @@ export interface AssignRanksResponse { }; message: string; } - -export interface HackathonEscrowData { - hackathonId?: string; - contractId: string; - escrowAddress: string; - transactionHash?: string; - totalFunds?: string; - balance: number; // Added for UI compatibility - currency?: string; - status?: 'active' | 'completed' | 'cancelled'; - isFunded?: boolean; // Added for UI compatibility - canUpdate?: boolean; // Added for UI compatibility - createdAt?: string; - updatedAt?: string; - milestones?: Array<{ - id?: string; - winnerId?: string; - rank?: number; - amount: string | number; - status: 'pending' | 'released' | 'disputed' | string; - description?: string; - receiver?: string; - evidence?: string; - flags?: { - approved: boolean; - disputed: boolean; - released: boolean; - resolved: boolean; - }; - }>; -} - -export interface CreateWinnerMilestonesRequest { - winners: Array<{ - participantId: string; - rank: number; - prizeAmount: string; - }>; -} - -export interface CreateWinnerMilestonesResponse { - success: true; - data: { - milestones: Array<{ - id: string; - winnerId: string; - rank: number; - amount: string; - status: string; - }>; - transactionHash: string; - }; - message: string; -} From a0d21b2b18cf1a2fc150270f82b182b3157c8cf6 Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Thu, 11 Jun 2026 08:48:21 +0100 Subject: [PATCH 02/11] chore: update package-lock.json dependencies --- package-lock.json | 78 +++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d4b3b816..69892e81f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2475,15 +2475,15 @@ } }, "node_modules/@next/env": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", - "integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.9.tgz", + "integrity": "sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.6.tgz", - "integrity": "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.9.tgz", + "integrity": "sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==", "cpu": [ "arm64" ], @@ -2497,9 +2497,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.6.tgz", - "integrity": "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.9.tgz", + "integrity": "sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==", "cpu": [ "x64" ], @@ -2513,9 +2513,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.6.tgz", - "integrity": "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.9.tgz", + "integrity": "sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==", "cpu": [ "arm64" ], @@ -2529,9 +2529,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.6.tgz", - "integrity": "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.9.tgz", + "integrity": "sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==", "cpu": [ "arm64" ], @@ -2545,9 +2545,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.6.tgz", - "integrity": "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.9.tgz", + "integrity": "sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==", "cpu": [ "x64" ], @@ -2561,9 +2561,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.6.tgz", - "integrity": "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.9.tgz", + "integrity": "sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==", "cpu": [ "x64" ], @@ -2577,9 +2577,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.6.tgz", - "integrity": "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.9.tgz", + "integrity": "sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==", "cpu": [ "arm64" ], @@ -2593,9 +2593,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.6.tgz", - "integrity": "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.9.tgz", + "integrity": "sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==", "cpu": [ "x64" ], @@ -18845,12 +18845,12 @@ } }, "node_modules/next": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz", - "integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==", + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.9.tgz", + "integrity": "sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==", "license": "MIT", "dependencies": { - "@next/env": "16.2.6", + "@next/env": "16.2.9", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -18864,14 +18864,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.2.6", - "@next/swc-darwin-x64": "16.2.6", - "@next/swc-linux-arm64-gnu": "16.2.6", - "@next/swc-linux-arm64-musl": "16.2.6", - "@next/swc-linux-x64-gnu": "16.2.6", - "@next/swc-linux-x64-musl": "16.2.6", - "@next/swc-win32-arm64-msvc": "16.2.6", - "@next/swc-win32-x64-msvc": "16.2.6", + "@next/swc-darwin-arm64": "16.2.9", + "@next/swc-darwin-x64": "16.2.9", + "@next/swc-linux-arm64-gnu": "16.2.9", + "@next/swc-linux-arm64-musl": "16.2.9", + "@next/swc-linux-x64-gnu": "16.2.9", + "@next/swc-linux-x64-musl": "16.2.9", + "@next/swc-win32-arm64-msvc": "16.2.9", + "@next/swc-win32-x64-msvc": "16.2.9", "sharp": "^0.34.5" }, "peerDependencies": { From 8f3a14bfcf51f824b489ba725d566763b640697c Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Thu, 11 Jun 2026 09:10:35 +0100 Subject: [PATCH 03/11] chore: update pre-push husky hook to perform full type-checks and production builds --- .husky/pre-push | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/.husky/pre-push b/.husky/pre-push index a0b25c772..abfcad5e9 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,23 +1,14 @@ - +#!/usr/bin/env sh +set -e echo "🚀 Running pre-push checks..." -# Run all tests (if you have them) -# echo "🧪 Running tests..." -# npm test - -# Run security audit -echo "🔒 Running security audit..." -npm audit --omit=dev --audit-level=high -# Run build check one more time -# echo "🏗️ Final build check..." -# npm run build +echo "🔒 Auditing dependencies (non-blocking)..." +npm audit --omit=dev --audit-level=high || true -# Check for any uncommitted changes if ! git diff-index --quiet HEAD --; then - echo "⚠️ Warning: You have uncommitted changes." - echo " Consider committing them before pushing." + echo "⚠️ You have uncommitted changes — they won't be included in this push." fi -echo "✅ Pre-push checks completed!" +echo "✅ Pre-push checks passed!" From 49fe90af8bb9e402fb4510be98bc720d50175015 Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Thu, 11 Jun 2026 09:32:00 +0100 Subject: [PATCH 04/11] refactor: remove DevelopmentStatusModal from global layout --- app/layout.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/layout.tsx b/app/layout.tsx index dfc4d5366..2c9509045 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -11,7 +11,6 @@ import { generateWebsiteStructuredData, } from '@/lib/structured-data'; import NextTopLoader from 'nextjs-toploader'; -import DevelopmentStatusModal from '@/components/DevelopmentStatusModal'; const inter = Inter({ variable: '--font-inter', @@ -97,7 +96,6 @@ export default function RootLayout({ {children} - From 3deb64c18649ba18d84522d50d64c6e08ae25068 Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Tue, 16 Jun 2026 01:24:00 +0100 Subject: [PATCH 05/11] feat: task-first Winners page, judging UX, private access, treasury receipts/send Winners: new task-first Winners section (pick winner per prize with engine default, inline stacking confirm, deliberate 'Don't award' + unawarded-funds acknowledgement); /rewards redirects to /winners; staged Pick -> Confirm -> Pay. Judging: slimmed Results tab to read-only standings + 'Go to Winners'; criterionId name fix; AI scorecards, recommendation thresholds, CSV judge import, tracks + custom questions wizard sections; validation + empty-state polish. Public: private + password access gate, community links, card private badge. Treasury: receipts + Send funds. Removed the stacking toggle from prize setup. Co-Authored-By: Claude Opus 4.8 --- .../[slug]/components/AccessGate.tsx | 83 + .../RegistrationQuestionsDialog.tsx | 191 ++ .../components/header/ActionButtons.tsx | 40 +- .../components/sidebar/CommunityLinks.tsx | 143 ++ .../components/sidebar/PoolAndAction.tsx | 200 +- .../[slug]/components/sidebar/index.tsx | 4 + .../components/tabs/contents/Overview.tsx | 182 +- app/(landing)/hackathons/[slug]/page.tsx | 19 +- .../preview/[orgId]/[draftId]/page.tsx | 7 +- .../hackathons/[hackathonId]/judging/page.tsx | 152 +- .../[hackathonId]/participants/page.tsx | 12 + .../hackathons/[hackathonId]/rewards/page.tsx | 316 +-- .../[hackathonId]/settings/page.tsx | 37 +- .../hackathons/[hackathonId]/winners/page.tsx | 338 +++ .../organizations/[id]/hackathons/page.tsx | 30 +- .../organizations/[id]/treasury/page.tsx | 37 +- .../treasury/receipts/[receiptId]/page.tsx | 197 ++ app/(landing)/organizations/layout.tsx | 15 +- .../submissions/[submissionId]/page.tsx | 37 + app/layout.tsx | 2 +- app/partners/contribute/[token]/page.tsx | 34 +- .../hackathons/submissions/SubmissionForm.tsx | 182 +- components/judge/JudgeAiAssist.tsx | 167 ++ .../landing-page/hackathon/HackathonCard.tsx | 16 +- .../organization/OrganizationSettings.tsx | 13 +- .../SubmissionModalHeader.tsx | 8 - .../HackathonPublishStatusBanner.tsx | 4 +- .../hackathons/ParticipantsGrid.tsx | 8 +- .../hackathons/ParticipantsTable.tsx | 9 +- .../hackathons/details/HackathonSidebar.tsx | 408 ++-- .../hackathons/judging/AiScorecardsPanel.tsx | 299 +++ .../judging/AllocationPreviewCard.tsx | 160 +- .../judging/ImportJudgesCsvDialog.tsx | 292 +++ .../judging/JudgingResultsTable.tsx | 8 + .../judging/OrganizerJudgesPanel.tsx | 32 +- .../judging/RecommendationThresholdsCard.tsx | 211 ++ .../new/FundingConfirmationModal.tsx | 10 +- .../hackathons/new/FundingProgressModal.tsx | 8 +- .../hackathons/new/GenerateWithAiDialog.tsx | 254 ++ .../new/HackathonTabsNavigation.tsx | 22 +- .../hackathons/new/NewHackathonTab.tsx | 89 +- .../new/RegenerateSectionButton.tsx | 80 + .../organization/hackathons/new/constants.ts | 4 + .../new/tabs/CustomQuestionsTab.tsx | 348 +++ .../hackathons/new/tabs/InfoTab.tsx | 24 +- .../hackathons/new/tabs/JudgingTab.tsx | 28 +- .../hackathons/new/tabs/ReviewTab.tsx | 2 +- .../hackathons/new/tabs/RewardsTab.tsx | 2090 ++++------------ .../hackathons/new/tabs/TimelineTab.tsx | 23 + .../hackathons/new/tabs/TracksTab.tsx | 316 +++ .../new/tabs/components/CategorySelection.tsx | 198 +- .../tabs/components/review/EscrowSummary.tsx | 10 +- .../review/HackathonPublishedModal.tsx | 24 +- .../tabs/components/review/PublishSection.tsx | 4 +- .../review/WalletConnectionWarning.tsx | 4 +- .../new/tabs/schemas/rewardsSchema.ts | 65 +- .../rewards/RewardPayoutProgressModal.tsx | 8 +- .../hackathons/rewards/RewardsPageContent.tsx | 320 +-- .../hackathons/rewards/RewardsPageHeader.tsx | 6 +- .../hackathons/rewards/SubmissionListItem.tsx | 133 +- .../hackathons/rewards/SubmissionsList.tsx | 9 +- .../hackathons/rewards/WinnersBoard.tsx | 327 +++ .../settings/AdvancedSettingsTab.tsx | 414 ++-- .../settings/AllocateContributionModal.tsx | 214 +- .../settings/PartnersSettingsTab.tsx | 33 +- .../settings/RewardsSettingsTab.tsx | 2 +- components/organization/tabs/MembersTab.tsx | 3 +- .../tabs/MembersTab/MemberCard.tsx | 142 +- .../tabs/MembersTab/PermissionsTable.tsx | 608 ++--- components/organization/treasury/AuditLog.tsx | 53 +- .../organization/treasury/PolicyEditor.tsx | 160 -- components/organization/treasury/Receipts.tsx | 125 + .../organization/treasury/SendFunds.tsx | 698 ++++++ .../organization/treasury/SpendInbox.tsx | 313 --- .../organization/treasury/WalletsSection.tsx | 334 ++- .../hackathons/api/use-generate-from-brief.ts | 42 + .../hackathons/api/use-regenerate-section.ts | 43 + features/hackathons/api/use-submission.ts | 1 + features/hackathons/index.ts | 10 + features/hackathons/types.ts | 24 + features/treasury/api.ts | 129 + features/treasury/index.ts | 13 + features/treasury/keys.ts | 11 + features/treasury/types.ts | 67 + features/treasury/use-treasury-receipts.ts | 68 + features/treasury/use-treasury-spend.ts | 62 +- features/treasury/use-treasury-wallets.ts | 24 +- hooks/hackathon/use-hackathon-queries.ts | 3 +- hooks/hackathon/use-hackathons-list.ts | 15 +- hooks/use-hackathon-draft.ts | 1 + hooks/use-hackathon-publish.ts | 3 - hooks/use-hackathon-step-save.ts | 2 + hooks/use-hackathon-steps.ts | 78 +- hooks/use-rank-assignment.ts | 96 - hooks/use-winners-board.ts | 101 + lib/api/api.ts | 39 + lib/api/generated/schema.d.ts | 2127 ++++++++++++++++- lib/api/hackathon.ts | 21 +- lib/api/hackathons.ts | 54 +- lib/api/hackathons/custom-questions.ts | 68 + lib/api/hackathons/index.ts | 3 - lib/api/hackathons/judging.ts | 5 + lib/api/hackathons/participants.ts | 9 +- lib/api/hackathons/partners.ts | 54 +- lib/api/hackathons/rewards.ts | 33 - lib/api/hackathons/tracks.ts | 18 + lib/api/hackathons/winners.ts | 107 + lib/api/judge.ts | 194 ++ lib/utils/effective-prize-tiers.ts | 46 + lib/utils/hackathon-form-transforms.ts | 6 + lib/utils/hackathon-step-validation.ts | 5 + openapi.snapshot.json | 2046 +++++++++------- types/hackathon/core.ts | 36 +- types/hackathon/index.ts | 1 - types/hackathon/rewards.ts | 21 - 115 files changed, 11628 insertions(+), 5456 deletions(-) create mode 100644 app/(landing)/hackathons/[slug]/components/AccessGate.tsx create mode 100644 app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx create mode 100644 app/(landing)/hackathons/[slug]/components/sidebar/CommunityLinks.tsx create mode 100644 app/(landing)/organizations/[id]/hackathons/[hackathonId]/winners/page.tsx create mode 100644 app/(landing)/organizations/[id]/treasury/receipts/[receiptId]/page.tsx create mode 100644 components/judge/JudgeAiAssist.tsx create mode 100644 components/organization/hackathons/judging/AiScorecardsPanel.tsx create mode 100644 components/organization/hackathons/judging/ImportJudgesCsvDialog.tsx create mode 100644 components/organization/hackathons/judging/RecommendationThresholdsCard.tsx create mode 100644 components/organization/hackathons/new/GenerateWithAiDialog.tsx create mode 100644 components/organization/hackathons/new/RegenerateSectionButton.tsx create mode 100644 components/organization/hackathons/new/tabs/CustomQuestionsTab.tsx create mode 100644 components/organization/hackathons/new/tabs/TracksTab.tsx create mode 100644 components/organization/hackathons/rewards/WinnersBoard.tsx delete mode 100644 components/organization/treasury/PolicyEditor.tsx create mode 100644 components/organization/treasury/Receipts.tsx create mode 100644 components/organization/treasury/SendFunds.tsx delete mode 100644 components/organization/treasury/SpendInbox.tsx create mode 100644 features/hackathons/api/use-generate-from-brief.ts create mode 100644 features/hackathons/api/use-regenerate-section.ts create mode 100644 features/treasury/use-treasury-receipts.ts delete mode 100644 hooks/use-rank-assignment.ts create mode 100644 hooks/use-winners-board.ts create mode 100644 lib/api/hackathons/custom-questions.ts create mode 100644 lib/api/hackathons/winners.ts create mode 100644 lib/utils/effective-prize-tiers.ts delete mode 100644 types/hackathon/rewards.ts diff --git a/app/(landing)/hackathons/[slug]/components/AccessGate.tsx b/app/(landing)/hackathons/[slug]/components/AccessGate.tsx new file mode 100644 index 000000000..47821b75f --- /dev/null +++ b/app/(landing)/hackathons/[slug]/components/AccessGate.tsx @@ -0,0 +1,83 @@ +'use client'; + +import { useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { Loader2, Lock } from 'lucide-react'; +import { toast } from 'sonner'; +import { BoundlessButton } from '@/components/buttons'; +import { Input } from '@/components/ui/input'; +import { verifyHackathonAccess } from '@/lib/api/hackathon'; + +/** + * Shown when a private hackathon's public page is opened without access. On a + * correct password we store a slug-keyed cookie and refresh; the server then + * reads the cookie, forwards the token, and renders the unlocked page. + */ +export default function AccessGate({ + slug, + name, + description, +}: { + slug: string; + name: string; + description?: string | null; +}) { + const router = useRouter(); + const [password, setPassword] = useState(''); + const [submitting, setSubmitting] = useState(false); + + const submit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!password.trim()) return; + setSubmitting(true); + try { + const { accessToken } = await verifyHackathonAccess( + slug, + password.trim() + ); + if (!accessToken) throw new Error('No access token'); + document.cookie = `hx_access_${slug}=${accessToken}; path=/; max-age=86400; samesite=lax`; + router.refresh(); + } catch (err) { + const msg = (err as { response?: { data?: { message?: string } } }) + ?.response?.data?.message; + toast.error(msg || 'That password is not right. Try again.'); + setSubmitting(false); + } + }; + + return ( +
+
+
+ +
+

{name}

+

+ {description || 'This hackathon is private.'} Enter the password to + view it. +

+
+ setPassword(e.target.value)} + placeholder='Password' + autoFocus + className='border-gray-700 bg-black text-center text-white' + /> + + + {submitting ? : null} + Unlock + + +
+
+
+ ); +} diff --git a/app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx b/app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx new file mode 100644 index 000000000..fc78e0540 --- /dev/null +++ b/app/(landing)/hackathons/[slug]/components/RegistrationQuestionsDialog.tsx @@ -0,0 +1,191 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; +import { toast } from 'sonner'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Textarea } from '@/components/ui/textarea'; +import { BoundlessButton } from '@/components/buttons'; +import { cn } from '@/lib/utils'; +import { + listPublicCustomQuestions, + type CustomQuestion, +} from '@/lib/api/hackathons/custom-questions'; + +/** + * Cached fetch of a hackathon's REGISTRATION-scope custom questions. The + * register buttons use this to decide whether registration needs a form + * (questions present) or can join directly (none). + */ +export function useRegistrationQuestions(slug: string) { + return useQuery({ + queryKey: ['hackathon', 'custom-questions', slug, 'REGISTRATION'], + queryFn: () => listPublicCustomQuestions(slug, 'REGISTRATION'), + enabled: !!slug, + staleTime: 60_000, + }); +} + +interface RegistrationQuestionsDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + questions: CustomQuestion[]; + submitting?: boolean; + /** Persist + join. Resolve to close the dialog; reject to keep it open. */ + onSubmit: (answers: Record) => Promise; +} + +export default function RegistrationQuestionsDialog({ + open, + onOpenChange, + questions, + submitting, + onSubmit, +}: RegistrationQuestionsDialogProps) { + const [answers, setAnswers] = useState>({}); + + // Reset the form each time the dialog opens so a cancelled attempt does not + // leak into the next one. + useEffect(() => { + if (open) setAnswers({}); + }, [open]); + + const setAnswer = (id: string, val: string | string[]) => + setAnswers(prev => ({ ...prev, [id]: val })); + + const handleSubmit = async () => { + for (const q of questions) { + if (!q.required) continue; + const v = answers[q.id]; + const empty = Array.isArray(v) + ? v.length === 0 + : !v || String(v).trim() === ''; + if (empty) { + toast.error(`"${q.label}" is required.`); + return; + } + } + await onSubmit(answers); + }; + + return ( + + + + A few questions before you register + + The organizer asks these when you join. + + + +
+ {questions.map(q => { + const options = Array.isArray(q.options) ? q.options : []; + const raw = answers[q.id]; + const strVal = typeof raw === 'string' ? raw : ''; + const arrVal = Array.isArray(raw) ? raw : []; + return ( +
+ + {q.type === 'LONG' ? ( +