From a1c8a4c0f6bd65f0abe52c21f02f3be6b43be54e Mon Sep 17 00:00:00 2001 From: Jared Pereira Date: Tue, 3 Mar 2026 15:55:45 -0500 Subject: [PATCH] Wire up Tinybird analytics to publication dashboard with Recharts Add real data fetching via SWR for traffic, referrers, and subscriber timeseries. Replace placeholder chart divs with Recharts AreaCharts, wire up live referrer data, and fix PostSelector to pass URL paths instead of titles to the analytics API. Co-Authored-By: Claude Opus 4.6 --- .../[command]/get_publication_analytics.ts | 78 ++ .../get_publication_subscribers_timeseries.ts | 79 ++ app/api/rpc/[command]/route.ts | 4 + .../[rkey]/PostHeader/PostHeader.tsx | 10 +- .../dashboard/PublicationAnalytics.tsx | 291 ++++- .../dashboard/PublicationDashboard.tsx | 6 +- components/PostListing.tsx | 8 +- lib/tinybird.ts | 235 ++++ package-lock.json | 1000 ++++++++++++++++- package.json | 2 + tinybird.config.mjs | 9 + 11 files changed, 1616 insertions(+), 106 deletions(-) create mode 100644 app/api/rpc/[command]/get_publication_analytics.ts create mode 100644 app/api/rpc/[command]/get_publication_subscribers_timeseries.ts create mode 100644 lib/tinybird.ts create mode 100644 tinybird.config.mjs diff --git a/app/api/rpc/[command]/get_publication_analytics.ts b/app/api/rpc/[command]/get_publication_analytics.ts new file mode 100644 index 00000000..94f9ea73 --- /dev/null +++ b/app/api/rpc/[command]/get_publication_analytics.ts @@ -0,0 +1,78 @@ +import { z } from "zod"; +import { makeRoute } from "../lib"; +import type { Env } from "./route"; +import { getIdentityData } from "actions/getIdentityData"; +import { tinybird } from "lib/tinybird"; + +export type GetPublicationAnalyticsReturnType = Awaited< + ReturnType<(typeof get_publication_analytics)["handler"]> +>; + +export const get_publication_analytics = makeRoute({ + route: "get_publication_analytics", + input: z.object({ + publication_uri: z.string(), + from: z.string().optional(), + to: z.string().optional(), + path: z.string().optional(), + }), + handler: async ( + { publication_uri, from, to, path }, + { supabase }: Pick, + ) => { + const identity = await getIdentityData(); + if (!identity?.atp_did || !identity.entitlements?.publication_analytics) { + return { error: "unauthorized" as const }; + } + + // Verify the user owns this publication + const { data: publication } = await supabase + .from("publications") + .select("*, publication_domains(*)") + .eq("uri", publication_uri) + .single(); + + if (!publication || publication.identity_did !== identity.atp_did) { + return { error: "not_found" as const }; + } + + const domain = publication.publication_domains?.[0]?.domain; + if (!domain) { + return { + result: { traffic: [], topReferrers: [], topPages: [] }, + }; + } + + const origin = `https://${domain}/`; + + const [trafficResult, referrersResult, pagesResult] = await Promise.all([ + tinybird.publicationTraffic.query({ + domain: origin, + ...(from ? { date_from: from } : {}), + ...(to ? { date_to: to } : {}), + ...(path ? { path } : {}), + }), + tinybird.publicationTopReferrers.query({ + domain: origin, + ...(from ? { date_from: from } : {}), + ...(to ? { date_to: to } : {}), + ...(path ? { path } : {}), + limit: 10, + }), + tinybird.publicationTopPages.query({ + domain: origin, + ...(from ? { date_from: from } : {}), + ...(to ? { date_to: to } : {}), + limit: 20, + }), + ]); + + return { + result: { + traffic: trafficResult.data, + topReferrers: referrersResult.data, + topPages: pagesResult.data, + }, + }; + }, +}); diff --git a/app/api/rpc/[command]/get_publication_subscribers_timeseries.ts b/app/api/rpc/[command]/get_publication_subscribers_timeseries.ts new file mode 100644 index 00000000..4cd860f1 --- /dev/null +++ b/app/api/rpc/[command]/get_publication_subscribers_timeseries.ts @@ -0,0 +1,79 @@ +import { z } from "zod"; +import { makeRoute } from "../lib"; +import type { Env } from "./route"; +import { getIdentityData } from "actions/getIdentityData"; + +export type GetPublicationSubscribersTimeseriesReturnType = Awaited< + ReturnType<(typeof get_publication_subscribers_timeseries)["handler"]> +>; + +export const get_publication_subscribers_timeseries = makeRoute({ + route: "get_publication_subscribers_timeseries", + input: z.object({ + publication_uri: z.string(), + from: z.string().optional(), + to: z.string().optional(), + }), + handler: async ( + { publication_uri, from, to }, + { supabase }: Pick, + ) => { + const identity = await getIdentityData(); + if (!identity?.atp_did || !identity.entitlements?.publication_analytics) { + return { error: "unauthorized" as const }; + } + + // Verify ownership + const { data: publication } = await supabase + .from("publications") + .select("uri, identity_did") + .eq("uri", publication_uri) + .single(); + + if (!publication || publication.identity_did !== identity.atp_did) { + return { error: "not_found" as const }; + } + + let query = supabase + .from("publication_subscriptions") + .select("created_at") + .eq("publication", publication_uri) + .order("created_at", { ascending: true }); + + if (from) { + query = query.gte("created_at", from); + } + if (to) { + query = query.lte("created_at", to); + } + + const { data: subscriptions } = await query; + + // Bucket subscriptions by day and compute cumulative count + const dailyCounts: Record = {}; + for (const sub of subscriptions || []) { + const day = sub.created_at.slice(0, 10); + dailyCounts[day] = (dailyCounts[day] || 0) + 1; + } + + const days = Object.keys(dailyCounts).sort(); + let cumulative = 0; + + // If we have a from filter, get the count of subscriptions before that date + if (from) { + const { count } = await supabase + .from("publication_subscriptions") + .select("*", { count: "exact", head: true }) + .eq("publication", publication_uri) + .lt("created_at", from); + cumulative = count || 0; + } + + const timeseries = days.map((day) => { + cumulative += dailyCounts[day]; + return { day, total_subscribers: cumulative }; + }); + + return { result: { timeseries } }; + }, +}); diff --git a/app/api/rpc/[command]/route.ts b/app/api/rpc/[command]/route.ts index ebb2af14..05912055 100644 --- a/app/api/rpc/[command]/route.ts +++ b/app/api/rpc/[command]/route.ts @@ -17,6 +17,8 @@ import { get_profile_data } from "./get_profile_data"; import { get_user_recommendations } from "./get_user_recommendations"; import { get_hot_feed } from "./get_hot_feed"; import { get_document_interactions } from "./get_document_interactions"; +import { get_publication_analytics } from "./get_publication_analytics"; +import { get_publication_subscribers_timeseries } from "./get_publication_subscribers_timeseries"; let supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, @@ -47,6 +49,8 @@ let Routes = [ get_user_recommendations, get_hot_feed, get_document_interactions, + get_publication_analytics, + get_publication_subscribers_timeseries, ]; export async function POST( req: Request, diff --git a/app/lish/[did]/[publication]/[rkey]/PostHeader/PostHeader.tsx b/app/lish/[did]/[publication]/[rkey]/PostHeader/PostHeader.tsx index 1159683a..d6d3da77 100644 --- a/app/lish/[did]/[publication]/[rkey]/PostHeader/PostHeader.tsx +++ b/app/lish/[did]/[publication]/[rkey]/PostHeader/PostHeader.tsx @@ -123,11 +123,11 @@ export const PostHeaderLayout = (props: {
{props.pubLink}
-

- {props.postTitle ? props.postTitle : "Untitled"} -

+ {props.postTitle && ( +

+ {props.postTitle} +

+ )} {props.postDescription ? (
{props.postDescription} diff --git a/app/lish/[did]/[publication]/dashboard/PublicationAnalytics.tsx b/app/lish/[did]/[publication]/dashboard/PublicationAnalytics.tsx index 8230c9b8..e8fd4097 100644 --- a/app/lish/[did]/[publication]/dashboard/PublicationAnalytics.tsx +++ b/app/lish/[did]/[publication]/dashboard/PublicationAnalytics.tsx @@ -6,31 +6,116 @@ import { useMemo, useState } from "react"; import { useLocalizedDate } from "src/hooks/useLocalizedDate"; import type { DateRange } from "react-day-picker"; import { usePublicationData } from "./PublicationSWRProvider"; -import { - Combobox, - ComboboxResult, - useComboboxState, -} from "components/Combobox"; +import { Combobox, ComboboxResult } from "components/Combobox"; import { useIsPro } from "src/hooks/useEntitlement"; +import { callRPC } from "app/api/rpc/client"; +import useSWR from "swr"; +import { + AreaChart, + Area, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, +} from "recharts"; + +type ReferrerType = { referrer_host: string; pageviews: number }; -type referrorType = { iconSrc: string; name: string; viewCount: string }; -let refferors = [ - { iconSrc: "", name: "Bluesky", viewCount: "12k" }, - { iconSrc: "", name: "Reddit", viewCount: "1.2k" }, - { iconSrc: "", name: "X", viewCount: "583" }, - { iconSrc: "", name: "Google", viewCount: "12" }, -]; +function fillDailyGaps( + data: T[], + fill: (day: string) => T, + from?: Date, + to?: Date, +): T[] { + let start = + from || (data.length > 0 ? new Date(data[0].day) : null); + let end = + to || (data.length > 0 ? new Date(data[data.length - 1].day) : null); + if (!start || !end) return data; + + let lookup = new Map(data.map((d) => [d.day, d])); + let result: T[] = []; + let cursor = new Date(start); + cursor.setHours(0, 0, 0, 0); + let endDate = new Date(end); + endDate.setHours(0, 0, 0, 0); + + while (cursor <= endDate) { + let key = cursor.toISOString().slice(0, 10); + result.push(lookup.get(key) ?? fill(key)); + cursor.setDate(cursor.getDate() + 1); + } + return result; +} -export const PublicationAnalytics = () => { +export const PublicationAnalytics = (props: { + showPageBackground: boolean; +}) => { let isPro = useIsPro(); let { data: publication } = usePublicationData(); let [dateRange, setDateRange] = useState({ from: undefined }); - let [selectedPost, setSelectedPost] = useState(undefined); + let [selectedPost, setSelectedPost] = useState< + { title: string; path: string } | undefined + >(undefined); let [selectedReferror, setSelectedReferror] = useState< - referrorType | undefined + ReferrerType | undefined >(undefined); + let publicationUri = publication?.publication?.uri; + + let { data: analyticsData } = useSWR( + publicationUri + ? [ + "publication-analytics", + publicationUri, + dateRange.from?.toISOString(), + dateRange.to?.toISOString(), + selectedPost?.path, + ] + : null, + async () => { + let res = await callRPC("get_publication_analytics", { + publication_uri: publicationUri!, + ...(dateRange.from ? { from: dateRange.from.toISOString() } : {}), + ...(dateRange.to ? { to: dateRange.to.toISOString() } : {}), + ...(selectedPost ? { path: `/${selectedPost.path}` } : {}), + }); + return res?.result; + }, + ); + + let { data: subscribersData } = useSWR( + publicationUri + ? [ + "publication-subscribers-timeseries", + publicationUri, + dateRange.from?.toISOString(), + dateRange.to?.toISOString(), + ] + : null, + async () => { + let res = await callRPC("get_publication_subscribers_timeseries", { + publication_uri: publicationUri!, + ...(dateRange.from ? { from: dateRange.from.toISOString() } : {}), + ...(dateRange.to ? { to: dateRange.to.toISOString() } : {}), + }); + return res?.result; + }, + ); + + let filledTraffic = useMemo( + () => + fillDailyGaps( + analyticsData?.traffic || [], + (day) => ({ day, pageviews: 0 }), + dateRange.from, + dateRange.to, + ), + [analyticsData?.traffic, dateRange.from, dateRange.to], + ); + if (!isPro) return (
@@ -40,7 +125,18 @@ export const PublicationAnalytics = () => { return (
-
+

Subscribers

{ pubStartDate={publication?.publication?.indexed_at} />
-
+
-
+

Traffic

@@ -63,7 +170,10 @@ export const PublicationAnalytics = () => { {selectedReferror && ( <> -
{selectedReferror.name}
+
+ {" "} + {selectedReferror.referrer_host} +
)}
@@ -74,9 +184,9 @@ export const PublicationAnalytics = () => { />
-
+ {" "} @@ -86,54 +196,139 @@ export const PublicationAnalytics = () => { ); }; +const SubscribersChart = (props: { + data: { day: string; total_subscribers: number }[]; +}) => { + if (props.data.length === 0) { + return ( +
+ No subscriber data +
+ ); + } + return ( +
+ + + + + + + + + +
+ ); +}; + +const TrafficChart = (props: { + data: { day: string; pageviews: number }[]; +}) => { + if (props.data.length === 0) { + return ( +
+ No traffic data +
+ ); + } + return ( +
+ + + + + + + + + +
+ ); +}; + const PostSelector = (props: { - selectedPost: string | undefined; - setSelectedPost: (s: string | undefined) => void; + selectedPost: { title: string; path: string } | undefined; + setSelectedPost: (s: { title: string; path: string } | undefined) => void; }) => { let { data } = usePublicationData(); let { documents } = data || {}; + let posts = useMemo( + () => + documents?.map((doc) => ({ + title: doc.record.title, + path: doc.record.path || "", + })), + [documents], + ); + let [highlighted, setHighlighted] = useState(undefined); let [searchValue, setSearchValue] = useState(""); - let open = useComboboxState((s) => s.open); - let posts = documents?.map((doc) => doc.record.title); - let filteredPosts = useMemo( + let postTitles = posts?.map((p) => p.title); + let filteredTitles = useMemo( () => - posts && - posts.filter((post) => - post.toLowerCase().includes(searchValue.toLowerCase()), + postTitles && + postTitles.filter((title) => + title.toLowerCase().includes(searchValue.toLowerCase()), ), - [searchValue, posts], + [searchValue, postTitles], ); - let filteredPostsWithClear = ["All Posts", ...(filteredPosts || [])]; + let filteredTitlesWithClear = ["All Posts", ...(filteredTitles || [])]; return ( - {props.selectedPost ?? "All Posts"} + {props.selectedPost?.title ?? "All Posts"} } - results={filteredPostsWithClear || []} + results={filteredTitlesWithClear || []} highlighted={highlighted} setHighlighted={setHighlighted} onSelect={() => { - props.setSelectedPost(highlighted); + if (highlighted === "All Posts" || !highlighted) { + props.setSelectedPost(undefined); + } else { + let post = posts?.find((p) => p.title === highlighted); + props.setSelectedPost(post); + } }} sideOffset={2} searchValue={searchValue} setSearchValue={setSearchValue} showSearch > - {filteredPostsWithClear.map((post) => { - if (post === "All Posts") + {filteredTitlesWithClear.map((title) => { + if (title === "All Posts") return ( <> { props.setSelectedPost(undefined); }} @@ -142,22 +337,23 @@ const PostSelector = (props: { > All Posts - {filteredPosts && filteredPosts.length !== 0 && ( + {filteredTitles && filteredTitles.length !== 0 && (
)} ); return ( { + let post = posts?.find((p) => p.title === title); props.setSelectedPost(post); }} highlighted={highlighted} setHighlighted={setHighlighted} > - {post} + {title} ); })} @@ -250,9 +446,9 @@ const DateRangeSelector = (props: { }; const TopReferrors = (props: { - refferors: referrorType[]; - setSelectedReferror: (ref: referrorType) => void; - selectedReferror: referrorType | undefined; + refferors: ReferrerType[]; + setSelectedReferror: (ref: ReferrerType) => void; + selectedReferror: ReferrerType | undefined; }) => { return (
@@ -261,17 +457,16 @@ const TopReferrors = (props: { return ( <>
diff --git a/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx b/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx index ed6b4a9c..8547ff7b 100644 --- a/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx +++ b/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx @@ -74,7 +74,11 @@ export default function PublicationDashboard({ controls: null, }, Analytics: { - content: , + content: ( + + ), controls: null, }, }} diff --git a/components/PostListing.tsx b/components/PostListing.tsx index 3004461c..6bf48ee0 100644 --- a/components/PostListing.tsx +++ b/components/PostListing.tsx @@ -133,9 +133,11 @@ export const PostListing = (props: Post) => {
)}
-

- {postRecord.title} -

+ {postRecord.title && ( +

+ {postRecord.title} +

+ )}

{postRecord.description} diff --git a/lib/tinybird.ts b/lib/tinybird.ts new file mode 100644 index 00000000..e9457032 --- /dev/null +++ b/lib/tinybird.ts @@ -0,0 +1,235 @@ +/** + * Tinybird Definitions + * + * Datasource matching the Vercel Web Analytics drain schema, + * endpoint pipes for publication analytics, and typed client. + * + * Column names use camelCase to match the JSON keys sent by + * Vercel's analytics drain (NDJSON format). + */ + +import { + defineDatasource, + defineEndpoint, + Tinybird, + node, + t, + p, + engine, + type InferRow, + type InferParams, + type InferOutputRow, +} from "@tinybirdco/sdk"; + +// ============================================================================ +// Datasources +// ============================================================================ + +/** + * Vercel Web Analytics drain events. + * Column names match the Vercel drain JSON keys exactly. + * `timestamp` is stored as UInt64 (Unix millis) as sent by Vercel. + */ +export const analyticsEvents = defineDatasource("analytics_events", { + description: "Vercel Web Analytics drain events", + schema: { + timestamp: t.uint64(), + eventType: t.string().lowCardinality(), + eventName: t.string().default(""), + eventData: t.string().default(""), + sessionId: t.uint64(), + deviceId: t.uint64(), + origin: t.string(), + path: t.string(), + referrer: t.string().default(""), + queryParams: t.string().default(""), + route: t.string().default(""), + country: t.string().lowCardinality().default(""), + region: t.string().default(""), + city: t.string().default(""), + osName: t.string().lowCardinality().default(""), + osVersion: t.string().default(""), + clientName: t.string().lowCardinality().default(""), + clientType: t.string().lowCardinality().default(""), + clientVersion: t.string().default(""), + deviceType: t.string().lowCardinality().default(""), + deviceBrand: t.string().default(""), + deviceModel: t.string().default(""), + browserEngine: t.string().default(""), + browserEngineVersion: t.string().default(""), + sdkVersion: t.string().default(""), + sdkName: t.string().default(""), + sdkVersionFull: t.string().default(""), + vercelEnvironment: t.string().lowCardinality().default(""), + vercelUrl: t.string().default(""), + flags: t.string().default(""), + deployment: t.string().default(""), + schema: t.string().default(""), + projectId: t.string().default(""), + ownerId: t.string().default(""), + dataSourceName: t.string().default(""), + }, + engine: engine.mergeTree({ + sortingKey: ["origin", "timestamp"], + partitionKey: "toYYYYMM(fromUnixTimestamp64Milli(timestamp))", + }), +}); + +export type AnalyticsEventsRow = InferRow; + +// ============================================================================ +// Endpoints +// ============================================================================ + +/** + * publication_traffic – daily pageview time series for a publication domain. + */ +export const publicationTraffic = defineEndpoint("publication_traffic", { + description: "Daily pageview time series for a publication domain", + params: { + domain: p.string(), + date_from: p.string().optional(), + date_to: p.string().optional(), + path: p.string().optional(), + }, + nodes: [ + node({ + name: "endpoint", + sql: ` + SELECT + toDate(fromUnixTimestamp64Milli(timestamp)) AS day, + count() AS pageviews + FROM analytics_events + WHERE eventType = 'pageview' + AND origin = {{String(domain)}} + {% if defined(date_from) %} + AND fromUnixTimestamp64Milli(timestamp) >= parseDateTimeBestEffort({{String(date_from)}}) + {% end %} + {% if defined(date_to) %} + AND fromUnixTimestamp64Milli(timestamp) <= parseDateTimeBestEffort({{String(date_to)}}) + {% end %} + {% if defined(path) %} + AND path = {{String(path)}} + {% end %} + GROUP BY day + ORDER BY day ASC + `, + }), + ], + output: { + day: t.date(), + pageviews: t.uint64(), + }, +}); + +export type PublicationTrafficParams = InferParams; +export type PublicationTrafficOutput = InferOutputRow; + +/** + * publication_top_referrers – top referring domains for a publication. + */ +export const publicationTopReferrers = defineEndpoint( + "publication_top_referrers", + { + description: "Top referrers for a publication domain", + params: { + domain: p.string(), + date_from: p.string().optional(), + date_to: p.string().optional(), + path: p.string().optional(), + limit: p.int32().optional(10), + }, + nodes: [ + node({ + name: "endpoint", + sql: ` + SELECT + domain(referrer) AS referrer_host, + count() AS pageviews + FROM analytics_events + WHERE eventType = 'pageview' + AND origin = {{String(domain)}} + AND referrer != '' + AND domain(referrer) != domain({{String(domain)}}) + {% if defined(date_from) %} + AND fromUnixTimestamp64Milli(timestamp) >= parseDateTimeBestEffort({{String(date_from)}}) + {% end %} + {% if defined(date_to) %} + AND fromUnixTimestamp64Milli(timestamp) <= parseDateTimeBestEffort({{String(date_to)}}) + {% end %} + {% if defined(path) %} + AND path = {{String(path)}} + {% end %} + GROUP BY referrer_host + ORDER BY pageviews DESC + LIMIT {{Int32(limit, 10)}} + `, + }), + ], + output: { + referrer_host: t.string(), + pageviews: t.uint64(), + }, + }, +); + +export type PublicationTopReferrersParams = InferParams< + typeof publicationTopReferrers +>; +export type PublicationTopReferrersOutput = InferOutputRow< + typeof publicationTopReferrers +>; + +/** + * publication_top_pages – top pages by pageviews for a publication. + */ +export const publicationTopPages = defineEndpoint("publication_top_pages", { + description: "Top pages for a publication domain", + params: { + domain: p.string(), + date_from: p.string().optional(), + date_to: p.string().optional(), + limit: p.int32().optional(10), + }, + nodes: [ + node({ + name: "endpoint", + sql: ` + SELECT + path, + count() AS pageviews + FROM analytics_events + WHERE eventType = 'pageview' + AND origin = {{String(domain)}} + {% if defined(date_from) %} + AND fromUnixTimestamp64Milli(timestamp) >= parseDateTimeBestEffort({{String(date_from)}}) + {% end %} + {% if defined(date_to) %} + AND fromUnixTimestamp64Milli(timestamp) <= parseDateTimeBestEffort({{String(date_to)}}) + {% end %} + GROUP BY path + ORDER BY pageviews DESC + LIMIT {{Int32(limit, 10)}} + `, + }), + ], + output: { + path: t.string(), + pageviews: t.uint64(), + }, +}); + +export type PublicationTopPagesParams = InferParams; +export type PublicationTopPagesOutput = InferOutputRow< + typeof publicationTopPages +>; + +// ============================================================================ +// Client +// ============================================================================ + +export const tinybird = new Tinybird({ + datasources: { analyticsEvents }, + pipes: { publicationTraffic, publicationTopReferrers, publicationTopPages }, + devMode: false, +}); diff --git a/package-lock.json b/package-lock.json index 00070e21..8cf00cf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "@rocicorp/undo": "^0.2.1", "@supabase/ssr": "^0.3.0", "@supabase/supabase-js": "^2.43.2", + "@tinybirdco/sdk": "^0.0.55", "@tiptap/core": "^2.11.5", "@types/mdx": "^2.0.13", "@vercel/analytics": "^1.5.0", @@ -66,6 +67,7 @@ "react-day-picker": "^9.3.0", "react-dom": "19.2.1", "react-use-measure": "^2.1.1", + "recharts": "^3.7.0", "redlock": "^5.0.0-beta.2", "rehype-parse": "^9.0.0", "rehype-remark": "^10.0.0", @@ -946,6 +948,27 @@ "linux" ] }, + "node_modules/@clack/core": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.0.1.tgz", + "integrity": "sha512-WKeyK3NOBwDOzagPR5H08rFk9D/WuN705yEbuZvKqlkmoLM2woKtXb10OO2k1NoSU4SFG947i2/SCYh+2u5e4g==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@clack/prompts": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.0.1.tgz", + "integrity": "sha512-/42G73JkuYdyWZ6m8d/CJtBrGl1Hegyc7Fy78m5Ob+jF85TOUmLR5XLce/U3LxYAw0kJ8CT5aI99RIvPHcGp/Q==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.0.1", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, "node_modules/@cloudflare/kv-asset-handler": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.2.tgz", @@ -7120,6 +7143,42 @@ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@remirror/core-constants": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", @@ -7226,6 +7285,18 @@ "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==" }, + "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/@supabase/auth-js": { "version": "2.64.2", "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.64.2.tgz", @@ -7535,86 +7606,584 @@ "tslib" ], "cpu": [ - "wasm32" + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@emnapi/wasi-threads": "^1.0.4", + "@napi-rs/wasm-runtime": "^0.2.12", + "@tybys/wasm-util": "^0.10.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.13.tgz", + "integrity": "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.13.tgz", + "integrity": "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide/node_modules/tar": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", + "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz", + "integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.13", + "@tailwindcss/oxide": "4.1.13", + "postcss": "^8.4.41", + "tailwindcss": "4.1.13" + } + }, + "node_modules/@tinybirdco/sdk": { + "version": "0.0.55", + "resolved": "https://registry.npmjs.org/@tinybirdco/sdk/-/sdk-0.0.55.tgz", + "integrity": "sha512-LzOocxjdGy1nXD+03zfY3C4ZQSOnH1CbarMajUnwOwi4OwDeJIEA3nohyPxWAxgXXRgH7kfhM/tokavhP+DH0A==", + "license": "MIT", + "dependencies": { + "@clack/prompts": "^1.0.0", + "chokidar": "^4.0.0", + "commander": "^12.0.0", + "dotenv": "^16.0.0", + "esbuild": "^0.24.0", + "picocolors": "^1.1.1", + "zod": "^3.25.0" + }, + "bin": { + "tinybird": "bin/tinybird.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/darwin-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" ], - "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.5", - "@emnapi/runtime": "^1.4.5", - "@emnapi/wasi-threads": "^1.0.4", - "@napi-rs/wasm-runtime": "^0.2.12", - "@tybys/wasm-util": "^0.10.0", - "tslib": "^2.8.0" - }, + "os": [ + "win32" + ], "engines": { - "node": ">=14.0.0" + "node": ">=18" } }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.13.tgz", - "integrity": "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==", + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", "cpu": [ - "arm64" + "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.13.tgz", - "integrity": "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==", + "node_modules/@tinybirdco/sdk/node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@tailwindcss/oxide/node_modules/tar": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", - "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", - "dev": true, - "license": "BlueOak-1.0.0", + "node_modules/@tinybirdco/sdk/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" + "readdirp": "^4.0.1" }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", "engines": { "node": ">=18" } }, - "node_modules/@tailwindcss/postcss": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz", - "integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==", - "dev": true, + "node_modules/@tinybirdco/sdk/node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.13", - "@tailwindcss/oxide": "4.1.13", - "postcss": "^8.4.41", - "tailwindcss": "4.1.13" + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, + "node_modules/@tinybirdco/sdk/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/@tiptap/core": { @@ -7731,6 +8300,69 @@ "@types/node": "*" } }, + "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-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-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-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-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-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-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/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -7929,6 +8561,12 @@ "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", @@ -9429,6 +10067,127 @@ "node": ">=0.12" } }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -9542,6 +10301,12 @@ "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "license": "MIT" }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/decode-named-character-reference": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", @@ -9689,6 +10454,18 @@ "node": ">=0.10.0" } }, + "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/dreamopt": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz", @@ -10502,6 +11279,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-toolkit": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.0.tgz", + "integrity": "sha512-RArCX+Zea16+R1jg4mH223Z8p/ivbJjIkU3oC6ld2bdUfmDxiCkFYSi9zLOR2anucWJUeH4Djnzgd0im0nD3dw==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/es5-ext": { "version": "0.10.64", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", @@ -12705,6 +13492,15 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/intl-messageformat": { "version": "10.7.16", "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.16.tgz", @@ -16579,9 +17375,31 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-remove-scroll": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", @@ -16746,6 +17564,42 @@ "node": ">= 12.13.0" } }, + "node_modules/recharts": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.7.0.tgz", + "integrity": "sha512-l2VCsy3XXeraxIID9fx23eCb6iCBsxUQDnE8tWm6DFdszVAO7WVY/ChAD9wVit01y6B2PMupYiMmQwhgPHc9Ew==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "1.x.x || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, "node_modules/recma-build-jsx": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", @@ -16839,6 +17693,21 @@ "node": ">=12" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -17103,6 +17972,12 @@ "node": ">=8.6.0" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -17674,8 +18549,7 @@ "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, "node_modules/sonic-boom": { "version": "3.8.1", @@ -18146,6 +19020,12 @@ "next-tick": "1" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -18856,6 +19736,28 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "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", diff --git a/package.json b/package.json index 83cd4550..1b94597c 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@rocicorp/undo": "^0.2.1", "@supabase/ssr": "^0.3.0", "@supabase/supabase-js": "^2.43.2", + "@tinybirdco/sdk": "^0.0.55", "@tiptap/core": "^2.11.5", "@types/mdx": "^2.0.13", "@vercel/analytics": "^1.5.0", @@ -77,6 +78,7 @@ "react-day-picker": "^9.3.0", "react-dom": "19.2.1", "react-use-measure": "^2.1.1", + "recharts": "^3.7.0", "redlock": "^5.0.0-beta.2", "rehype-parse": "^9.0.0", "rehype-remark": "^10.0.0", diff --git a/tinybird.config.mjs b/tinybird.config.mjs new file mode 100644 index 00000000..0b1667b7 --- /dev/null +++ b/tinybird.config.mjs @@ -0,0 +1,9 @@ +/** @type {import("@tinybirdco/sdk").TinybirdConfig} */ +const tinybirdConfig = { + include: ["lib/tinybird.ts"], + token: process.env.TINYBIRD_TOKEN, + baseUrl: process.env.TINYBIRD_URL, + devMode: "branch", // or "local" if you want to run the project locally (Tinybird Local required) +}; + +export default tinybirdConfig; -- 2.51.2