wip share
This commit is contained in:
@@ -10,7 +10,6 @@
|
|||||||
"cf-typegen": "wrangler types",
|
"cf-typegen": "wrangler types",
|
||||||
"build": "pnpm with-env vite build",
|
"build": "pnpm with-env vite build",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
"test": "vitest run",
|
|
||||||
"format": "biome format",
|
"format": "biome format",
|
||||||
"lint": "biome lint",
|
"lint": "biome lint",
|
||||||
"check": "biome check",
|
"check": "biome check",
|
||||||
@@ -26,7 +25,7 @@
|
|||||||
"@hookform/resolvers": "^3.3.4",
|
"@hookform/resolvers": "^3.3.4",
|
||||||
"@hyperdx/node-opentelemetry": "^0.8.1",
|
"@hyperdx/node-opentelemetry": "^0.8.1",
|
||||||
"@nivo/sankey": "^0.99.0",
|
"@nivo/sankey": "^0.99.0",
|
||||||
"@number-flow/react": "0.3.5",
|
"@number-flow/react": "0.5.10",
|
||||||
"@openpanel/common": "workspace:^",
|
"@openpanel/common": "workspace:^",
|
||||||
"@openpanel/constants": "workspace:^",
|
"@openpanel/constants": "workspace:^",
|
||||||
"@openpanel/integrations": "workspace:^",
|
"@openpanel/integrations": "workspace:^",
|
||||||
@@ -150,7 +149,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "1.9.4",
|
||||||
"@cloudflare/vite-plugin": "^1.13.12",
|
"@cloudflare/vite-plugin": "1.20.3",
|
||||||
"@openpanel/db": "workspace:*",
|
"@openpanel/db": "workspace:*",
|
||||||
"@openpanel/trpc": "workspace:*",
|
"@openpanel/trpc": "workspace:*",
|
||||||
"@tanstack/devtools-event-client": "^0.3.3",
|
"@tanstack/devtools-event-client": "^0.3.3",
|
||||||
@@ -171,6 +170,6 @@
|
|||||||
"vite": "^6.3.5",
|
"vite": "^6.3.5",
|
||||||
"vitest": "^3.0.5",
|
"vitest": "^3.0.5",
|
||||||
"web-vitals": "^4.2.4",
|
"web-vitals": "^4.2.4",
|
||||||
"wrangler": "^4.42.2"
|
"wrangler": "4.59.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,6 @@
|
|||||||
import type { NumberFlowProps } from '@number-flow/react';
|
import type { NumberFlowProps } from '@number-flow/react';
|
||||||
import { useEffect, useState } from 'react';
|
import ReactAnimatedNumber from '@number-flow/react';
|
||||||
|
|
||||||
// NumberFlow is breaking ssr and forces loaders to fetch twice
|
|
||||||
export function AnimatedNumber(props: NumberFlowProps) {
|
export function AnimatedNumber(props: NumberFlowProps) {
|
||||||
const [Component, setComponent] =
|
return <ReactAnimatedNumber {...props} />;
|
||||||
useState<React.ComponentType<NumberFlowProps> | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
import('@number-flow/react').then(({ default: NumberFlow }) => {
|
|
||||||
setComponent(NumberFlow);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!Component) {
|
|
||||||
return <>{props.value}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Component {...props} />;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ import { Route as PublicRouteImport } from './routes/_public'
|
|||||||
import { Route as LoginRouteImport } from './routes/_login'
|
import { Route as LoginRouteImport } from './routes/_login'
|
||||||
import { Route as AppRouteImport } from './routes/_app'
|
import { Route as AppRouteImport } from './routes/_app'
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
|
import { Route as WidgetTestRouteImport } from './routes/widget/test'
|
||||||
|
import { Route as WidgetRealtimeRouteImport } from './routes/widget/realtime'
|
||||||
|
import { Route as WidgetCounterRouteImport } from './routes/widget/counter'
|
||||||
import { Route as ApiHealthcheckRouteImport } from './routes/api/healthcheck'
|
import { Route as ApiHealthcheckRouteImport } from './routes/api/healthcheck'
|
||||||
import { Route as ApiConfigRouteImport } from './routes/api/config'
|
import { Route as ApiConfigRouteImport } from './routes/api/config'
|
||||||
import { Route as PublicOnboardingRouteImport } from './routes/_public.onboarding'
|
import { Route as PublicOnboardingRouteImport } from './routes/_public.onboarding'
|
||||||
@@ -60,6 +63,7 @@ import { Route as AppOrganizationIdProjectIdSettingsTabsIndexRouteImport } from
|
|||||||
import { Route as AppOrganizationIdProjectIdProfilesTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.profiles._tabs.index'
|
import { Route as AppOrganizationIdProjectIdProfilesTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.profiles._tabs.index'
|
||||||
import { Route as AppOrganizationIdProjectIdNotificationsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.notifications._tabs.index'
|
import { Route as AppOrganizationIdProjectIdNotificationsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.notifications._tabs.index'
|
||||||
import { Route as AppOrganizationIdProjectIdEventsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.events._tabs.index'
|
import { Route as AppOrganizationIdProjectIdEventsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.events._tabs.index'
|
||||||
|
import { Route as AppOrganizationIdProjectIdSettingsTabsWidgetsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.widgets'
|
||||||
import { Route as AppOrganizationIdProjectIdSettingsTabsImportsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.imports'
|
import { Route as AppOrganizationIdProjectIdSettingsTabsImportsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.imports'
|
||||||
import { Route as AppOrganizationIdProjectIdSettingsTabsEventsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.events'
|
import { Route as AppOrganizationIdProjectIdSettingsTabsEventsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.events'
|
||||||
import { Route as AppOrganizationIdProjectIdSettingsTabsDetailsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.details'
|
import { Route as AppOrganizationIdProjectIdSettingsTabsDetailsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.details'
|
||||||
@@ -119,6 +123,21 @@ const IndexRoute = IndexRouteImport.update({
|
|||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const WidgetTestRoute = WidgetTestRouteImport.update({
|
||||||
|
id: '/widget/test',
|
||||||
|
path: '/widget/test',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const WidgetRealtimeRoute = WidgetRealtimeRouteImport.update({
|
||||||
|
id: '/widget/realtime',
|
||||||
|
path: '/widget/realtime',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const WidgetCounterRoute = WidgetCounterRouteImport.update({
|
||||||
|
id: '/widget/counter',
|
||||||
|
path: '/widget/counter',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
const ApiHealthcheckRoute = ApiHealthcheckRouteImport.update({
|
const ApiHealthcheckRoute = ApiHealthcheckRouteImport.update({
|
||||||
id: '/api/healthcheck',
|
id: '/api/healthcheck',
|
||||||
path: '/api/healthcheck',
|
path: '/api/healthcheck',
|
||||||
@@ -408,6 +427,12 @@ const AppOrganizationIdProjectIdEventsTabsIndexRoute =
|
|||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => AppOrganizationIdProjectIdEventsTabsRoute,
|
getParentRoute: () => AppOrganizationIdProjectIdEventsTabsRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const AppOrganizationIdProjectIdSettingsTabsWidgetsRoute =
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsWidgetsRouteImport.update({
|
||||||
|
id: '/widgets',
|
||||||
|
path: '/widgets',
|
||||||
|
getParentRoute: () => AppOrganizationIdProjectIdSettingsTabsRoute,
|
||||||
|
} as any)
|
||||||
const AppOrganizationIdProjectIdSettingsTabsImportsRoute =
|
const AppOrganizationIdProjectIdSettingsTabsImportsRoute =
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRouteImport.update({
|
AppOrganizationIdProjectIdSettingsTabsImportsRouteImport.update({
|
||||||
id: '/imports',
|
id: '/imports',
|
||||||
@@ -506,6 +531,9 @@ export interface FileRoutesByFullPath {
|
|||||||
'/onboarding': typeof PublicOnboardingRoute
|
'/onboarding': typeof PublicOnboardingRoute
|
||||||
'/api/config': typeof ApiConfigRoute
|
'/api/config': typeof ApiConfigRoute
|
||||||
'/api/healthcheck': typeof ApiHealthcheckRoute
|
'/api/healthcheck': typeof ApiHealthcheckRoute
|
||||||
|
'/widget/counter': typeof WidgetCounterRoute
|
||||||
|
'/widget/realtime': typeof WidgetRealtimeRoute
|
||||||
|
'/widget/test': typeof WidgetTestRoute
|
||||||
'/$organizationId/$projectId': typeof AppOrganizationIdProjectIdRouteWithChildren
|
'/$organizationId/$projectId': typeof AppOrganizationIdProjectIdRouteWithChildren
|
||||||
'/$organizationId/billing': typeof AppOrganizationIdBillingRoute
|
'/$organizationId/billing': typeof AppOrganizationIdBillingRoute
|
||||||
'/$organizationId/settings': typeof AppOrganizationIdSettingsRoute
|
'/$organizationId/settings': typeof AppOrganizationIdSettingsRoute
|
||||||
@@ -553,6 +581,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
'/$organizationId/$projectId/settings/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
'/$organizationId/$projectId/events/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
'/$organizationId/$projectId/events/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
||||||
'/$organizationId/$projectId/notifications/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
'/$organizationId/$projectId/notifications/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
||||||
'/$organizationId/$projectId/profiles/': typeof AppOrganizationIdProjectIdProfilesTabsIndexRoute
|
'/$organizationId/$projectId/profiles/': typeof AppOrganizationIdProjectIdProfilesTabsIndexRoute
|
||||||
@@ -567,6 +596,9 @@ export interface FileRoutesByTo {
|
|||||||
'/onboarding': typeof PublicOnboardingRoute
|
'/onboarding': typeof PublicOnboardingRoute
|
||||||
'/api/config': typeof ApiConfigRoute
|
'/api/config': typeof ApiConfigRoute
|
||||||
'/api/healthcheck': typeof ApiHealthcheckRoute
|
'/api/healthcheck': typeof ApiHealthcheckRoute
|
||||||
|
'/widget/counter': typeof WidgetCounterRoute
|
||||||
|
'/widget/realtime': typeof WidgetRealtimeRoute
|
||||||
|
'/widget/test': typeof WidgetTestRoute
|
||||||
'/$organizationId/billing': typeof AppOrganizationIdBillingRoute
|
'/$organizationId/billing': typeof AppOrganizationIdBillingRoute
|
||||||
'/$organizationId/settings': typeof AppOrganizationIdSettingsRoute
|
'/$organizationId/settings': typeof AppOrganizationIdSettingsRoute
|
||||||
'/onboarding/project': typeof StepsOnboardingProjectRoute
|
'/onboarding/project': typeof StepsOnboardingProjectRoute
|
||||||
@@ -611,6 +643,7 @@ export interface FileRoutesByTo {
|
|||||||
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
'/$organizationId/$projectId/settings/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
'/$organizationId/$projectId/profiles/$profileId/events': typeof AppOrganizationIdProjectIdProfilesProfileIdTabsEventsRoute
|
'/$organizationId/$projectId/profiles/$profileId/events': typeof AppOrganizationIdProjectIdProfilesProfileIdTabsEventsRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
@@ -626,6 +659,9 @@ export interface FileRoutesById {
|
|||||||
'/_public/onboarding': typeof PublicOnboardingRoute
|
'/_public/onboarding': typeof PublicOnboardingRoute
|
||||||
'/api/config': typeof ApiConfigRoute
|
'/api/config': typeof ApiConfigRoute
|
||||||
'/api/healthcheck': typeof ApiHealthcheckRoute
|
'/api/healthcheck': typeof ApiHealthcheckRoute
|
||||||
|
'/widget/counter': typeof WidgetCounterRoute
|
||||||
|
'/widget/realtime': typeof WidgetRealtimeRoute
|
||||||
|
'/widget/test': typeof WidgetTestRoute
|
||||||
'/_app/$organizationId/$projectId': typeof AppOrganizationIdProjectIdRouteWithChildren
|
'/_app/$organizationId/$projectId': typeof AppOrganizationIdProjectIdRouteWithChildren
|
||||||
'/_app/$organizationId/billing': typeof AppOrganizationIdBillingRoute
|
'/_app/$organizationId/billing': typeof AppOrganizationIdBillingRoute
|
||||||
'/_app/$organizationId/settings': typeof AppOrganizationIdSettingsRoute
|
'/_app/$organizationId/settings': typeof AppOrganizationIdSettingsRoute
|
||||||
@@ -680,6 +716,7 @@ export interface FileRoutesById {
|
|||||||
'/_app/$organizationId/$projectId/settings/_tabs/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
'/_app/$organizationId/$projectId/settings/_tabs/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
'/_app/$organizationId/$projectId/settings/_tabs/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
'/_app/$organizationId/$projectId/settings/_tabs/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
'/_app/$organizationId/$projectId/settings/_tabs/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
'/_app/$organizationId/$projectId/events/_tabs/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
'/_app/$organizationId/$projectId/events/_tabs/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
||||||
'/_app/$organizationId/$projectId/notifications/_tabs/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
'/_app/$organizationId/$projectId/notifications/_tabs/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
||||||
'/_app/$organizationId/$projectId/profiles/_tabs/': typeof AppOrganizationIdProjectIdProfilesTabsIndexRoute
|
'/_app/$organizationId/$projectId/profiles/_tabs/': typeof AppOrganizationIdProjectIdProfilesTabsIndexRoute
|
||||||
@@ -697,6 +734,9 @@ export interface FileRouteTypes {
|
|||||||
| '/onboarding'
|
| '/onboarding'
|
||||||
| '/api/config'
|
| '/api/config'
|
||||||
| '/api/healthcheck'
|
| '/api/healthcheck'
|
||||||
|
| '/widget/counter'
|
||||||
|
| '/widget/realtime'
|
||||||
|
| '/widget/test'
|
||||||
| '/$organizationId/$projectId'
|
| '/$organizationId/$projectId'
|
||||||
| '/$organizationId/billing'
|
| '/$organizationId/billing'
|
||||||
| '/$organizationId/settings'
|
| '/$organizationId/settings'
|
||||||
@@ -744,6 +784,7 @@ export interface FileRouteTypes {
|
|||||||
| '/$organizationId/$projectId/settings/details'
|
| '/$organizationId/$projectId/settings/details'
|
||||||
| '/$organizationId/$projectId/settings/events'
|
| '/$organizationId/$projectId/settings/events'
|
||||||
| '/$organizationId/$projectId/settings/imports'
|
| '/$organizationId/$projectId/settings/imports'
|
||||||
|
| '/$organizationId/$projectId/settings/widgets'
|
||||||
| '/$organizationId/$projectId/events/'
|
| '/$organizationId/$projectId/events/'
|
||||||
| '/$organizationId/$projectId/notifications/'
|
| '/$organizationId/$projectId/notifications/'
|
||||||
| '/$organizationId/$projectId/profiles/'
|
| '/$organizationId/$projectId/profiles/'
|
||||||
@@ -758,6 +799,9 @@ export interface FileRouteTypes {
|
|||||||
| '/onboarding'
|
| '/onboarding'
|
||||||
| '/api/config'
|
| '/api/config'
|
||||||
| '/api/healthcheck'
|
| '/api/healthcheck'
|
||||||
|
| '/widget/counter'
|
||||||
|
| '/widget/realtime'
|
||||||
|
| '/widget/test'
|
||||||
| '/$organizationId/billing'
|
| '/$organizationId/billing'
|
||||||
| '/$organizationId/settings'
|
| '/$organizationId/settings'
|
||||||
| '/onboarding/project'
|
| '/onboarding/project'
|
||||||
@@ -802,6 +846,7 @@ export interface FileRouteTypes {
|
|||||||
| '/$organizationId/$projectId/settings/details'
|
| '/$organizationId/$projectId/settings/details'
|
||||||
| '/$organizationId/$projectId/settings/events'
|
| '/$organizationId/$projectId/settings/events'
|
||||||
| '/$organizationId/$projectId/settings/imports'
|
| '/$organizationId/$projectId/settings/imports'
|
||||||
|
| '/$organizationId/$projectId/settings/widgets'
|
||||||
| '/$organizationId/$projectId/profiles/$profileId/events'
|
| '/$organizationId/$projectId/profiles/$profileId/events'
|
||||||
id:
|
id:
|
||||||
| '__root__'
|
| '__root__'
|
||||||
@@ -816,6 +861,9 @@ export interface FileRouteTypes {
|
|||||||
| '/_public/onboarding'
|
| '/_public/onboarding'
|
||||||
| '/api/config'
|
| '/api/config'
|
||||||
| '/api/healthcheck'
|
| '/api/healthcheck'
|
||||||
|
| '/widget/counter'
|
||||||
|
| '/widget/realtime'
|
||||||
|
| '/widget/test'
|
||||||
| '/_app/$organizationId/$projectId'
|
| '/_app/$organizationId/$projectId'
|
||||||
| '/_app/$organizationId/billing'
|
| '/_app/$organizationId/billing'
|
||||||
| '/_app/$organizationId/settings'
|
| '/_app/$organizationId/settings'
|
||||||
@@ -870,6 +918,7 @@ export interface FileRouteTypes {
|
|||||||
| '/_app/$organizationId/$projectId/settings/_tabs/details'
|
| '/_app/$organizationId/$projectId/settings/_tabs/details'
|
||||||
| '/_app/$organizationId/$projectId/settings/_tabs/events'
|
| '/_app/$organizationId/$projectId/settings/_tabs/events'
|
||||||
| '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
| '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
||||||
|
| '/_app/$organizationId/$projectId/settings/_tabs/widgets'
|
||||||
| '/_app/$organizationId/$projectId/events/_tabs/'
|
| '/_app/$organizationId/$projectId/events/_tabs/'
|
||||||
| '/_app/$organizationId/$projectId/notifications/_tabs/'
|
| '/_app/$organizationId/$projectId/notifications/_tabs/'
|
||||||
| '/_app/$organizationId/$projectId/profiles/_tabs/'
|
| '/_app/$organizationId/$projectId/profiles/_tabs/'
|
||||||
@@ -886,6 +935,9 @@ export interface RootRouteChildren {
|
|||||||
StepsRoute: typeof StepsRouteWithChildren
|
StepsRoute: typeof StepsRouteWithChildren
|
||||||
ApiConfigRoute: typeof ApiConfigRoute
|
ApiConfigRoute: typeof ApiConfigRoute
|
||||||
ApiHealthcheckRoute: typeof ApiHealthcheckRoute
|
ApiHealthcheckRoute: typeof ApiHealthcheckRoute
|
||||||
|
WidgetCounterRoute: typeof WidgetCounterRoute
|
||||||
|
WidgetRealtimeRoute: typeof WidgetRealtimeRoute
|
||||||
|
WidgetTestRoute: typeof WidgetTestRoute
|
||||||
ShareDashboardShareIdRoute: typeof ShareDashboardShareIdRoute
|
ShareDashboardShareIdRoute: typeof ShareDashboardShareIdRoute
|
||||||
ShareOverviewShareIdRoute: typeof ShareOverviewShareIdRoute
|
ShareOverviewShareIdRoute: typeof ShareOverviewShareIdRoute
|
||||||
ShareReportShareIdRoute: typeof ShareReportShareIdRoute
|
ShareReportShareIdRoute: typeof ShareReportShareIdRoute
|
||||||
@@ -928,6 +980,27 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof IndexRouteImport
|
preLoaderRoute: typeof IndexRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/widget/test': {
|
||||||
|
id: '/widget/test'
|
||||||
|
path: '/widget/test'
|
||||||
|
fullPath: '/widget/test'
|
||||||
|
preLoaderRoute: typeof WidgetTestRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/widget/realtime': {
|
||||||
|
id: '/widget/realtime'
|
||||||
|
path: '/widget/realtime'
|
||||||
|
fullPath: '/widget/realtime'
|
||||||
|
preLoaderRoute: typeof WidgetRealtimeRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/widget/counter': {
|
||||||
|
id: '/widget/counter'
|
||||||
|
path: '/widget/counter'
|
||||||
|
fullPath: '/widget/counter'
|
||||||
|
preLoaderRoute: typeof WidgetCounterRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
'/api/healthcheck': {
|
'/api/healthcheck': {
|
||||||
id: '/api/healthcheck'
|
id: '/api/healthcheck'
|
||||||
path: '/api/healthcheck'
|
path: '/api/healthcheck'
|
||||||
@@ -1285,6 +1358,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AppOrganizationIdProjectIdEventsTabsIndexRouteImport
|
preLoaderRoute: typeof AppOrganizationIdProjectIdEventsTabsIndexRouteImport
|
||||||
parentRoute: typeof AppOrganizationIdProjectIdEventsTabsRoute
|
parentRoute: typeof AppOrganizationIdProjectIdEventsTabsRoute
|
||||||
}
|
}
|
||||||
|
'/_app/$organizationId/$projectId/settings/_tabs/widgets': {
|
||||||
|
id: '/_app/$organizationId/$projectId/settings/_tabs/widgets'
|
||||||
|
path: '/widgets'
|
||||||
|
fullPath: '/$organizationId/$projectId/settings/widgets'
|
||||||
|
preLoaderRoute: typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRouteImport
|
||||||
|
parentRoute: typeof AppOrganizationIdProjectIdSettingsTabsRoute
|
||||||
|
}
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs/imports': {
|
'/_app/$organizationId/$projectId/settings/_tabs/imports': {
|
||||||
id: '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
id: '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
||||||
path: '/imports'
|
path: '/imports'
|
||||||
@@ -1548,6 +1628,7 @@ interface AppOrganizationIdProjectIdSettingsTabsRouteChildren {
|
|||||||
AppOrganizationIdProjectIdSettingsTabsDetailsRoute: typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
AppOrganizationIdProjectIdSettingsTabsDetailsRoute: typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
AppOrganizationIdProjectIdSettingsTabsEventsRoute: typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
AppOrganizationIdProjectIdSettingsTabsEventsRoute: typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRoute: typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
AppOrganizationIdProjectIdSettingsTabsImportsRoute: typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute: typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
AppOrganizationIdProjectIdSettingsTabsIndexRoute: typeof AppOrganizationIdProjectIdSettingsTabsIndexRoute
|
AppOrganizationIdProjectIdSettingsTabsIndexRoute: typeof AppOrganizationIdProjectIdSettingsTabsIndexRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1561,6 +1642,8 @@ const AppOrganizationIdProjectIdSettingsTabsRouteChildren: AppOrganizationIdProj
|
|||||||
AppOrganizationIdProjectIdSettingsTabsEventsRoute,
|
AppOrganizationIdProjectIdSettingsTabsEventsRoute,
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRoute:
|
AppOrganizationIdProjectIdSettingsTabsImportsRoute:
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRoute,
|
AppOrganizationIdProjectIdSettingsTabsImportsRoute,
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute:
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute,
|
||||||
AppOrganizationIdProjectIdSettingsTabsIndexRoute:
|
AppOrganizationIdProjectIdSettingsTabsIndexRoute:
|
||||||
AppOrganizationIdProjectIdSettingsTabsIndexRoute,
|
AppOrganizationIdProjectIdSettingsTabsIndexRoute,
|
||||||
}
|
}
|
||||||
@@ -1791,6 +1874,9 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
StepsRoute: StepsRouteWithChildren,
|
StepsRoute: StepsRouteWithChildren,
|
||||||
ApiConfigRoute: ApiConfigRoute,
|
ApiConfigRoute: ApiConfigRoute,
|
||||||
ApiHealthcheckRoute: ApiHealthcheckRoute,
|
ApiHealthcheckRoute: ApiHealthcheckRoute,
|
||||||
|
WidgetCounterRoute: WidgetCounterRoute,
|
||||||
|
WidgetRealtimeRoute: WidgetRealtimeRoute,
|
||||||
|
WidgetTestRoute: WidgetTestRoute,
|
||||||
ShareDashboardShareIdRoute: ShareDashboardShareIdRoute,
|
ShareDashboardShareIdRoute: ShareDashboardShareIdRoute,
|
||||||
ShareOverviewShareIdRoute: ShareOverviewShareIdRoute,
|
ShareOverviewShareIdRoute: ShareOverviewShareIdRoute,
|
||||||
ShareReportShareIdRoute: ShareReportShareIdRoute,
|
ShareReportShareIdRoute: ShareReportShareIdRoute,
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ function ProjectDashboard() {
|
|||||||
{ id: 'details', label: 'Details' },
|
{ id: 'details', label: 'Details' },
|
||||||
{ id: 'events', label: 'Events' },
|
{ id: 'events', label: 'Events' },
|
||||||
{ id: 'clients', label: 'Clients' },
|
{ id: 'clients', label: 'Clients' },
|
||||||
|
{ id: 'widgets', label: 'Widgets' },
|
||||||
{ id: 'imports', label: 'Imports' },
|
{ id: 'imports', label: 'Imports' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,370 @@
|
|||||||
|
import CopyInput from '@/components/forms/copy-input';
|
||||||
|
import FullPageLoadingState from '@/components/full-page-loading-state';
|
||||||
|
import Syntax from '@/components/syntax';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { Widget, WidgetBody, WidgetHead } from '@/components/widget';
|
||||||
|
import { useAppContext } from '@/hooks/use-app-context';
|
||||||
|
import { useAppParams } from '@/hooks/use-app-params';
|
||||||
|
import { useTRPC } from '@/integrations/trpc/react';
|
||||||
|
import type {
|
||||||
|
IRealtimeWidgetOptions,
|
||||||
|
IWidgetType,
|
||||||
|
} from '@openpanel/validation';
|
||||||
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { ExternalLinkIcon } from 'lucide-react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
'/_app/$organizationId/$projectId/settings/_tabs/widgets',
|
||||||
|
)({
|
||||||
|
component: Component,
|
||||||
|
});
|
||||||
|
|
||||||
|
function Component() {
|
||||||
|
const { projectId, organizationId } = useAppParams();
|
||||||
|
const { dashboardUrl } = useAppContext();
|
||||||
|
const trpc = useTRPC();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
// Fetch both widget types
|
||||||
|
const realtimeWidgetQuery = useQuery(
|
||||||
|
trpc.widget.get.queryOptions({ projectId, type: 'realtime' }),
|
||||||
|
);
|
||||||
|
const counterWidgetQuery = useQuery(
|
||||||
|
trpc.widget.get.queryOptions({ projectId, type: 'counter' }),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Toggle mutation
|
||||||
|
const toggleMutation = useMutation(
|
||||||
|
trpc.widget.toggle.mutationOptions({
|
||||||
|
onSuccess: (_, variables) => {
|
||||||
|
queryClient.invalidateQueries(
|
||||||
|
trpc.widget.get.queryFilter({ projectId, type: variables.type }),
|
||||||
|
);
|
||||||
|
toast.success(variables.enabled ? 'Widget enabled' : 'Widget disabled');
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.message || 'Failed to update widget');
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update options mutation
|
||||||
|
const updateOptionsMutation = useMutation(
|
||||||
|
trpc.widget.updateOptions.mutationOptions({
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(
|
||||||
|
trpc.widget.get.queryFilter({ projectId, type: 'realtime' }),
|
||||||
|
);
|
||||||
|
toast.success('Widget options updated');
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.message || 'Failed to update options');
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleToggle = (type: IWidgetType, enabled: boolean) => {
|
||||||
|
toggleMutation.mutate({
|
||||||
|
projectId,
|
||||||
|
organizationId,
|
||||||
|
type,
|
||||||
|
enabled,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (realtimeWidgetQuery.isLoading || counterWidgetQuery.isLoading) {
|
||||||
|
return <FullPageLoadingState />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const realtimeWidget = realtimeWidgetQuery.data;
|
||||||
|
const counterWidget = counterWidgetQuery.data;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
{realtimeWidget && (
|
||||||
|
<RealtimeWidgetSection
|
||||||
|
widget={realtimeWidget as any}
|
||||||
|
dashboardUrl={dashboardUrl}
|
||||||
|
isToggling={toggleMutation.isPending}
|
||||||
|
isUpdatingOptions={updateOptionsMutation.isPending}
|
||||||
|
onToggle={(enabled) => handleToggle('realtime', enabled)}
|
||||||
|
onUpdateOptions={(options) =>
|
||||||
|
updateOptionsMutation.mutate({
|
||||||
|
projectId,
|
||||||
|
organizationId,
|
||||||
|
options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{counterWidget && (
|
||||||
|
<CounterWidgetSection
|
||||||
|
widget={counterWidget}
|
||||||
|
dashboardUrl={dashboardUrl}
|
||||||
|
isToggling={toggleMutation.isPending}
|
||||||
|
onToggle={(enabled) => handleToggle('counter', enabled)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RealtimeWidgetSectionProps {
|
||||||
|
widget: {
|
||||||
|
id: string;
|
||||||
|
public: boolean;
|
||||||
|
options: IRealtimeWidgetOptions;
|
||||||
|
} | null;
|
||||||
|
dashboardUrl: string;
|
||||||
|
isToggling: boolean;
|
||||||
|
isUpdatingOptions: boolean;
|
||||||
|
onToggle: (enabled: boolean) => void;
|
||||||
|
onUpdateOptions: (options: IRealtimeWidgetOptions) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function RealtimeWidgetSection({
|
||||||
|
widget,
|
||||||
|
dashboardUrl,
|
||||||
|
isToggling,
|
||||||
|
isUpdatingOptions,
|
||||||
|
onToggle,
|
||||||
|
onUpdateOptions,
|
||||||
|
}: RealtimeWidgetSectionProps) {
|
||||||
|
const isEnabled = widget?.public ?? false;
|
||||||
|
const widgetUrl =
|
||||||
|
isEnabled && widget?.id
|
||||||
|
? `${dashboardUrl}/widget/realtime?shareId=${widget.id}`
|
||||||
|
: null;
|
||||||
|
const embedCode = widgetUrl
|
||||||
|
? `<iframe src="${widgetUrl}" width="100%" height="400" frameborder="0" style="border-radius: 8px;"></iframe>`
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Default options
|
||||||
|
const defaultOptions: IRealtimeWidgetOptions = {
|
||||||
|
type: 'realtime',
|
||||||
|
referrers: true,
|
||||||
|
countries: true,
|
||||||
|
paths: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [options, setOptions] = useState<IRealtimeWidgetOptions>(
|
||||||
|
(widget?.options as IRealtimeWidgetOptions) || defaultOptions,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update local options when widget data changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (widget?.options) {
|
||||||
|
setOptions(widget.options as IRealtimeWidgetOptions);
|
||||||
|
}
|
||||||
|
}, [widget?.options]);
|
||||||
|
|
||||||
|
const handleUpdateOptions = (newOptions: IRealtimeWidgetOptions) => {
|
||||||
|
setOptions(newOptions);
|
||||||
|
onUpdateOptions(newOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Widget className="max-w-screen-md w-full">
|
||||||
|
<WidgetHead className="row items-center justify-between gap-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<span className="title">Realtime Widget</span>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
Embed a realtime visitor counter widget on your website. The widget
|
||||||
|
shows live visitor count, activity histogram, top countries,
|
||||||
|
referrers and paths.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={isEnabled}
|
||||||
|
onCheckedChange={onToggle}
|
||||||
|
disabled={isToggling}
|
||||||
|
/>
|
||||||
|
</WidgetHead>
|
||||||
|
{isEnabled && (
|
||||||
|
<WidgetBody className="space-y-6">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-sm font-medium">Widget Options</h3>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label htmlFor="referrers" className="text-sm">
|
||||||
|
Show Referrers
|
||||||
|
</Label>
|
||||||
|
<Switch
|
||||||
|
id="referrers"
|
||||||
|
checked={options.referrers}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
handleUpdateOptions({ ...options, referrers: checked })
|
||||||
|
}
|
||||||
|
disabled={isUpdatingOptions}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label htmlFor="countries" className="text-sm">
|
||||||
|
Show Countries
|
||||||
|
</Label>
|
||||||
|
<Switch
|
||||||
|
id="countries"
|
||||||
|
checked={options.countries}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
handleUpdateOptions({ ...options, countries: checked })
|
||||||
|
}
|
||||||
|
disabled={isUpdatingOptions}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label htmlFor="paths" className="text-sm">
|
||||||
|
Show Paths
|
||||||
|
</Label>
|
||||||
|
<Switch
|
||||||
|
id="paths"
|
||||||
|
checked={options.paths}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
handleUpdateOptions({ ...options, paths: checked })
|
||||||
|
}
|
||||||
|
disabled={isUpdatingOptions}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Widget URL</h3>
|
||||||
|
<CopyInput label="" value={widgetUrl!} className="w-full" />
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Direct link to the widget. You can open this in a new tab or embed
|
||||||
|
it.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Embed Code</h3>
|
||||||
|
<Syntax code={embedCode!} language="bash" />
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Copy this code and paste it into your website HTML where you want
|
||||||
|
the widget to appear.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Preview</h3>
|
||||||
|
<div className="border rounded-lg overflow-hidden">
|
||||||
|
<iframe
|
||||||
|
src={widgetUrl!}
|
||||||
|
width="100%"
|
||||||
|
height="600"
|
||||||
|
className="border-0"
|
||||||
|
title="Realtime Widget Preview"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
icon={ExternalLinkIcon}
|
||||||
|
onClick={() =>
|
||||||
|
window.open(widgetUrl!, '_blank', 'noopener,noreferrer')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Open in new tab
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</WidgetBody>
|
||||||
|
)}
|
||||||
|
</Widget>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CounterWidgetSectionProps {
|
||||||
|
widget: {
|
||||||
|
id: string;
|
||||||
|
public: boolean;
|
||||||
|
} | null;
|
||||||
|
dashboardUrl: string;
|
||||||
|
isToggling: boolean;
|
||||||
|
onToggle: (enabled: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CounterWidgetSection({
|
||||||
|
widget,
|
||||||
|
dashboardUrl,
|
||||||
|
isToggling,
|
||||||
|
onToggle,
|
||||||
|
}: CounterWidgetSectionProps) {
|
||||||
|
const isEnabled = widget?.public ?? false;
|
||||||
|
const counterUrl =
|
||||||
|
isEnabled && widget?.id
|
||||||
|
? `${dashboardUrl}/widget/counter?shareId=${widget.id}`
|
||||||
|
: null;
|
||||||
|
const counterEmbedCode = counterUrl
|
||||||
|
? `<iframe src="${counterUrl}" height="32" style="border: none; overflow: hidden;" title="Visitor Counter"></iframe>`
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Widget className="max-w-screen-md w-full">
|
||||||
|
<WidgetHead className="row items-center justify-between gap-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<span className="title">Counter Widget</span>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
A compact live visitor counter badge you can embed anywhere. Shows
|
||||||
|
the current number of unique visitors with a live indicator.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={isEnabled}
|
||||||
|
onCheckedChange={onToggle}
|
||||||
|
disabled={isToggling}
|
||||||
|
/>
|
||||||
|
</WidgetHead>
|
||||||
|
{isEnabled && counterUrl && (
|
||||||
|
<WidgetBody className="space-y-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Widget URL</h3>
|
||||||
|
<CopyInput label="" value={counterUrl} className="w-full" />
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Direct link to the counter widget.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Embed Code</h3>
|
||||||
|
<Syntax code={counterEmbedCode!} language="bash" />
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Copy this code and paste it into your website HTML where you want
|
||||||
|
the counter to appear.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Preview</h3>
|
||||||
|
<div className="border rounded-lg p-4 bg-muted/30">
|
||||||
|
<iframe
|
||||||
|
src={counterUrl}
|
||||||
|
height="32"
|
||||||
|
className="border-0"
|
||||||
|
title="Counter Widget Preview"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
icon={ExternalLinkIcon}
|
||||||
|
onClick={() =>
|
||||||
|
window.open(counterUrl, '_blank', 'noopener,noreferrer')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Open in new tab
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</WidgetBody>
|
||||||
|
)}
|
||||||
|
</Widget>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -12,9 +12,8 @@ import OverviewTopGeo from '@/components/overview/overview-top-geo';
|
|||||||
import OverviewTopPages from '@/components/overview/overview-top-pages';
|
import OverviewTopPages from '@/components/overview/overview-top-pages';
|
||||||
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
import OverviewTopSources from '@/components/overview/overview-top-sources';
|
||||||
import { useTRPC } from '@/integrations/trpc/react';
|
import { useTRPC } from '@/integrations/trpc/react';
|
||||||
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
|
import { useSuspenseQuery } from '@tanstack/react-query';
|
||||||
import { createFileRoute, notFound, useSearch } from '@tanstack/react-router';
|
import { createFileRoute, notFound, useSearch } from '@tanstack/react-router';
|
||||||
import { EyeClosedIcon, FrownIcon } from 'lucide-react';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
const shareSearchSchema = z.object({
|
const shareSearchSchema = z.object({
|
||||||
|
|||||||
86
apps/start/src/routes/widget/counter.tsx
Normal file
86
apps/start/src/routes/widget/counter.tsx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { AnimatedNumber } from '@/components/animated-number';
|
||||||
|
import { Ping } from '@/components/ping';
|
||||||
|
import { useNumber } from '@/hooks/use-numer-formatter';
|
||||||
|
import useWS from '@/hooks/use-ws';
|
||||||
|
import { useTRPC } from '@/integrations/trpc/react';
|
||||||
|
import type { RouterOutputs } from '@/trpc/client';
|
||||||
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
const widgetSearchSchema = z.object({
|
||||||
|
shareId: z.string(),
|
||||||
|
limit: z.number().default(10),
|
||||||
|
color: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/widget/counter')({
|
||||||
|
component: RouteComponent,
|
||||||
|
validateSearch: widgetSearchSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
const { shareId, limit, color } = Route.useSearch();
|
||||||
|
const trpc = useTRPC();
|
||||||
|
|
||||||
|
// Fetch widget data
|
||||||
|
const { data, isLoading } = useQuery(
|
||||||
|
trpc.widget.counter.queryOptions({ shareId }),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2 px-2 h-8">
|
||||||
|
<Ping />
|
||||||
|
<AnimatedNumber value={0} suffix=" unique visitors" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2 px-2 h-8">
|
||||||
|
<Ping className="bg-orange-500" />
|
||||||
|
<AnimatedNumber value={0} suffix=" unique visitors" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <CounterWidget shareId={shareId} data={data} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RealtimeWidgetProps {
|
||||||
|
shareId: string;
|
||||||
|
data: RouterOutputs['widget']['counter'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function CounterWidget({ shareId, data }: RealtimeWidgetProps) {
|
||||||
|
const trpc = useTRPC();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const number = useNumber();
|
||||||
|
|
||||||
|
// WebSocket subscription for real-time updates
|
||||||
|
useWS<number>(
|
||||||
|
`/live/visitors/${data.projectId}`,
|
||||||
|
(res) => {
|
||||||
|
if (!document.hidden) {
|
||||||
|
queryClient.refetchQueries(
|
||||||
|
trpc.widget.counter.queryFilter({ shareId }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
debounce: {
|
||||||
|
delay: 1000,
|
||||||
|
maxWait: 60000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2 px-2 h-8">
|
||||||
|
<Ping />
|
||||||
|
<AnimatedNumber value={data.counter} suffix=" unique visitors" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
528
apps/start/src/routes/widget/realtime.tsx
Normal file
528
apps/start/src/routes/widget/realtime.tsx
Normal file
@@ -0,0 +1,528 @@
|
|||||||
|
import { AnimatedNumber } from '@/components/animated-number';
|
||||||
|
import {
|
||||||
|
ChartTooltipContainer,
|
||||||
|
ChartTooltipHeader,
|
||||||
|
ChartTooltipItem,
|
||||||
|
} from '@/components/charts/chart-tooltip';
|
||||||
|
import { LogoSquare } from '@/components/logo';
|
||||||
|
import { Ping } from '@/components/ping';
|
||||||
|
import { SerieIcon } from '@/components/report-chart/common/serie-icon';
|
||||||
|
import { useNumber } from '@/hooks/use-numer-formatter';
|
||||||
|
import useWS from '@/hooks/use-ws';
|
||||||
|
import { useTRPC } from '@/integrations/trpc/react';
|
||||||
|
import { countries } from '@/translations/countries';
|
||||||
|
import type { RouterOutputs } from '@/trpc/client';
|
||||||
|
import { cn } from '@/utils/cn';
|
||||||
|
import { getChartColor } from '@/utils/theme';
|
||||||
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import type React from 'react';
|
||||||
|
import {
|
||||||
|
Bar,
|
||||||
|
BarChart,
|
||||||
|
ResponsiveContainer,
|
||||||
|
Tooltip,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
} from 'recharts';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
const widgetSearchSchema = z.object({
|
||||||
|
shareId: z.string(),
|
||||||
|
limit: z.number().default(10),
|
||||||
|
color: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/widget/realtime')({
|
||||||
|
component: RouteComponent,
|
||||||
|
validateSearch: widgetSearchSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
const { shareId, limit, color } = Route.useSearch();
|
||||||
|
const trpc = useTRPC();
|
||||||
|
|
||||||
|
// Fetch widget data
|
||||||
|
const { data: widgetData, isLoading } = useQuery(
|
||||||
|
trpc.widget.realtimeData.queryOptions({ shareId }),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <RealtimeWidgetSkeleton limit={limit} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!widgetData) {
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen w-full center-center bg-background text-foreground col p-4">
|
||||||
|
<LogoSquare className="size-10 mb-4" />
|
||||||
|
<h1 className="text-xl font-semibold">Widget not found</h1>
|
||||||
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
|
This widget is not available or has been removed.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RealtimeWidget
|
||||||
|
shareId={shareId}
|
||||||
|
limit={limit}
|
||||||
|
data={widgetData}
|
||||||
|
color={color}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RealtimeWidgetProps {
|
||||||
|
shareId: string;
|
||||||
|
limit: number;
|
||||||
|
color: string | undefined;
|
||||||
|
data: RouterOutputs['widget']['realtimeData'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function RealtimeWidget({ shareId, data, limit, color }: RealtimeWidgetProps) {
|
||||||
|
const trpc = useTRPC();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const number = useNumber();
|
||||||
|
|
||||||
|
// WebSocket subscription for real-time updates
|
||||||
|
useWS<number>(
|
||||||
|
`/live/visitors/${data.projectId}`,
|
||||||
|
() => {
|
||||||
|
if (!document.hidden) {
|
||||||
|
queryClient.refetchQueries(
|
||||||
|
trpc.widget.realtimeData.queryFilter({ shareId }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
debounce: {
|
||||||
|
delay: 1000,
|
||||||
|
maxWait: 60000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const maxDomain =
|
||||||
|
Math.max(...data.histogram.map((item) => item.sessionCount), 1) * 1.2;
|
||||||
|
|
||||||
|
const grids = (() => {
|
||||||
|
const countries = data.countries.length > 0 ? 1 : 0;
|
||||||
|
const referrers = data.referrers.length > 0 ? 1 : 0;
|
||||||
|
const paths = data.paths.length > 0 ? 1 : 0;
|
||||||
|
const value = countries + referrers + paths;
|
||||||
|
if (value === 3) return 'md:grid-cols-3';
|
||||||
|
if (value === 2) return 'md:grid-cols-2';
|
||||||
|
return 'md:grid-cols-1';
|
||||||
|
})();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen w-full flex-col bg-background text-foreground">
|
||||||
|
{/* Header with live counter */}
|
||||||
|
<div className="border-b p-6 pb-3">
|
||||||
|
<div className="flex items-center justify-between w-full h-4">
|
||||||
|
<div className="flex items-center gap-3 w-full">
|
||||||
|
<Ping />
|
||||||
|
<div className="text-sm font-medium text-muted-foreground flex-1">
|
||||||
|
USERS IN LAST 30 MINUTES
|
||||||
|
</div>
|
||||||
|
{data.project.domain && <SerieIcon name={data.project.domain} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="font-mono text-6xl font-bold h-18 text-foreground">
|
||||||
|
<AnimatedNumber value={data.liveCount} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex h-20 w-full flex-col -mt-4">
|
||||||
|
<div className="flex-1">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<BarChart
|
||||||
|
data={data.histogram}
|
||||||
|
margin={{ top: 0, right: 0, left: 0, bottom: 0 }}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
content={CustomTooltip}
|
||||||
|
cursor={{ fill: 'var(--def-100)', radius: 4 }}
|
||||||
|
/>
|
||||||
|
<XAxis
|
||||||
|
dataKey="time"
|
||||||
|
axisLine={false}
|
||||||
|
tickLine={false}
|
||||||
|
tick={{ fill: 'var(--muted-foreground)', fontSize: 10 }}
|
||||||
|
ticks={[
|
||||||
|
data.histogram[0].time,
|
||||||
|
data.histogram[data.histogram.length - 1].time,
|
||||||
|
]}
|
||||||
|
interval="preserveStartEnd"
|
||||||
|
/>
|
||||||
|
<YAxis hide domain={[0, maxDomain]} />
|
||||||
|
<Bar
|
||||||
|
dataKey="sessionCount"
|
||||||
|
isAnimationActive={false}
|
||||||
|
radius={[4, 4, 4, 4]}
|
||||||
|
fill={color || 'var(--chart-0)'}
|
||||||
|
/>
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-1 flex-col gap-6 overflow-auto p-6 hide-scrollbar">
|
||||||
|
{/* Histogram */}
|
||||||
|
{/* Countries and Referrers */}
|
||||||
|
{(data.countries.length > 0 || data.referrers.length > 0) && (
|
||||||
|
<div className={cn('grid grid-cols-1 gap-6', grids)}>
|
||||||
|
{/* Countries */}
|
||||||
|
{data.countries.length > 0 && (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="mb-3 text-xs font-medium text-muted-foreground">
|
||||||
|
COUNTRY
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
{(() => {
|
||||||
|
const { visible, rest, restCount } = getRestItems(
|
||||||
|
data.countries,
|
||||||
|
limit,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{visible.map((item) => (
|
||||||
|
<RowItem key={item.country} count={item.count}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<SerieIcon name={item.country} />
|
||||||
|
<span className="text-sm">
|
||||||
|
{countries[
|
||||||
|
item.country as keyof typeof countries
|
||||||
|
] || item.country}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</RowItem>
|
||||||
|
))}
|
||||||
|
{rest.length > 0 && (
|
||||||
|
<RestRow
|
||||||
|
firstName={
|
||||||
|
countries[
|
||||||
|
rest[0].country as keyof typeof countries
|
||||||
|
] || rest[0].country
|
||||||
|
}
|
||||||
|
restCount={rest.length}
|
||||||
|
totalCount={restCount}
|
||||||
|
type="countries"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Referrers */}
|
||||||
|
{data.referrers.length > 0 && (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="mb-3 text-xs font-medium text-muted-foreground">
|
||||||
|
REFERRER
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
{(() => {
|
||||||
|
const { visible, rest, restCount } = getRestItems(
|
||||||
|
data.referrers,
|
||||||
|
limit,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{visible.map((item) => (
|
||||||
|
<RowItem key={item.referrer} count={item.count}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<SerieIcon name={item.referrer} />
|
||||||
|
<span className="truncate text-sm">
|
||||||
|
{item.referrer}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</RowItem>
|
||||||
|
))}
|
||||||
|
{rest.length > 0 && (
|
||||||
|
<RestRow
|
||||||
|
firstName={rest[0].referrer}
|
||||||
|
restCount={rest.length}
|
||||||
|
totalCount={restCount}
|
||||||
|
type="referrers"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Paths */}
|
||||||
|
{data.paths.length > 0 && (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="mb-3 text-xs font-medium text-muted-foreground">
|
||||||
|
PATH
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
{(() => {
|
||||||
|
const { visible, rest, restCount } = getRestItems(
|
||||||
|
data.paths,
|
||||||
|
limit,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{visible.map((item) => (
|
||||||
|
<RowItem key={item.path} count={item.count}>
|
||||||
|
<span className="truncate text-sm">
|
||||||
|
{item.path}
|
||||||
|
</span>
|
||||||
|
</RowItem>
|
||||||
|
))}
|
||||||
|
{rest.length > 0 && (
|
||||||
|
<RestRow
|
||||||
|
firstName={rest[0].path}
|
||||||
|
restCount={rest.length}
|
||||||
|
totalCount={restCount}
|
||||||
|
type="paths"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom tooltip component that uses portals to escape overflow hidden
|
||||||
|
const CustomTooltip = ({ active, payload, coordinate }: any) => {
|
||||||
|
const number = useNumber();
|
||||||
|
|
||||||
|
if (!active || !payload || !payload.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = payload[0].payload;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChartTooltipContainer className="max-w-[100px]">
|
||||||
|
<ChartTooltipHeader>
|
||||||
|
<div>{data.time}</div>
|
||||||
|
</ChartTooltipHeader>
|
||||||
|
<ChartTooltipItem color={getChartColor(0)} innerClassName="row gap-1">
|
||||||
|
<div className="flex-1">Visitors</div>
|
||||||
|
<div>{number.short(data.sessionCount)}</div>
|
||||||
|
</ChartTooltipItem>
|
||||||
|
</ChartTooltipContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function RowItem({
|
||||||
|
children,
|
||||||
|
count,
|
||||||
|
}: { children: React.ReactNode; count: number }) {
|
||||||
|
const number = useNumber();
|
||||||
|
return (
|
||||||
|
<div className="h-10 text-sm flex items-center justify-between px-3 py-2 border-b hover:bg-foreground/5 -mx-3">
|
||||||
|
{children}
|
||||||
|
<span className="font-semibold">{number.short(count)}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRestItems<T extends { count: number }>(
|
||||||
|
items: T[],
|
||||||
|
limit: number,
|
||||||
|
): { visible: T[]; rest: T[]; restCount: number } {
|
||||||
|
const visible = items.slice(0, limit);
|
||||||
|
const rest = items.slice(limit);
|
||||||
|
const restCount = rest.reduce((sum, item) => sum + item.count, 0);
|
||||||
|
return { visible, rest, restCount };
|
||||||
|
}
|
||||||
|
|
||||||
|
function RestRow({
|
||||||
|
firstName,
|
||||||
|
restCount,
|
||||||
|
totalCount,
|
||||||
|
type,
|
||||||
|
}: {
|
||||||
|
firstName: string;
|
||||||
|
restCount: number;
|
||||||
|
totalCount: number;
|
||||||
|
type: 'countries' | 'referrers' | 'paths';
|
||||||
|
}) {
|
||||||
|
const number = useNumber();
|
||||||
|
const otherCount = restCount - 1;
|
||||||
|
const typeLabel =
|
||||||
|
type === 'countries'
|
||||||
|
? otherCount === 1
|
||||||
|
? 'country'
|
||||||
|
: 'countries'
|
||||||
|
: type === 'referrers'
|
||||||
|
? otherCount === 1
|
||||||
|
? 'referrer'
|
||||||
|
: 'referrers'
|
||||||
|
: otherCount === 1
|
||||||
|
? 'path'
|
||||||
|
: 'paths';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-10 text-sm flex items-center justify-between px-3 py-2 border-b hover:bg-foreground/5 -mx-3">
|
||||||
|
<span className="truncate">
|
||||||
|
{firstName} and {otherCount} more {typeLabel}...
|
||||||
|
</span>
|
||||||
|
<span className="font-semibold">{number.short(totalCount)}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-generated skeleton keys to avoid index-based keys in render
|
||||||
|
const SKELETON_KEYS = {
|
||||||
|
countries: [
|
||||||
|
'country-0',
|
||||||
|
'country-1',
|
||||||
|
'country-2',
|
||||||
|
'country-3',
|
||||||
|
'country-4',
|
||||||
|
'country-5',
|
||||||
|
'country-6',
|
||||||
|
'country-7',
|
||||||
|
'country-8',
|
||||||
|
'country-9',
|
||||||
|
],
|
||||||
|
referrers: [
|
||||||
|
'referrer-0',
|
||||||
|
'referrer-1',
|
||||||
|
'referrer-2',
|
||||||
|
'referrer-3',
|
||||||
|
'referrer-4',
|
||||||
|
'referrer-5',
|
||||||
|
'referrer-6',
|
||||||
|
'referrer-7',
|
||||||
|
'referrer-8',
|
||||||
|
'referrer-9',
|
||||||
|
],
|
||||||
|
paths: [
|
||||||
|
'path-0',
|
||||||
|
'path-1',
|
||||||
|
'path-2',
|
||||||
|
'path-3',
|
||||||
|
'path-4',
|
||||||
|
'path-5',
|
||||||
|
'path-6',
|
||||||
|
'path-7',
|
||||||
|
'path-8',
|
||||||
|
'path-9',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pre-generated skeleton histogram data
|
||||||
|
const SKELETON_HISTOGRAM = [
|
||||||
|
24, 48, 21, 32, 19, 16, 52, 14, 11, 7, 12, 18, 25, 65, 55, 62, 9, 68, 10, 31,
|
||||||
|
58, 70, 10, 47, 43, 10, 38, 35, 41, 28,
|
||||||
|
];
|
||||||
|
|
||||||
|
function RealtimeWidgetSkeleton({ limit }: { limit: number }) {
|
||||||
|
const itemCount = Math.min(limit, 5);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen w-full flex-col bg-background text-foreground animate-pulse">
|
||||||
|
{/* Header with live counter */}
|
||||||
|
<div className="border-b p-6 pb-3">
|
||||||
|
<div className="flex items-center justify-between w-full h-4">
|
||||||
|
<div className="flex items-center gap-3 w-full">
|
||||||
|
<div className="size-2 rounded-full bg-muted" />
|
||||||
|
<div className="text-sm font-medium text-muted-foreground flex-1">
|
||||||
|
USERS IN LAST 30 MINUTES
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="size-4 shrink-0 rounded bg-muted" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="row">
|
||||||
|
<div className="font-mono text-6xl font-bold h-18 flex items-center py-4 gap-1 row">
|
||||||
|
<div className="h-full w-6 bg-muted rounded" />
|
||||||
|
<div className="h-full w-6 bg-muted rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex h-20 w-full flex-col -mt-4 pb-2.5">
|
||||||
|
<div className="flex-1 row gap-1 h-full">
|
||||||
|
{SKELETON_HISTOGRAM.map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={index.toString()}
|
||||||
|
style={{ height: `${item}%` }}
|
||||||
|
className="h-full w-full bg-muted rounded mt-auto"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="row justify-between pt-2">
|
||||||
|
<div className="h-3 w-8 bg-muted rounded" />
|
||||||
|
<div className="h-3 w-8 bg-muted rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-1 flex-col gap-6 overflow-auto p-6 hide-scrollbar">
|
||||||
|
{/* Countries, Referrers, and Paths skeleton */}
|
||||||
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-3">
|
||||||
|
{/* Countries skeleton */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="mb-3 text-xs font-medium text-muted-foreground">
|
||||||
|
COUNTRY
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
{SKELETON_KEYS.countries.slice(0, itemCount).map((key) => (
|
||||||
|
<RowItemSkeleton key={key} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Referrers skeleton */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="mb-3 text-xs font-medium text-muted-foreground">
|
||||||
|
REFERRER
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
{SKELETON_KEYS.referrers.slice(0, itemCount).map((key) => (
|
||||||
|
<RowItemSkeleton key={key} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Paths skeleton */}
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="mb-3 text-xs font-medium text-muted-foreground">
|
||||||
|
PATH
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
{SKELETON_KEYS.paths.slice(0, itemCount).map((key) => (
|
||||||
|
<RowItemSkeleton key={key} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RowItemSkeleton() {
|
||||||
|
return (
|
||||||
|
<div className="h-10 text-sm flex items-center justify-between px-3 py-2 border-b -mx-3">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="size-5 rounded bg-muted" />
|
||||||
|
<div className="h-4 w-24 bg-muted rounded" />
|
||||||
|
</div>
|
||||||
|
<div className="h-4 w-8 bg-muted rounded" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
apps/start/src/routes/widget/test.tsx
Normal file
34
apps/start/src/routes/widget/test.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/widget/test')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div className="center-center h-screen w-screen gap-4">
|
||||||
|
<iframe
|
||||||
|
title="Realtime Widget"
|
||||||
|
src="http://localhost:3000/widget/realtime?shareId=qkC561&limit=2"
|
||||||
|
width="300"
|
||||||
|
height="400"
|
||||||
|
className="rounded-xl border"
|
||||||
|
/>
|
||||||
|
<iframe
|
||||||
|
title="Realtime Widget"
|
||||||
|
src="http://localhost:3000/widget/realtime?shareId=qkC562&limit=2"
|
||||||
|
width="300"
|
||||||
|
height="400"
|
||||||
|
className="rounded-xl border"
|
||||||
|
/>
|
||||||
|
<iframe
|
||||||
|
title="Counter Widget"
|
||||||
|
src="http://localhost:3000/widget/counter?shareId=qkC561"
|
||||||
|
height="32"
|
||||||
|
width="auto"
|
||||||
|
frameBorder="0"
|
||||||
|
className="rounded-xl border"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -61,7 +61,8 @@
|
|||||||
"nuqs": "patches/nuqs.patch"
|
"nuqs": "patches/nuqs.patch"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"rolldown": "1.0.0-beta.43"
|
"rolldown": "1.0.0-beta.43",
|
||||||
|
"esm-env": "npm:esm-env-runtime@^0.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,11 @@ export async function up() {
|
|||||||
const currentOptions = report.options as IReportOptions | null | undefined;
|
const currentOptions = report.options as IReportOptions | null | undefined;
|
||||||
|
|
||||||
// Skip if options already exists and is valid
|
// Skip if options already exists and is valid
|
||||||
if (currentOptions && typeof currentOptions === 'object' && 'type' in currentOptions) {
|
if (
|
||||||
|
currentOptions &&
|
||||||
|
typeof currentOptions === 'object' &&
|
||||||
|
'type' in currentOptions
|
||||||
|
) {
|
||||||
skippedCount++;
|
skippedCount++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -84,5 +88,3 @@ export async function up() {
|
|||||||
`Skipped: ${skippedCount} reports (already migrated or no legacy fields)`,
|
`Skipped: ${skippedCount} reports (already migrated or no legacy fields)`,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "public"."share_widgets" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"projectId" TEXT NOT NULL,
|
||||||
|
"organizationId" TEXT NOT NULL,
|
||||||
|
"public" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"options" JSONB NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "share_widgets_id_key" ON "public"."share_widgets"("id");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "public"."share_widgets" ADD CONSTRAINT "share_widgets_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "public"."projects"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "public"."share_widgets" ADD CONSTRAINT "share_widgets_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "public"."organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -58,6 +58,7 @@ model Organization {
|
|||||||
ShareOverview ShareOverview[]
|
ShareOverview ShareOverview[]
|
||||||
ShareDashboard ShareDashboard[]
|
ShareDashboard ShareDashboard[]
|
||||||
ShareReport ShareReport[]
|
ShareReport ShareReport[]
|
||||||
|
ShareWidget ShareWidget[]
|
||||||
integrations Integration[]
|
integrations Integration[]
|
||||||
invites Invite[]
|
invites Invite[]
|
||||||
timezone String?
|
timezone String?
|
||||||
@@ -193,6 +194,7 @@ model Project {
|
|||||||
share ShareOverview?
|
share ShareOverview?
|
||||||
shareDashboards ShareDashboard[]
|
shareDashboards ShareDashboard[]
|
||||||
shareReports ShareReport[]
|
shareReports ShareReport[]
|
||||||
|
shareWidgets ShareWidget[]
|
||||||
meta EventMeta[]
|
meta EventMeta[]
|
||||||
references Reference[]
|
references Reference[]
|
||||||
access ProjectAccess[]
|
access ProjectAccess[]
|
||||||
@@ -410,6 +412,21 @@ model ShareReport {
|
|||||||
@@map("share_reports")
|
@@map("share_reports")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model ShareWidget {
|
||||||
|
id String @unique
|
||||||
|
projectId String
|
||||||
|
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||||
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||||
|
organizationId String
|
||||||
|
public Boolean @default(true)
|
||||||
|
/// [IPrismaWidgetOptions]
|
||||||
|
options Json
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
|
||||||
|
@@map("share_widgets")
|
||||||
|
}
|
||||||
|
|
||||||
model EventMeta {
|
model EventMeta {
|
||||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||||
name String
|
name String
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type {
|
|||||||
IIntegrationConfig,
|
IIntegrationConfig,
|
||||||
INotificationRuleConfig,
|
INotificationRuleConfig,
|
||||||
IProjectFilters,
|
IProjectFilters,
|
||||||
|
IWidgetOptions,
|
||||||
InsightPayload,
|
InsightPayload,
|
||||||
} from '@openpanel/validation';
|
} from '@openpanel/validation';
|
||||||
import type {
|
import type {
|
||||||
@@ -20,6 +21,7 @@ declare global {
|
|||||||
type IPrismaNotificationPayload = INotificationPayload;
|
type IPrismaNotificationPayload = INotificationPayload;
|
||||||
type IPrismaProjectFilters = IProjectFilters[];
|
type IPrismaProjectFilters = IProjectFilters[];
|
||||||
type IPrismaProjectInsightPayload = InsightPayload;
|
type IPrismaProjectInsightPayload = InsightPayload;
|
||||||
|
type IPrismaWidgetOptions = IWidgetOptions;
|
||||||
type IPrismaClickhouseEvent = IClickhouseEvent;
|
type IPrismaClickhouseEvent = IClickhouseEvent;
|
||||||
type IPrismaClickhouseProfile = IClickhouseProfile;
|
type IPrismaClickhouseProfile = IClickhouseProfile;
|
||||||
type IPrismaClickhouseBotEvent = IClickhouseBotEvent;
|
type IPrismaClickhouseBotEvent = IClickhouseBotEvent;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { sessionRouter } from './routers/session';
|
|||||||
import { shareRouter } from './routers/share';
|
import { shareRouter } from './routers/share';
|
||||||
import { subscriptionRouter } from './routers/subscription';
|
import { subscriptionRouter } from './routers/subscription';
|
||||||
import { userRouter } from './routers/user';
|
import { userRouter } from './routers/user';
|
||||||
|
import { widgetRouter } from './routers/widget';
|
||||||
import { createTRPCRouter } from './trpc';
|
import { createTRPCRouter } from './trpc';
|
||||||
/**
|
/**
|
||||||
* This is the primary router for your server.
|
* This is the primary router for your server.
|
||||||
@@ -49,6 +50,7 @@ export const appRouter = createTRPCRouter({
|
|||||||
realtime: realtimeRouter,
|
realtime: realtimeRouter,
|
||||||
chat: chatRouter,
|
chat: chatRouter,
|
||||||
insight: insightRouter,
|
insight: insightRouter,
|
||||||
|
widget: widgetRouter,
|
||||||
});
|
});
|
||||||
|
|
||||||
// export type definition of API
|
// export type definition of API
|
||||||
|
|||||||
298
packages/trpc/src/routers/widget.ts
Normal file
298
packages/trpc/src/routers/widget.ts
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
import ShortUniqueId from 'short-unique-id';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import {
|
||||||
|
TABLE_NAMES,
|
||||||
|
ch,
|
||||||
|
clix,
|
||||||
|
db,
|
||||||
|
eventBuffer,
|
||||||
|
getSettingsForProject,
|
||||||
|
} from '@openpanel/db';
|
||||||
|
import {
|
||||||
|
zCounterWidgetOptions,
|
||||||
|
zRealtimeWidgetOptions,
|
||||||
|
zWidgetOptions,
|
||||||
|
zWidgetType,
|
||||||
|
} from '@openpanel/validation';
|
||||||
|
|
||||||
|
import { TRPCNotFoundError } from '../errors';
|
||||||
|
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
|
||||||
|
|
||||||
|
const uid = new ShortUniqueId({ length: 6 });
|
||||||
|
|
||||||
|
// Helper to find widget by projectId and type
|
||||||
|
async function findWidgetByType(projectId: string, type: string) {
|
||||||
|
const widgets = await db.shareWidget.findMany({
|
||||||
|
where: { projectId },
|
||||||
|
});
|
||||||
|
return widgets.find(
|
||||||
|
(w) => (w.options as z.infer<typeof zWidgetOptions>)?.type === type,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const widgetRouter = createTRPCRouter({
|
||||||
|
// Get widget by projectId and type (returns null if not found or not public)
|
||||||
|
get: protectedProcedure
|
||||||
|
.input(z.object({ projectId: z.string(), type: zWidgetType }))
|
||||||
|
.query(async ({ input }) => {
|
||||||
|
const widget = await findWidgetByType(input.projectId, input.type);
|
||||||
|
|
||||||
|
if (!widget) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Toggle widget public status (creates if doesn't exist)
|
||||||
|
toggle: protectedProcedure
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
projectId: z.string(),
|
||||||
|
organizationId: z.string(),
|
||||||
|
type: zWidgetType,
|
||||||
|
enabled: z.boolean(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mutation(async ({ input }) => {
|
||||||
|
const existing = await findWidgetByType(input.projectId, input.type);
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return db.shareWidget.update({
|
||||||
|
where: { id: existing.id },
|
||||||
|
data: { public: input.enabled },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new widget with default options
|
||||||
|
const defaultOptions =
|
||||||
|
input.type === 'realtime'
|
||||||
|
? {
|
||||||
|
type: 'realtime' as const,
|
||||||
|
referrers: true,
|
||||||
|
countries: true,
|
||||||
|
paths: false,
|
||||||
|
}
|
||||||
|
: { type: 'counter' as const };
|
||||||
|
|
||||||
|
return db.shareWidget.create({
|
||||||
|
data: {
|
||||||
|
id: uid.rnd(),
|
||||||
|
projectId: input.projectId,
|
||||||
|
organizationId: input.organizationId,
|
||||||
|
public: input.enabled,
|
||||||
|
options: defaultOptions,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Update widget options (for realtime widget)
|
||||||
|
updateOptions: protectedProcedure
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
projectId: z.string(),
|
||||||
|
organizationId: z.string(),
|
||||||
|
options: zWidgetOptions,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mutation(async ({ input }) => {
|
||||||
|
const existing = await findWidgetByType(
|
||||||
|
input.projectId,
|
||||||
|
input.options.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return db.shareWidget.update({
|
||||||
|
where: { id: existing.id },
|
||||||
|
data: { options: input.options },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new widget if it doesn't exist
|
||||||
|
return db.shareWidget.create({
|
||||||
|
data: {
|
||||||
|
id: uid.rnd(),
|
||||||
|
projectId: input.projectId,
|
||||||
|
organizationId: input.organizationId,
|
||||||
|
public: false,
|
||||||
|
options: input.options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
|
||||||
|
counter: publicProcedure
|
||||||
|
.input(z.object({ shareId: z.string() }))
|
||||||
|
.query(async ({ input }) => {
|
||||||
|
const widget = await db.shareWidget.findUnique({
|
||||||
|
where: {
|
||||||
|
id: input.shareId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!widget || !widget.public) {
|
||||||
|
throw TRPCNotFoundError('Widget not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.options.type !== 'counter') {
|
||||||
|
throw TRPCNotFoundError('Invalid widget type');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
projectId: widget.projectId,
|
||||||
|
counter: await eventBuffer.getActiveVisitorCount(widget.projectId),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
realtimeData: publicProcedure
|
||||||
|
.input(z.object({ shareId: z.string() }))
|
||||||
|
.query(async ({ input }) => {
|
||||||
|
// Validate ShareWidget exists and is public
|
||||||
|
const widget = await db.shareWidget.findUnique({
|
||||||
|
where: {
|
||||||
|
id: input.shareId,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
project: {
|
||||||
|
select: {
|
||||||
|
domain: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!widget || !widget.public) {
|
||||||
|
throw TRPCNotFoundError('Widget not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { projectId, options } = widget;
|
||||||
|
|
||||||
|
if (options.type !== 'realtime') {
|
||||||
|
throw TRPCNotFoundError('Invalid widget type');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timezone } = await getSettingsForProject(projectId);
|
||||||
|
|
||||||
|
// Always fetch live count and histogram
|
||||||
|
const totalSessionsQuery = clix(ch, timezone)
|
||||||
|
.select<{ total_sessions: number }>([
|
||||||
|
'uniq(session_id) as total_sessions',
|
||||||
|
])
|
||||||
|
.from(TABLE_NAMES.events)
|
||||||
|
.where('project_id', '=', projectId)
|
||||||
|
.where('created_at', '>=', clix.exp('now() - INTERVAL 30 MINUTE'));
|
||||||
|
|
||||||
|
const minuteCountsQuery = clix(ch, timezone)
|
||||||
|
.select<{
|
||||||
|
minute: string;
|
||||||
|
session_count: number;
|
||||||
|
visitor_count: number;
|
||||||
|
}>([
|
||||||
|
`${clix.toStartOf('created_at', 'minute')} as minute`,
|
||||||
|
'uniq(session_id) as session_count',
|
||||||
|
'uniq(profile_id) as visitor_count',
|
||||||
|
])
|
||||||
|
.from(TABLE_NAMES.events)
|
||||||
|
.where('project_id', '=', projectId)
|
||||||
|
.where('created_at', '>=', clix.exp('now() - INTERVAL 30 MINUTE'))
|
||||||
|
.groupBy(['minute'])
|
||||||
|
.orderBy('minute', 'ASC')
|
||||||
|
.fill(
|
||||||
|
clix.exp('toStartOfMinute(now() - INTERVAL 30 MINUTE)'),
|
||||||
|
clix.exp('toStartOfMinute(now())'),
|
||||||
|
clix.exp('INTERVAL 1 MINUTE'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Conditionally fetch countries
|
||||||
|
const countriesQueryPromise = options.countries
|
||||||
|
? clix(ch, timezone)
|
||||||
|
.select<{
|
||||||
|
country: string;
|
||||||
|
count: number;
|
||||||
|
}>(['country', 'uniq(session_id) as count'])
|
||||||
|
.from(TABLE_NAMES.events)
|
||||||
|
.where('project_id', '=', projectId)
|
||||||
|
.where('created_at', '>=', clix.exp('now() - INTERVAL 30 MINUTE'))
|
||||||
|
.where('country', '!=', '')
|
||||||
|
.where('country', 'IS NOT NULL')
|
||||||
|
.groupBy(['country'])
|
||||||
|
.orderBy('count', 'DESC')
|
||||||
|
.limit(10)
|
||||||
|
.execute()
|
||||||
|
: Promise.resolve<Array<{ country: string; count: number }>>([]);
|
||||||
|
|
||||||
|
// Conditionally fetch referrers
|
||||||
|
const referrersQueryPromise = options.referrers
|
||||||
|
? clix(ch, timezone)
|
||||||
|
.select<{ referrer: string; count: number }>([
|
||||||
|
'referrer_name as referrer',
|
||||||
|
'uniq(session_id) as count',
|
||||||
|
])
|
||||||
|
.from(TABLE_NAMES.events)
|
||||||
|
.where('project_id', '=', projectId)
|
||||||
|
.where('created_at', '>=', clix.exp('now() - INTERVAL 30 MINUTE'))
|
||||||
|
.where('referrer_name', '!=', '')
|
||||||
|
.where('referrer_name', 'IS NOT NULL')
|
||||||
|
.groupBy(['referrer_name'])
|
||||||
|
.orderBy('count', 'DESC')
|
||||||
|
.limit(10)
|
||||||
|
.execute()
|
||||||
|
: Promise.resolve<Array<{ referrer: string; count: number }>>([]);
|
||||||
|
|
||||||
|
// Conditionally fetch paths
|
||||||
|
const pathsQueryPromise = options.paths
|
||||||
|
? clix(ch, timezone)
|
||||||
|
.select<{ path: string; count: number }>([
|
||||||
|
'path',
|
||||||
|
'uniq(session_id) as count',
|
||||||
|
])
|
||||||
|
.from(TABLE_NAMES.events)
|
||||||
|
.where('project_id', '=', projectId)
|
||||||
|
.where('created_at', '>=', clix.exp('now() - INTERVAL 30 MINUTE'))
|
||||||
|
.where('path', '!=', '')
|
||||||
|
.where('path', 'IS NOT NULL')
|
||||||
|
.groupBy(['path'])
|
||||||
|
.orderBy('count', 'DESC')
|
||||||
|
.limit(10)
|
||||||
|
.execute()
|
||||||
|
: Promise.resolve<Array<{ path: string; count: number }>>([]);
|
||||||
|
|
||||||
|
const [totalSessions, minuteCounts, countries, referrers, paths] =
|
||||||
|
await Promise.all([
|
||||||
|
totalSessionsQuery.execute(),
|
||||||
|
minuteCountsQuery.execute(),
|
||||||
|
countriesQueryPromise,
|
||||||
|
referrersQueryPromise,
|
||||||
|
pathsQueryPromise,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
projectId,
|
||||||
|
liveCount: totalSessions[0]?.total_sessions || 0,
|
||||||
|
project: widget.project,
|
||||||
|
histogram: minuteCounts.map((item) => ({
|
||||||
|
minute: item.minute,
|
||||||
|
sessionCount: item.session_count,
|
||||||
|
visitorCount: item.visitor_count,
|
||||||
|
timestamp: new Date(item.minute).getTime(),
|
||||||
|
time: new Date(item.minute).toLocaleTimeString([], {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
countries: countries.map((item) => ({
|
||||||
|
country: item.country,
|
||||||
|
count: item.count,
|
||||||
|
})),
|
||||||
|
referrers: referrers.map((item) => ({
|
||||||
|
referrer: item.referrer,
|
||||||
|
count: item.count,
|
||||||
|
})),
|
||||||
|
paths: paths.map((item) => ({
|
||||||
|
path: item.path,
|
||||||
|
count: item.count,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
});
|
||||||
@@ -135,6 +135,29 @@ export const zReportOptions = z.discriminatedUnion('type', [
|
|||||||
export type IReportOptions = z.infer<typeof zReportOptions>;
|
export type IReportOptions = z.infer<typeof zReportOptions>;
|
||||||
export type ISankeyOptions = z.infer<typeof zSankeyOptions>;
|
export type ISankeyOptions = z.infer<typeof zSankeyOptions>;
|
||||||
|
|
||||||
|
export const zWidgetType = z.enum(['realtime', 'counter']);
|
||||||
|
export type IWidgetType = z.infer<typeof zWidgetType>;
|
||||||
|
|
||||||
|
export const zRealtimeWidgetOptions = z.object({
|
||||||
|
type: z.literal('realtime'),
|
||||||
|
referrers: z.boolean().default(true),
|
||||||
|
countries: z.boolean().default(true),
|
||||||
|
paths: z.boolean().default(false),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const zCounterWidgetOptions = z.object({
|
||||||
|
type: z.literal('counter'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const zWidgetOptions = z.discriminatedUnion('type', [
|
||||||
|
zRealtimeWidgetOptions,
|
||||||
|
zCounterWidgetOptions,
|
||||||
|
]);
|
||||||
|
|
||||||
|
export type IWidgetOptions = z.infer<typeof zWidgetOptions>;
|
||||||
|
export type ICounterWidgetOptions = z.infer<typeof zCounterWidgetOptions>;
|
||||||
|
export type IRealtimeWidgetOptions = z.infer<typeof zRealtimeWidgetOptions>;
|
||||||
|
|
||||||
// Base input schema - for API calls, engine, chart queries
|
// Base input schema - for API calls, engine, chart queries
|
||||||
export const zReportInput = z.object({
|
export const zReportInput = z.object({
|
||||||
projectId: z.string().describe('The ID of the project this chart belongs to'),
|
projectId: z.string().describe('The ID of the project this chart belongs to'),
|
||||||
@@ -193,7 +216,9 @@ export const zReportInput = z.object({
|
|||||||
.describe('Chart-specific options (funnel, retention, sankey)'),
|
.describe('Chart-specific options (funnel, retention, sankey)'),
|
||||||
// Optional display fields
|
// Optional display fields
|
||||||
name: z.string().optional().describe('The user-defined name for the report'),
|
name: z.string().optional().describe('The user-defined name for the report'),
|
||||||
lineType: zLineType.optional().describe('The visual style of the line in the chart'),
|
lineType: zLineType
|
||||||
|
.optional()
|
||||||
|
.describe('The visual style of the line in the chart'),
|
||||||
unit: z
|
unit: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -204,8 +229,13 @@ export const zReportInput = z.object({
|
|||||||
|
|
||||||
// Complete report schema - for saved reports
|
// Complete report schema - for saved reports
|
||||||
export const zReport = zReportInput.extend({
|
export const zReport = zReportInput.extend({
|
||||||
name: z.string().default('Untitled').describe('The user-defined name for the report'),
|
name: z
|
||||||
lineType: zLineType.default('monotone').describe('The visual style of the line in the chart'),
|
.string()
|
||||||
|
.default('Untitled')
|
||||||
|
.describe('The user-defined name for the report'),
|
||||||
|
lineType: zLineType
|
||||||
|
.default('monotone')
|
||||||
|
.describe('The visual style of the line in the chart'),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Alias for backward compatibility
|
// Alias for backward compatibility
|
||||||
|
|||||||
450
pnpm-lock.yaml
generated
450
pnpm-lock.yaml
generated
@@ -33,6 +33,7 @@ catalogs:
|
|||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
rolldown: 1.0.0-beta.43
|
rolldown: 1.0.0-beta.43
|
||||||
|
esm-env: npm:esm-env-runtime@^0.1.0
|
||||||
|
|
||||||
patchedDependencies:
|
patchedDependencies:
|
||||||
nuqs:
|
nuqs:
|
||||||
@@ -417,8 +418,8 @@ importers:
|
|||||||
specifier: ^0.99.0
|
specifier: ^0.99.0
|
||||||
version: 0.99.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 0.99.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
'@number-flow/react':
|
'@number-flow/react':
|
||||||
specifier: 0.3.5
|
specifier: 0.5.10
|
||||||
version: 0.3.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 0.5.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
'@openpanel/common':
|
'@openpanel/common':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../../packages/common
|
version: link:../../packages/common
|
||||||
@@ -784,8 +785,8 @@ importers:
|
|||||||
specifier: 1.9.4
|
specifier: 1.9.4
|
||||||
version: 1.9.4
|
version: 1.9.4
|
||||||
'@cloudflare/vite-plugin':
|
'@cloudflare/vite-plugin':
|
||||||
specifier: ^1.13.12
|
specifier: 1.20.3
|
||||||
version: 1.13.12(vite@6.3.5(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.27.1)(tsx@4.20.5)(yaml@2.8.2))(workerd@1.20251008.0)(wrangler@4.42.2)
|
version: 1.20.3(vite@6.3.5(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.27.1)(tsx@4.20.5)(yaml@2.8.2))(workerd@1.20260111.0)(wrangler@4.59.1)
|
||||||
'@openpanel/db':
|
'@openpanel/db':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/db
|
version: link:../../packages/db
|
||||||
@@ -847,8 +848,8 @@ importers:
|
|||||||
specifier: ^4.2.4
|
specifier: ^4.2.4
|
||||||
version: 4.2.4
|
version: 4.2.4
|
||||||
wrangler:
|
wrangler:
|
||||||
specifier: ^4.42.2
|
specifier: 4.59.1
|
||||||
version: 4.42.2
|
version: 4.59.1
|
||||||
|
|
||||||
apps/worker:
|
apps/worker:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2843,47 +2844,51 @@ packages:
|
|||||||
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
|
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
'@cloudflare/unenv-preset@2.7.7':
|
'@cloudflare/kv-asset-handler@0.4.1':
|
||||||
resolution: {integrity: sha512-HtZuh166y0Olbj9bqqySckz0Rw9uHjggJeoGbDx5x+sgezBXlxO6tQSig2RZw5tgObF8mWI8zaPvQMkQZtAODw==}
|
resolution: {integrity: sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
|
'@cloudflare/unenv-preset@2.9.0':
|
||||||
|
resolution: {integrity: sha512-99nEvuOTCGGGRNaIat8UVVXJ27aZK+U09SYDp0kVjQLwC9wyxcrQ28IqLwrQq2DjWLmBI1+UalGJzdPqYgPlRw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
unenv: 2.0.0-rc.21
|
unenv: 2.0.0-rc.24
|
||||||
workerd: ^1.20250927.0
|
workerd: ^1.20251202.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
workerd:
|
workerd:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/vite-plugin@1.13.12':
|
'@cloudflare/vite-plugin@1.20.3':
|
||||||
resolution: {integrity: sha512-JEcrUF1uXxMQfp+RcGw7ov5K8uOGX0arFYdyO3QfHrjWspHnsw0zOYL+4083itEInRVnZjS5LunpsNpxSVbCEw==}
|
resolution: {integrity: sha512-o6ePNfGpu2AKCi7bs32fOl121qFvdyi2fSblF6xID7aHFosqEfZAgCUaJ86LvXJWcPeUl+B0sFII67N5st1rBg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^6.1.0 || ^7.0.0
|
vite: ^6.1.0 || ^7.0.0
|
||||||
wrangler: ^4.42.2
|
wrangler: ^4.59.1
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-64@1.20251008.0':
|
'@cloudflare/workerd-darwin-64@1.20260111.0':
|
||||||
resolution: {integrity: sha512-yph0H+8mMOK5Z9oDwjb8rI96oTVt4no5lZ43aorcbzsWG9VUIaXSXlBBoB3von6p4YCRW+J3n36fBM9XZ6TLaA==}
|
resolution: {integrity: sha512-UGAjrGLev2/CMLZy7b+v1NIXA4Hupc/QJBFlJwMqldywMcJ/iEqvuUYYuVI2wZXuXeWkgmgFP87oFDQsg78YTQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-arm64@1.20251008.0':
|
'@cloudflare/workerd-darwin-arm64@1.20260111.0':
|
||||||
resolution: {integrity: sha512-Yc4lMGSbM4AEtYRpyDpmk77MsHb6X2BSwJgMgGsLVPmckM7ZHivZkJChfcNQjZ/MGR6nkhYc4iF6TcVS+UMEVw==}
|
resolution: {integrity: sha512-YFAZwidLCQVa6rKCCaiWrhA+eh87a7MUhyd9lat3KSbLBAGpYM+ORpyTXpi2Gjm3j6Mp1e/wtzcFTSeMIy2UqA==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-64@1.20251008.0':
|
'@cloudflare/workerd-linux-64@1.20260111.0':
|
||||||
resolution: {integrity: sha512-AjoQnylw4/5G6SmfhZRsli7EuIK7ZMhmbxtU0jkpciTlVV8H01OsFOgS1d8zaTXMfkWamEfMouy8oH/L7B9YcQ==}
|
resolution: {integrity: sha512-zx1GW6FwfOBjCV7QUCRzGRkViUtn3Is/zaaVPmm57xyy9sjtInx6/SdeBr2Y45tx9AnOP1CnaOFFdmH1P7VIEg==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-arm64@1.20251008.0':
|
'@cloudflare/workerd-linux-arm64@1.20260111.0':
|
||||||
resolution: {integrity: sha512-hRy9yyvzVq1HsqHZUmFkAr0C8JGjAD/PeeVEGCKL3jln3M9sNCKIrbDXiL+efe+EwajJNNlDxpO+s30uVWVaRg==}
|
resolution: {integrity: sha512-wFVKxNvCyjRaAcgiSnJNJAmIos3p3Vv6Uhf4pFUZ9JIxr69GNlLWlm9SdCPvtwNFAjzSoDaKzDwjj5xqpuCS6Q==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@cloudflare/workerd-windows-64@1.20251008.0':
|
'@cloudflare/workerd-windows-64@1.20260111.0':
|
||||||
resolution: {integrity: sha512-Gm0RR+ehfNMsScn2pUcn3N9PDUpy7FyvV9ecHEyclKttvztyFOcmsF14bxEaSVv7iM4TxWEBn1rclmYHxDM4ow==}
|
resolution: {integrity: sha512-zWgd77L7OI1BxgBbG+2gybDahIMgPX5iNo6e3LqcEz1Xm3KfiqgnDyMBcxeQ7xDrj7fHUGAlc//QnKvDchuUoQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
@@ -3018,12 +3023,6 @@ packages:
|
|||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [aix]
|
os: [aix]
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [aix]
|
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.9':
|
'@esbuild/aix-ppc64@0.25.9':
|
||||||
resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==}
|
resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3072,12 +3071,6 @@ packages:
|
|||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@esbuild/android-arm64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [android]
|
|
||||||
|
|
||||||
'@esbuild/android-arm64@0.25.9':
|
'@esbuild/android-arm64@0.25.9':
|
||||||
resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==}
|
resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3126,12 +3119,6 @@ packages:
|
|||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@esbuild/android-arm@0.25.4':
|
|
||||||
resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm]
|
|
||||||
os: [android]
|
|
||||||
|
|
||||||
'@esbuild/android-arm@0.25.9':
|
'@esbuild/android-arm@0.25.9':
|
||||||
resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==}
|
resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3180,12 +3167,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
|
||||||
'@esbuild/android-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [android]
|
|
||||||
|
|
||||||
'@esbuild/android-x64@0.25.9':
|
'@esbuild/android-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==}
|
resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3234,12 +3215,6 @@ packages:
|
|||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@esbuild/darwin-arm64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@esbuild/darwin-arm64@0.25.9':
|
'@esbuild/darwin-arm64@0.25.9':
|
||||||
resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==}
|
resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3288,12 +3263,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@esbuild/darwin-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@esbuild/darwin-x64@0.25.9':
|
'@esbuild/darwin-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==}
|
resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3342,12 +3311,6 @@ packages:
|
|||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@esbuild/freebsd-arm64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [freebsd]
|
|
||||||
|
|
||||||
'@esbuild/freebsd-arm64@0.25.9':
|
'@esbuild/freebsd-arm64@0.25.9':
|
||||||
resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==}
|
resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3396,12 +3359,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
|
||||||
'@esbuild/freebsd-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [freebsd]
|
|
||||||
|
|
||||||
'@esbuild/freebsd-x64@0.25.9':
|
'@esbuild/freebsd-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==}
|
resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3450,12 +3407,6 @@ packages:
|
|||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-arm64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-arm64@0.25.9':
|
'@esbuild/linux-arm64@0.25.9':
|
||||||
resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==}
|
resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3504,12 +3455,6 @@ packages:
|
|||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-arm@0.25.4':
|
|
||||||
resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-arm@0.25.9':
|
'@esbuild/linux-arm@0.25.9':
|
||||||
resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==}
|
resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3558,12 +3503,6 @@ packages:
|
|||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-ia32@0.25.4':
|
|
||||||
resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ia32]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-ia32@0.25.9':
|
'@esbuild/linux-ia32@0.25.9':
|
||||||
resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==}
|
resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3612,12 +3551,6 @@ packages:
|
|||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-loong64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [loong64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-loong64@0.25.9':
|
'@esbuild/linux-loong64@0.25.9':
|
||||||
resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==}
|
resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3666,12 +3599,6 @@ packages:
|
|||||||
cpu: [mips64el]
|
cpu: [mips64el]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-mips64el@0.25.4':
|
|
||||||
resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [mips64el]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-mips64el@0.25.9':
|
'@esbuild/linux-mips64el@0.25.9':
|
||||||
resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==}
|
resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3720,12 +3647,6 @@ packages:
|
|||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-ppc64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-ppc64@0.25.9':
|
'@esbuild/linux-ppc64@0.25.9':
|
||||||
resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==}
|
resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3774,12 +3695,6 @@ packages:
|
|||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-riscv64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [riscv64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-riscv64@0.25.9':
|
'@esbuild/linux-riscv64@0.25.9':
|
||||||
resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==}
|
resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3828,12 +3743,6 @@ packages:
|
|||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-s390x@0.25.4':
|
|
||||||
resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [s390x]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-s390x@0.25.9':
|
'@esbuild/linux-s390x@0.25.9':
|
||||||
resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==}
|
resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3882,12 +3791,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@esbuild/linux-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-x64@0.25.9':
|
'@esbuild/linux-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==}
|
resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3918,12 +3821,6 @@ packages:
|
|||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [netbsd]
|
os: [netbsd]
|
||||||
|
|
||||||
'@esbuild/netbsd-arm64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [netbsd]
|
|
||||||
|
|
||||||
'@esbuild/netbsd-arm64@0.25.9':
|
'@esbuild/netbsd-arm64@0.25.9':
|
||||||
resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==}
|
resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3972,12 +3869,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [netbsd]
|
os: [netbsd]
|
||||||
|
|
||||||
'@esbuild/netbsd-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [netbsd]
|
|
||||||
|
|
||||||
'@esbuild/netbsd-x64@0.25.9':
|
'@esbuild/netbsd-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==}
|
resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4008,12 +3899,6 @@ packages:
|
|||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [openbsd]
|
os: [openbsd]
|
||||||
|
|
||||||
'@esbuild/openbsd-arm64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [openbsd]
|
|
||||||
|
|
||||||
'@esbuild/openbsd-arm64@0.25.9':
|
'@esbuild/openbsd-arm64@0.25.9':
|
||||||
resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==}
|
resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4062,12 +3947,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [openbsd]
|
os: [openbsd]
|
||||||
|
|
||||||
'@esbuild/openbsd-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [openbsd]
|
|
||||||
|
|
||||||
'@esbuild/openbsd-x64@0.25.9':
|
'@esbuild/openbsd-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==}
|
resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4140,12 +4019,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [sunos]
|
os: [sunos]
|
||||||
|
|
||||||
'@esbuild/sunos-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [sunos]
|
|
||||||
|
|
||||||
'@esbuild/sunos-x64@0.25.9':
|
'@esbuild/sunos-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==}
|
resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4194,12 +4067,6 @@ packages:
|
|||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@esbuild/win32-arm64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@esbuild/win32-arm64@0.25.9':
|
'@esbuild/win32-arm64@0.25.9':
|
||||||
resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==}
|
resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4248,12 +4115,6 @@ packages:
|
|||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@esbuild/win32-ia32@0.25.4':
|
|
||||||
resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ia32]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@esbuild/win32-ia32@0.25.9':
|
'@esbuild/win32-ia32@0.25.9':
|
||||||
resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==}
|
resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4302,12 +4163,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@esbuild/win32-x64@0.25.4':
|
|
||||||
resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@esbuild/win32-x64@0.25.9':
|
'@esbuild/win32-x64@0.25.9':
|
||||||
resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==}
|
resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4829,9 +4684,6 @@ packages:
|
|||||||
'@jridgewell/sourcemap-codec@1.5.5':
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
'@jridgewell/trace-mapping@0.3.22':
|
|
||||||
resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==}
|
|
||||||
|
|
||||||
'@jridgewell/trace-mapping@0.3.25':
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||||
|
|
||||||
@@ -5209,12 +5061,6 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
deprecated: This functionality has been moved to @npmcli/fs
|
deprecated: This functionality has been moved to @npmcli/fs
|
||||||
|
|
||||||
'@number-flow/react@0.3.5':
|
|
||||||
resolution: {integrity: sha512-jkN4hqdYVbmxlEHD8sPF98f3AmQ3wGhHRJHYfgX9p9TsO3UyEky687qX8HSnTsk0ja6ZULzuHTA8MWoWqqTOQA==}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^18 || ^19.0.0-rc-915b914b3a-20240515
|
|
||||||
react-dom: ^18
|
|
||||||
|
|
||||||
'@number-flow/react@0.5.10':
|
'@number-flow/react@0.5.10':
|
||||||
resolution: {integrity: sha512-a8Wh5eNITn7Km4xbddAH7QH8eNmnduR6k34ER1hkHSGO4H2yU1DDnuAWLQM99vciGInFODemSc0tdxrXkJEpbA==}
|
resolution: {integrity: sha512-a8Wh5eNITn7Km4xbddAH7QH8eNmnduR6k34ER1hkHSGO4H2yU1DDnuAWLQM99vciGInFODemSc0tdxrXkJEpbA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -11474,11 +11320,6 @@ packages:
|
|||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
esbuild@0.25.4:
|
|
||||||
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
esbuild@0.25.9:
|
esbuild@0.25.9:
|
||||||
resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==}
|
resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -11520,8 +11361,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
esm-env@1.2.2:
|
esm-env-runtime@0.1.1:
|
||||||
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
|
resolution: {integrity: sha512-s5c/JKEF8faaXr3y1O9IZljnVO4FXFvmxB+/dGAKWUQF2nyjsoALGN5MCNu4ZLbAVLmtNFwU0fwb8FExIRwWmw==}
|
||||||
|
engines: {pnpm: ^9.0.0}
|
||||||
|
|
||||||
esprima@4.0.1:
|
esprima@4.0.1:
|
||||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||||
@@ -13929,8 +13771,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
miniflare@4.20251008.0:
|
miniflare@4.20260111.0:
|
||||||
resolution: {integrity: sha512-sKCNYNzXG6l8qg0Oo7y8WcDKcpbgw0qwZsxNpdZilFTR4EavRow2TlcwuPSVN99jqAjhz0M4VXvTdSGdtJ2VfQ==}
|
resolution: {integrity: sha512-pUsbDlumPaTzliA+J9HMAM74nLR8wqpCQNOESximab51jAfvL7ZaP5Npzh4PWNV0Jfq28tlqazakuJcw6w5qlA==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -14355,9 +14197,6 @@ packages:
|
|||||||
nullthrows@1.1.1:
|
nullthrows@1.1.1:
|
||||||
resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
|
resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
|
||||||
|
|
||||||
number-flow@0.3.10:
|
|
||||||
resolution: {integrity: sha512-BpNMhQnRAHOFbi0giD+dMnDoaPibVW22Vl2CWfZZIlpgTtixmbPm+Cv7a7F7FrEc/dTOECMS/T8V5rltIGI0tw==}
|
|
||||||
|
|
||||||
number-flow@0.5.8:
|
number-flow@0.5.8:
|
||||||
resolution: {integrity: sha512-FPr1DumWyGi5Nucoug14bC6xEz70A1TnhgSHhKyfqjgji2SOTz+iLJxKtv37N5JyJbteGYCm6NQ9p1O4KZ7iiA==}
|
resolution: {integrity: sha512-FPr1DumWyGi5Nucoug14bC6xEz70A1TnhgSHhKyfqjgji2SOTz+iLJxKtv37N5JyJbteGYCm6NQ9p1O4KZ7iiA==}
|
||||||
|
|
||||||
@@ -18102,17 +17941,17 @@ packages:
|
|||||||
wonka@4.0.15:
|
wonka@4.0.15:
|
||||||
resolution: {integrity: sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==}
|
resolution: {integrity: sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==}
|
||||||
|
|
||||||
workerd@1.20251008.0:
|
workerd@1.20260111.0:
|
||||||
resolution: {integrity: sha512-HwaJmXO3M1r4S8x2ea2vy8Rw/y/38HRQuK/gNDRQ7w9cJXn6xSl1sIIqKCffULSUjul3wV3I3Nd/GfbmsRReEA==}
|
resolution: {integrity: sha512-ov6Pt4k6d/ALfJja/EIHohT9IrY/f6GAa0arWEPat2qekp78xHbVM7jSxNWAMbaE7ZmnQQIFEGD1ZhAWZmQKIg==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
wrangler@4.42.2:
|
wrangler@4.59.1:
|
||||||
resolution: {integrity: sha512-1iTnbjB4F12KSP1zbfxQL495xarS+vdrZnulQP2SEcAxDTUGn7N9zk1O2WtFOc+Fhcgl+9/sdz/4AL9pF34Pwg==}
|
resolution: {integrity: sha512-5DddGSNxHd6dOjREWTDQdovQlZ1Lh80NNRXZFQ4/CrK3fNyVIBj9tqCs9pmXMNrKQ/AnKNeYzEs/l1kr8rHhOg==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=20.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@cloudflare/workers-types': ^4.20251008.0
|
'@cloudflare/workers-types': ^4.20260111.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
'@cloudflare/workers-types':
|
'@cloudflare/workers-types':
|
||||||
optional: true
|
optional: true
|
||||||
@@ -18348,9 +18187,6 @@ packages:
|
|||||||
typescript: ^4.9.4 || ^5.0.2
|
typescript: ^4.9.4 || ^5.0.2
|
||||||
zod: ^3
|
zod: ^3
|
||||||
|
|
||||||
zod@3.22.3:
|
|
||||||
resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==}
|
|
||||||
|
|
||||||
zod@3.24.2:
|
zod@3.24.2:
|
||||||
resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==}
|
resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==}
|
||||||
|
|
||||||
@@ -19972,42 +19808,47 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime: 3.0.0
|
mime: 3.0.0
|
||||||
|
|
||||||
'@cloudflare/unenv-preset@2.7.7(unenv@2.0.0-rc.21)(workerd@1.20251008.0)':
|
'@cloudflare/kv-asset-handler@0.4.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
unenv: 2.0.0-rc.21
|
mime: 3.0.0
|
||||||
optionalDependencies:
|
|
||||||
workerd: 1.20251008.0
|
|
||||||
|
|
||||||
'@cloudflare/vite-plugin@1.13.12(vite@6.3.5(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.27.1)(tsx@4.20.5)(yaml@2.8.2))(workerd@1.20251008.0)(wrangler@4.42.2)':
|
'@cloudflare/unenv-preset@2.9.0(unenv@2.0.0-rc.24)(workerd@1.20260111.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cloudflare/unenv-preset': 2.7.7(unenv@2.0.0-rc.21)(workerd@1.20251008.0)
|
unenv: 2.0.0-rc.24
|
||||||
|
optionalDependencies:
|
||||||
|
workerd: 1.20260111.0
|
||||||
|
|
||||||
|
'@cloudflare/vite-plugin@1.20.3(vite@6.3.5(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.27.1)(tsx@4.20.5)(yaml@2.8.2))(workerd@1.20260111.0)(wrangler@4.59.1)':
|
||||||
|
dependencies:
|
||||||
|
'@cloudflare/unenv-preset': 2.9.0(unenv@2.0.0-rc.24)(workerd@1.20260111.0)
|
||||||
'@remix-run/node-fetch-server': 0.8.1
|
'@remix-run/node-fetch-server': 0.8.1
|
||||||
|
defu: 6.1.4
|
||||||
get-port: 7.1.0
|
get-port: 7.1.0
|
||||||
miniflare: 4.20251008.0
|
miniflare: 4.20260111.0
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
tinyglobby: 0.2.14
|
tinyglobby: 0.2.15
|
||||||
unenv: 2.0.0-rc.21
|
unenv: 2.0.0-rc.24
|
||||||
vite: 6.3.5(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.27.1)(tsx@4.20.5)(yaml@2.8.2)
|
vite: 6.3.5(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.27.1)(tsx@4.20.5)(yaml@2.8.2)
|
||||||
wrangler: 4.42.2
|
wrangler: 4.59.1
|
||||||
ws: 8.18.0
|
ws: 8.18.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
- workerd
|
- workerd
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-64@1.20251008.0':
|
'@cloudflare/workerd-darwin-64@1.20260111.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-darwin-arm64@1.20251008.0':
|
'@cloudflare/workerd-darwin-arm64@1.20260111.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-64@1.20251008.0':
|
'@cloudflare/workerd-linux-64@1.20260111.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-linux-arm64@1.20251008.0':
|
'@cloudflare/workerd-linux-arm64@1.20260111.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@cloudflare/workerd-windows-64@1.20251008.0':
|
'@cloudflare/workerd-windows-64@1.20260111.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@colors/colors@1.6.0': {}
|
'@colors/colors@1.6.0': {}
|
||||||
@@ -20147,9 +19988,6 @@ snapshots:
|
|||||||
'@esbuild/aix-ppc64@0.25.3':
|
'@esbuild/aix-ppc64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.9':
|
'@esbuild/aix-ppc64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20174,9 +20012,6 @@ snapshots:
|
|||||||
'@esbuild/android-arm64@0.25.3':
|
'@esbuild/android-arm64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/android-arm64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/android-arm64@0.25.9':
|
'@esbuild/android-arm64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20201,9 +20036,6 @@ snapshots:
|
|||||||
'@esbuild/android-arm@0.25.3':
|
'@esbuild/android-arm@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/android-arm@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/android-arm@0.25.9':
|
'@esbuild/android-arm@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20228,9 +20060,6 @@ snapshots:
|
|||||||
'@esbuild/android-x64@0.25.3':
|
'@esbuild/android-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/android-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/android-x64@0.25.9':
|
'@esbuild/android-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20255,9 +20084,6 @@ snapshots:
|
|||||||
'@esbuild/darwin-arm64@0.25.3':
|
'@esbuild/darwin-arm64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/darwin-arm64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/darwin-arm64@0.25.9':
|
'@esbuild/darwin-arm64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20282,9 +20108,6 @@ snapshots:
|
|||||||
'@esbuild/darwin-x64@0.25.3':
|
'@esbuild/darwin-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/darwin-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/darwin-x64@0.25.9':
|
'@esbuild/darwin-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20309,9 +20132,6 @@ snapshots:
|
|||||||
'@esbuild/freebsd-arm64@0.25.3':
|
'@esbuild/freebsd-arm64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/freebsd-arm64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/freebsd-arm64@0.25.9':
|
'@esbuild/freebsd-arm64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20336,9 +20156,6 @@ snapshots:
|
|||||||
'@esbuild/freebsd-x64@0.25.3':
|
'@esbuild/freebsd-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/freebsd-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/freebsd-x64@0.25.9':
|
'@esbuild/freebsd-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20363,9 +20180,6 @@ snapshots:
|
|||||||
'@esbuild/linux-arm64@0.25.3':
|
'@esbuild/linux-arm64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-arm64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-arm64@0.25.9':
|
'@esbuild/linux-arm64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20390,9 +20204,6 @@ snapshots:
|
|||||||
'@esbuild/linux-arm@0.25.3':
|
'@esbuild/linux-arm@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-arm@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-arm@0.25.9':
|
'@esbuild/linux-arm@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20417,9 +20228,6 @@ snapshots:
|
|||||||
'@esbuild/linux-ia32@0.25.3':
|
'@esbuild/linux-ia32@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-ia32@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-ia32@0.25.9':
|
'@esbuild/linux-ia32@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20444,9 +20252,6 @@ snapshots:
|
|||||||
'@esbuild/linux-loong64@0.25.3':
|
'@esbuild/linux-loong64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-loong64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-loong64@0.25.9':
|
'@esbuild/linux-loong64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20471,9 +20276,6 @@ snapshots:
|
|||||||
'@esbuild/linux-mips64el@0.25.3':
|
'@esbuild/linux-mips64el@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-mips64el@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-mips64el@0.25.9':
|
'@esbuild/linux-mips64el@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20498,9 +20300,6 @@ snapshots:
|
|||||||
'@esbuild/linux-ppc64@0.25.3':
|
'@esbuild/linux-ppc64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-ppc64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-ppc64@0.25.9':
|
'@esbuild/linux-ppc64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20525,9 +20324,6 @@ snapshots:
|
|||||||
'@esbuild/linux-riscv64@0.25.3':
|
'@esbuild/linux-riscv64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-riscv64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-riscv64@0.25.9':
|
'@esbuild/linux-riscv64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20552,9 +20348,6 @@ snapshots:
|
|||||||
'@esbuild/linux-s390x@0.25.3':
|
'@esbuild/linux-s390x@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-s390x@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-s390x@0.25.9':
|
'@esbuild/linux-s390x@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20579,9 +20372,6 @@ snapshots:
|
|||||||
'@esbuild/linux-x64@0.25.3':
|
'@esbuild/linux-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/linux-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-x64@0.25.9':
|
'@esbuild/linux-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20597,9 +20387,6 @@ snapshots:
|
|||||||
'@esbuild/netbsd-arm64@0.25.3':
|
'@esbuild/netbsd-arm64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/netbsd-arm64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/netbsd-arm64@0.25.9':
|
'@esbuild/netbsd-arm64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20624,9 +20411,6 @@ snapshots:
|
|||||||
'@esbuild/netbsd-x64@0.25.3':
|
'@esbuild/netbsd-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/netbsd-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/netbsd-x64@0.25.9':
|
'@esbuild/netbsd-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20642,9 +20426,6 @@ snapshots:
|
|||||||
'@esbuild/openbsd-arm64@0.25.3':
|
'@esbuild/openbsd-arm64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/openbsd-arm64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/openbsd-arm64@0.25.9':
|
'@esbuild/openbsd-arm64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20669,9 +20450,6 @@ snapshots:
|
|||||||
'@esbuild/openbsd-x64@0.25.3':
|
'@esbuild/openbsd-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/openbsd-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/openbsd-x64@0.25.9':
|
'@esbuild/openbsd-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20708,9 +20486,6 @@ snapshots:
|
|||||||
'@esbuild/sunos-x64@0.25.3':
|
'@esbuild/sunos-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/sunos-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/sunos-x64@0.25.9':
|
'@esbuild/sunos-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20735,9 +20510,6 @@ snapshots:
|
|||||||
'@esbuild/win32-arm64@0.25.3':
|
'@esbuild/win32-arm64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/win32-arm64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/win32-arm64@0.25.9':
|
'@esbuild/win32-arm64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20762,9 +20534,6 @@ snapshots:
|
|||||||
'@esbuild/win32-ia32@0.25.3':
|
'@esbuild/win32-ia32@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/win32-ia32@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/win32-ia32@0.25.9':
|
'@esbuild/win32-ia32@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -20789,9 +20558,6 @@ snapshots:
|
|||||||
'@esbuild/win32-x64@0.25.3':
|
'@esbuild/win32-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@esbuild/win32-x64@0.25.4':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/win32-x64@0.25.9':
|
'@esbuild/win32-x64@0.25.9':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -21280,8 +21046,7 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@img/colour@1.0.0':
|
'@img/colour@1.0.0': {}
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-darwin-arm64@0.33.5':
|
'@img/sharp-darwin-arm64@0.33.5':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@@ -21521,7 +21286,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/set-array': 1.1.2
|
'@jridgewell/set-array': 1.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
'@jridgewell/trace-mapping': 0.3.22
|
'@jridgewell/trace-mapping': 0.3.30
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.5':
|
'@jridgewell/gen-mapping@0.3.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -21549,11 +21314,6 @@ snapshots:
|
|||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
'@jridgewell/trace-mapping@0.3.22':
|
|
||||||
dependencies:
|
|
||||||
'@jridgewell/resolve-uri': 3.1.2
|
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
|
||||||
|
|
||||||
'@jridgewell/trace-mapping@0.3.25':
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
@@ -21944,16 +21704,9 @@ snapshots:
|
|||||||
mkdirp: 1.0.4
|
mkdirp: 1.0.4
|
||||||
rimraf: 3.0.2
|
rimraf: 3.0.2
|
||||||
|
|
||||||
'@number-flow/react@0.3.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
|
|
||||||
dependencies:
|
|
||||||
esm-env: 1.2.2
|
|
||||||
number-flow: 0.3.10
|
|
||||||
react: 19.2.3
|
|
||||||
react-dom: 19.2.3(react@19.2.3)
|
|
||||||
|
|
||||||
'@number-flow/react@0.5.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
|
'@number-flow/react@0.5.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
esm-env: 1.2.2
|
esm-env: esm-env-runtime@0.1.1
|
||||||
number-flow: 0.5.8
|
number-flow: 0.5.8
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-dom: 19.2.3(react@19.2.3)
|
react-dom: 19.2.3(react@19.2.3)
|
||||||
@@ -29540,34 +29293,6 @@ snapshots:
|
|||||||
'@esbuild/win32-ia32': 0.25.3
|
'@esbuild/win32-ia32': 0.25.3
|
||||||
'@esbuild/win32-x64': 0.25.3
|
'@esbuild/win32-x64': 0.25.3
|
||||||
|
|
||||||
esbuild@0.25.4:
|
|
||||||
optionalDependencies:
|
|
||||||
'@esbuild/aix-ppc64': 0.25.4
|
|
||||||
'@esbuild/android-arm': 0.25.4
|
|
||||||
'@esbuild/android-arm64': 0.25.4
|
|
||||||
'@esbuild/android-x64': 0.25.4
|
|
||||||
'@esbuild/darwin-arm64': 0.25.4
|
|
||||||
'@esbuild/darwin-x64': 0.25.4
|
|
||||||
'@esbuild/freebsd-arm64': 0.25.4
|
|
||||||
'@esbuild/freebsd-x64': 0.25.4
|
|
||||||
'@esbuild/linux-arm': 0.25.4
|
|
||||||
'@esbuild/linux-arm64': 0.25.4
|
|
||||||
'@esbuild/linux-ia32': 0.25.4
|
|
||||||
'@esbuild/linux-loong64': 0.25.4
|
|
||||||
'@esbuild/linux-mips64el': 0.25.4
|
|
||||||
'@esbuild/linux-ppc64': 0.25.4
|
|
||||||
'@esbuild/linux-riscv64': 0.25.4
|
|
||||||
'@esbuild/linux-s390x': 0.25.4
|
|
||||||
'@esbuild/linux-x64': 0.25.4
|
|
||||||
'@esbuild/netbsd-arm64': 0.25.4
|
|
||||||
'@esbuild/netbsd-x64': 0.25.4
|
|
||||||
'@esbuild/openbsd-arm64': 0.25.4
|
|
||||||
'@esbuild/openbsd-x64': 0.25.4
|
|
||||||
'@esbuild/sunos-x64': 0.25.4
|
|
||||||
'@esbuild/win32-arm64': 0.25.4
|
|
||||||
'@esbuild/win32-ia32': 0.25.4
|
|
||||||
'@esbuild/win32-x64': 0.25.4
|
|
||||||
|
|
||||||
esbuild@0.25.9:
|
esbuild@0.25.9:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/aix-ppc64': 0.25.9
|
'@esbuild/aix-ppc64': 0.25.9
|
||||||
@@ -29669,7 +29394,7 @@ snapshots:
|
|||||||
|
|
||||||
escape-string-regexp@5.0.0: {}
|
escape-string-regexp@5.0.0: {}
|
||||||
|
|
||||||
esm-env@1.2.2: {}
|
esm-env-runtime@0.1.1: {}
|
||||||
|
|
||||||
esprima@4.0.1: {}
|
esprima@4.0.1: {}
|
||||||
|
|
||||||
@@ -32834,20 +32559,20 @@ snapshots:
|
|||||||
|
|
||||||
mimic-fn@4.0.0: {}
|
mimic-fn@4.0.0: {}
|
||||||
|
|
||||||
miniflare@4.20251008.0:
|
miniflare@4.20260111.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cspotcode/source-map-support': 0.8.1
|
'@cspotcode/source-map-support': 0.8.1
|
||||||
acorn: 8.14.0
|
acorn: 8.14.0
|
||||||
acorn-walk: 8.3.2
|
acorn-walk: 8.3.2
|
||||||
exit-hook: 2.2.1
|
exit-hook: 2.2.1
|
||||||
glob-to-regexp: 0.4.1
|
glob-to-regexp: 0.4.1
|
||||||
sharp: 0.33.5
|
sharp: 0.34.5
|
||||||
stoppable: 1.1.0
|
stoppable: 1.1.0
|
||||||
undici: 7.14.0
|
undici: 7.14.0
|
||||||
workerd: 1.20251008.0
|
workerd: 1.20260111.0
|
||||||
ws: 8.18.0
|
ws: 8.18.0
|
||||||
youch: 4.1.0-beta.10
|
youch: 4.1.0-beta.10
|
||||||
zod: 3.22.3
|
zod: 3.25.76
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
@@ -33322,7 +33047,7 @@ snapshots:
|
|||||||
unstorage: 1.17.3(db0@0.3.4)(ioredis@5.8.2)
|
unstorage: 1.17.3(db0@0.3.4)(ioredis@5.8.2)
|
||||||
untyped: 2.0.0
|
untyped: 2.0.0
|
||||||
unwasm: 0.3.11
|
unwasm: 0.3.11
|
||||||
youch: 4.1.0-beta.11
|
youch: 4.1.0-beta.13
|
||||||
youch-core: 0.3.3
|
youch-core: 0.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@azure/app-configuration'
|
- '@azure/app-configuration'
|
||||||
@@ -33445,13 +33170,9 @@ snapshots:
|
|||||||
|
|
||||||
nullthrows@1.1.1: {}
|
nullthrows@1.1.1: {}
|
||||||
|
|
||||||
number-flow@0.3.10:
|
|
||||||
dependencies:
|
|
||||||
esm-env: 1.2.2
|
|
||||||
|
|
||||||
number-flow@0.5.8:
|
number-flow@0.5.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
esm-env: 1.2.2
|
esm-env: esm-env-runtime@0.1.1
|
||||||
|
|
||||||
nuqs@2.5.2(patch_hash=4f93812bf7a04685f9477b2935e3acbf2aa24dfbb1b00b9ae0ed8f7a2877a98e)(@tanstack/react-router@1.132.47(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@16.0.7(@babel/core@7.28.3)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3):
|
nuqs@2.5.2(patch_hash=4f93812bf7a04685f9477b2935e3acbf2aa24dfbb1b00b9ae0ed8f7a2877a98e)(@tanstack/react-router@1.132.47(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(next@16.0.7(@babel/core@7.28.3)(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -35789,7 +35510,6 @@ snapshots:
|
|||||||
'@img/sharp-win32-arm64': 0.34.5
|
'@img/sharp-win32-arm64': 0.34.5
|
||||||
'@img/sharp-win32-ia32': 0.34.5
|
'@img/sharp-win32-ia32': 0.34.5
|
||||||
'@img/sharp-win32-x64': 0.34.5
|
'@img/sharp-win32-x64': 0.34.5
|
||||||
optional: true
|
|
||||||
|
|
||||||
shebang-command@1.2.0:
|
shebang-command@1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -37678,24 +37398,24 @@ snapshots:
|
|||||||
|
|
||||||
wonka@4.0.15: {}
|
wonka@4.0.15: {}
|
||||||
|
|
||||||
workerd@1.20251008.0:
|
workerd@1.20260111.0:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@cloudflare/workerd-darwin-64': 1.20251008.0
|
'@cloudflare/workerd-darwin-64': 1.20260111.0
|
||||||
'@cloudflare/workerd-darwin-arm64': 1.20251008.0
|
'@cloudflare/workerd-darwin-arm64': 1.20260111.0
|
||||||
'@cloudflare/workerd-linux-64': 1.20251008.0
|
'@cloudflare/workerd-linux-64': 1.20260111.0
|
||||||
'@cloudflare/workerd-linux-arm64': 1.20251008.0
|
'@cloudflare/workerd-linux-arm64': 1.20260111.0
|
||||||
'@cloudflare/workerd-windows-64': 1.20251008.0
|
'@cloudflare/workerd-windows-64': 1.20260111.0
|
||||||
|
|
||||||
wrangler@4.42.2:
|
wrangler@4.59.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cloudflare/kv-asset-handler': 0.4.0
|
'@cloudflare/kv-asset-handler': 0.4.1
|
||||||
'@cloudflare/unenv-preset': 2.7.7(unenv@2.0.0-rc.21)(workerd@1.20251008.0)
|
'@cloudflare/unenv-preset': 2.9.0(unenv@2.0.0-rc.24)(workerd@1.20260111.0)
|
||||||
blake3-wasm: 2.1.5
|
blake3-wasm: 2.1.5
|
||||||
esbuild: 0.25.4
|
esbuild: 0.27.0
|
||||||
miniflare: 4.20251008.0
|
miniflare: 4.20260111.0
|
||||||
path-to-regexp: 6.3.0
|
path-to-regexp: 6.3.0
|
||||||
unenv: 2.0.0-rc.21
|
unenv: 2.0.0-rc.24
|
||||||
workerd: 1.20251008.0
|
workerd: 1.20260111.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -37860,8 +37580,8 @@ snapshots:
|
|||||||
youch@4.1.0-beta.10:
|
youch@4.1.0-beta.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@poppinss/colors': 4.1.5
|
'@poppinss/colors': 4.1.5
|
||||||
'@poppinss/dumper': 0.6.4
|
'@poppinss/dumper': 0.6.5
|
||||||
'@speed-highlight/core': 1.2.7
|
'@speed-highlight/core': 1.2.12
|
||||||
cookie: 1.0.2
|
cookie: 1.0.2
|
||||||
youch-core: 0.3.3
|
youch-core: 0.3.3
|
||||||
|
|
||||||
@@ -37923,8 +37643,6 @@ snapshots:
|
|||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
zod: 3.25.76
|
zod: 3.25.76
|
||||||
|
|
||||||
zod@3.22.3: {}
|
|
||||||
|
|
||||||
zod@3.24.2: {}
|
zod@3.24.2: {}
|
||||||
|
|
||||||
zod@3.25.76: {}
|
zod@3.25.76: {}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export default ['packages/*', 'apps/*'];
|
export default ['packages/*', 'apps/*', '!apps/start'];
|
||||||
|
|||||||
Reference in New Issue
Block a user