mirror of
https://github.com/Mail-0/Zero.git
synced 2026-06-28 06:46:15 +00:00
feat: fix eslint
This commit is contained in:
@@ -22,6 +22,7 @@ RESEND_API_KEY=
|
||||
|
||||
# OpenAI API Key
|
||||
OPENAI_API_KEY=
|
||||
PERPLEXITY_API_KEY=
|
||||
|
||||
#AI PROMPT
|
||||
AI_SYSTEM_PROMPT=""
|
||||
|
||||
@@ -166,22 +166,23 @@ export default function OpenPage() {
|
||||
}, [initialContributors, additionalContributors]);
|
||||
|
||||
const { data: repoData, error: repoError } = useQuery({
|
||||
queryFn: () => fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json()),
|
||||
queryFn: () =>
|
||||
fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json() as any),
|
||||
queryKey: ['repo-data', REPOSITORY],
|
||||
});
|
||||
|
||||
const { data: commitsData, error: commitsError } = useQuery({
|
||||
queryFn: () =>
|
||||
fetch(`https://api.github.com/repos/${REPOSITORY}/commits?per_page=100`).then((res) =>
|
||||
res.json(),
|
||||
fetch(`https://api.github.com/repos/${REPOSITORY}/commits?per_page=100`).then(
|
||||
(res) => res.json() as any,
|
||||
),
|
||||
queryKey: ['commits-data', REPOSITORY],
|
||||
});
|
||||
|
||||
const { data: prsData, error: prsError } = useQuery({
|
||||
queryFn: () =>
|
||||
fetch(`https://api.github.com/repos/${REPOSITORY}/pulls?state=open`).then((res) =>
|
||||
res.json(),
|
||||
fetch(`https://api.github.com/repos/${REPOSITORY}/pulls?state=open`).then(
|
||||
(res) => res.json() as any,
|
||||
),
|
||||
queryKey: ['prs-data', REPOSITORY],
|
||||
});
|
||||
@@ -746,19 +747,6 @@ export default function OpenPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style jsx global>{`
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
|
||||
<div>
|
||||
<Tabs defaultValue="grid" className="w-full">
|
||||
<div className="mb-6 flex justify-center">
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/components/ui/dialog';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from '@/components/ui/accordion';
|
||||
import { COOKIE_CATEGORIES, type CookieCategory } from '@/lib/cookies';
|
||||
import { useCookies } from '@/providers/cookie-provider';
|
||||
import { CookieTrigger } from './cookie-trigger';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { X, Cookie } from 'lucide-react';
|
||||
|
||||
interface CookieConsentProps {
|
||||
children?: React.ReactNode;
|
||||
showFloatingButton?: boolean;
|
||||
}
|
||||
|
||||
export function CookieConsent({ children, showFloatingButton = true }: CookieConsentProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [showBanner, setShowBanner] = useState(false);
|
||||
const { preferences, updatePreference, acceptAll, rejectAll, isLoaded } = useCookies();
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoaded && !Object.values(preferences).some((value) => value)) {
|
||||
const timer = setTimeout(() => {
|
||||
setShowBanner(true);
|
||||
}, 1000);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [isLoaded, preferences]);
|
||||
|
||||
const handleSavePreferences = () => {
|
||||
setOpen(false);
|
||||
setShowBanner(false);
|
||||
};
|
||||
|
||||
const handleAcceptAll = () => {
|
||||
acceptAll();
|
||||
setOpen(false);
|
||||
setShowBanner(false);
|
||||
};
|
||||
|
||||
const handleRejectAll = () => {
|
||||
rejectAll();
|
||||
setOpen(false);
|
||||
setShowBanner(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{showFloatingButton && (
|
||||
<div className="fixed bottom-4 right-4 z-50">
|
||||
<CookieTrigger variant="icon" onClick={() => setOpen(true)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
{children && (
|
||||
<DialogTrigger asChild onClick={() => setOpen(true)}>
|
||||
{children}
|
||||
</DialogTrigger>
|
||||
)}
|
||||
<DialogContent className="flex max-h-[90vh] flex-col gap-0 border-zinc-200 bg-white p-0 outline-none dark:border-zinc-800 dark:bg-black">
|
||||
<div className="border-zinc-200 px-6 py-6 dark:border-zinc-800">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="my-2 text-xl text-zinc-900 dark:text-zinc-100">
|
||||
Cookie Settings
|
||||
</DialogTitle>
|
||||
<DialogDescription className="space-y-4">
|
||||
<span className="block text-sm text-zinc-600 dark:text-zinc-400">
|
||||
We use cookies and similar technologies to help personalize content, tailor and
|
||||
measure ads, and provide a better experience. By clicking "Accept All", you
|
||||
consent to all cookies. You can customize your choices by clicking "Customize" or
|
||||
reject all optional cookies by clicking "Reject All".
|
||||
</span>
|
||||
<span className="block text-sm text-zinc-600 dark:text-zinc-400">
|
||||
For California residents (CCPA): We do not sell your personal information.
|
||||
However, some cookies collect data for targeted advertising. To opt out of the
|
||||
sale of your data for targeted advertising purposes, click "Reject All" or disable
|
||||
Marketing cookies below.
|
||||
</span>
|
||||
<span className="block text-sm text-zinc-600 dark:text-zinc-400">
|
||||
You can change your preferences at any time by clicking the cookie settings button
|
||||
in the corner of the screen. For more information about how we use cookies, please
|
||||
see our{' '}
|
||||
<a href="/privacy" className="text-blue-500 hover:underline">
|
||||
Privacy Policy
|
||||
</a>
|
||||
.
|
||||
</span>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-y-auto px-6 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-zinc-200 dark:[&::-webkit-scrollbar-thumb]:bg-zinc-800 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar]:w-2">
|
||||
<div className="space-y-6 pb-4">
|
||||
<Accordion type="multiple" className="space-y-4">
|
||||
{(
|
||||
Object.entries(COOKIE_CATEGORIES) as [
|
||||
CookieCategory,
|
||||
(typeof COOKIE_CATEGORIES)[CookieCategory],
|
||||
][]
|
||||
).map(([category, info]) => (
|
||||
<AccordionItem
|
||||
key={category}
|
||||
value={category}
|
||||
className="rounded-lg border border-zinc-200 px-4 dark:border-zinc-800"
|
||||
>
|
||||
<div className="flex items-center justify-between py-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Label
|
||||
htmlFor={category}
|
||||
className="font-medium text-zinc-900 dark:text-zinc-100"
|
||||
>
|
||||
{info.name}
|
||||
{info.required && (
|
||||
<span className="ml-2 text-xs text-zinc-600 dark:text-zinc-400">
|
||||
(Required)
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
</div>
|
||||
<Switch
|
||||
id={category}
|
||||
checked={preferences[category]}
|
||||
disabled={info.required}
|
||||
onCheckedChange={(checked) => updatePreference(category, checked)}
|
||||
className="data-[state=checked]:bg-blue-600"
|
||||
/>
|
||||
</div>
|
||||
<AccordionTrigger className="mb-2 py-0 text-sm text-zinc-600 hover:no-underline dark:text-zinc-400 [&[data-state=open]>svg]:rotate-180">
|
||||
More information
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pb-4 pt-2">
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
{info.description}
|
||||
</p>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
|
||||
Duration:
|
||||
</p>
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
{category === 'necessary'
|
||||
? 'Session - These cookies are deleted when you close your browser'
|
||||
: category === 'functional'
|
||||
? '1 year - To remember your preferences'
|
||||
: category === 'analytics'
|
||||
? '2 years - To maintain consistent analytics data'
|
||||
: '90 days - Regular refresh of marketing preferences'}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-zinc-700 dark:text-zinc-300">
|
||||
Provider:
|
||||
</p>
|
||||
<p className="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
{category === 'necessary'
|
||||
? 'First party - Set by us'
|
||||
: category === 'functional'
|
||||
? 'First party and selected third parties'
|
||||
: category === 'analytics'
|
||||
? 'Google Analytics and similar services'
|
||||
: 'Various advertising partners'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-zinc-200 bg-white px-6 py-4 dark:border-zinc-800 dark:bg-black">
|
||||
<div className="flex flex-col-reverse sm:flex-row sm:justify-between sm:space-x-2">
|
||||
<div className="mt-2 flex flex-1 gap-2 sm:mt-0">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex-1 border-zinc-200 bg-transparent text-zinc-900 hover:bg-zinc-100 dark:border-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-900"
|
||||
onClick={handleRejectAll}
|
||||
>
|
||||
Reject All
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex-1 border-zinc-200 bg-transparent text-zinc-900 hover:bg-zinc-100 dark:border-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-900"
|
||||
onClick={handleAcceptAll}
|
||||
>
|
||||
Accept All
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleSavePreferences}
|
||||
className="flex-1 bg-black text-white hover:bg-zinc-800 sm:flex-none dark:bg-white dark:text-black dark:hover:bg-white"
|
||||
>
|
||||
Save Preferences
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{showBanner && (
|
||||
<Card className="animate-in fade-in slide-in-from-bottom-4 fixed bottom-4 left-4 right-4 z-40 border-zinc-200 bg-white p-4 shadow-lg duration-300 md:left-auto md:right-4 md:max-w-md dark:border-zinc-800 dark:bg-black">
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Cookie className="h-5 w-5 text-zinc-900 dark:text-zinc-100" />
|
||||
<h3 className="font-semibold text-zinc-900 dark:text-zinc-100">Cookie Preferences</h3>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setShowBanner(false)}
|
||||
className="text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</Button>
|
||||
</div>
|
||||
<p className="mb-4 text-sm text-zinc-600 dark:text-zinc-400">
|
||||
We use cookies to enhance your experience. By continuing to visit this site you agree to
|
||||
our use of cookies. For California residents: We do not sell personal information, but
|
||||
some cookies enable targeted advertising.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setOpen(true)}
|
||||
className="border-zinc-200 bg-transparent text-zinc-900 hover:bg-zinc-100 dark:border-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-900"
|
||||
>
|
||||
Customize
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleAcceptAll}
|
||||
className="bg-blue-600 text-white hover:bg-blue-700"
|
||||
>
|
||||
Accept All
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleRejectAll}
|
||||
className="text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
Reject All
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
'use client';
|
||||
|
||||
import React, {
|
||||
createContext,
|
||||
forwardRef,
|
||||
@@ -229,7 +227,7 @@ const Folder = forwardRef<HTMLDivElement, FolderProps & React.HTMLAttributes<HTM
|
||||
<Accordion.Item {...props} value={value} className="relative h-full overflow-hidden">
|
||||
<div
|
||||
className={cn(
|
||||
`hover:bg-black/10 flex items-center gap-1 rounded-lg px-2 py-1.5 text-sm dark:hover:bg-[#202020]`,
|
||||
`flex items-center gap-1 rounded-lg px-2 py-1.5 text-sm hover:bg-black/10 dark:hover:bg-[#202020]`,
|
||||
className,
|
||||
{
|
||||
'bg-sidebar-accent rounded-md': isSelect && isSelectable,
|
||||
|
||||
@@ -170,7 +170,6 @@ const createVariantsWithTransition = (
|
||||
visible: {
|
||||
...baseVariants.visible,
|
||||
transition: {
|
||||
// @ts-expect-error, fix later if needed
|
||||
...(hasTransition(baseVariants.visible) ? baseVariants.visible.transition : {}),
|
||||
...mainTransition,
|
||||
},
|
||||
@@ -178,7 +177,6 @@ const createVariantsWithTransition = (
|
||||
exit: {
|
||||
...baseVariants.exit,
|
||||
transition: {
|
||||
// @ts-expect-error, fix later if needed
|
||||
...(hasTransition(baseVariants.exit) ? baseVariants.exit.transition : {}),
|
||||
...mainTransition,
|
||||
staggerDirection: -1,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
'use client';
|
||||
|
||||
import { Switch as SwitchPrimitives } from 'radix-ui';
|
||||
import * as React from 'react';
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
// import { FlatCompat } from "@eslint/eslintrc";
|
||||
// import baseConfig from "@zero/eslint-config";
|
||||
// import { dirname, resolve } from "path";
|
||||
// import { fileURLToPath } from "url";
|
||||
|
||||
// const __filename = fileURLToPath(import.meta.url);
|
||||
// const __dirname = dirname(__filename);
|
||||
|
||||
// const compat = new FlatCompat({
|
||||
// baseDirectory: __dirname,
|
||||
// resolvePluginsRelativeTo: __dirname,
|
||||
// });
|
||||
|
||||
// /** @type {import("eslint").Linter.Config[]} */
|
||||
// const eslintConfig = [
|
||||
// ...baseConfig,
|
||||
// {
|
||||
// files: ["**/*.{ts,tsx}"],
|
||||
// languageOptions: {
|
||||
// parserOptions: {
|
||||
// project: resolve(__dirname, "./tsconfig.json"),
|
||||
// tsconfigRootDir: __dirname,
|
||||
// },
|
||||
// },
|
||||
// settings: {
|
||||
// "import/resolver": {
|
||||
// typescript: {
|
||||
// project: resolve(__dirname, "./tsconfig.json"),
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ...compat.extends("next/core-web-vitals"),
|
||||
// ];
|
||||
|
||||
// export default eslintConfig;
|
||||
3
apps/mail/eslint.config.ts
Normal file
3
apps/mail/eslint.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import config from '@zero/eslint-config';
|
||||
|
||||
export default config;
|
||||
@@ -1,137 +0,0 @@
|
||||
import type { CookieCategory } from './cookies';
|
||||
|
||||
interface CookieOptions {
|
||||
category: CookieCategory;
|
||||
path?: string;
|
||||
domain?: string;
|
||||
secure?: boolean;
|
||||
sameSite?: 'Strict' | 'Lax' | 'None';
|
||||
expires?: Date;
|
||||
}
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
path: '/',
|
||||
maxAge: 365 * 24 * 60 * 60,
|
||||
};
|
||||
|
||||
class CookieUtils {
|
||||
private static cookieRegistry: Map<string, CookieCategory> = new Map();
|
||||
|
||||
static registerCookie(name: string, category: CookieCategory) {
|
||||
this.cookieRegistry.set(name, category);
|
||||
}
|
||||
|
||||
static getCookieCategory(name: string): CookieCategory | undefined {
|
||||
return this.cookieRegistry.get(name);
|
||||
}
|
||||
|
||||
static setCookie(name: string, value: string, options: CookieOptions): void {
|
||||
const cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
||||
const cookieOptions: string[] = [];
|
||||
|
||||
if (options.path) cookieOptions.push(`path=${options.path}`);
|
||||
if (options.domain) cookieOptions.push(`domain=${options.domain}`);
|
||||
if (options.secure) cookieOptions.push('secure');
|
||||
if (options.sameSite) cookieOptions.push(`samesite=${options.sameSite}`);
|
||||
if (options.expires) cookieOptions.push(`expires=${options.expires.toUTCString()}`);
|
||||
|
||||
document.cookie = `${cookieString}${cookieOptions.length ? '; ' + cookieOptions.join('; ') : ''}`;
|
||||
}
|
||||
|
||||
static getCookie(name: string): string | null {
|
||||
const cookies = document.cookie.split(';');
|
||||
for (const cookie of cookies) {
|
||||
const parts = cookie.split('=').map((c) => c.trim());
|
||||
const cookieName = parts[0];
|
||||
const cookieValue = parts[1];
|
||||
if (cookieName === name && cookieValue !== undefined) {
|
||||
return decodeURIComponent(cookieValue);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static deleteCookie(name: string, options?: Pick<CookieOptions, 'path' | 'domain'>): void {
|
||||
const opts: CookieOptions = {
|
||||
...options,
|
||||
category: 'necessary',
|
||||
expires: new Date(0),
|
||||
};
|
||||
this.setCookie(name, '', opts);
|
||||
}
|
||||
|
||||
static getAllCookies(): { [key: string]: string } {
|
||||
return document.cookie.split(';').reduce(
|
||||
(acc, cookie) => {
|
||||
const [name, value] = cookie.split('=').map((c) => c.trim());
|
||||
if (name && value) {
|
||||
acc[name] = decodeURIComponent(value);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as { [key: string]: string },
|
||||
);
|
||||
}
|
||||
|
||||
static removeAllCookiesByCategory(category: CookieCategory) {
|
||||
const allCookies = this.getAllCookies();
|
||||
|
||||
Object.keys(allCookies).forEach((cookieName) => {
|
||||
const cookieCategory = this.getCookieCategory(cookieName);
|
||||
if (cookieCategory === category) {
|
||||
this.deleteCookie(cookieName, { path: '/' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static cleanupRejectedCookies(acceptedCategories: CookieCategory[]): void {
|
||||
const cookieMapping: Record<string, CookieCategory> = {
|
||||
_ga: 'analytics',
|
||||
_gid: 'analytics',
|
||||
_fbp: 'marketing',
|
||||
// TODO: Add more cookie mappings as needed
|
||||
};
|
||||
|
||||
const cookies = document.cookie.split(';');
|
||||
for (const cookie of cookies) {
|
||||
const parts = cookie.split('=').map((c) => c.trim());
|
||||
const cookieName = parts[0];
|
||||
if (
|
||||
cookieName &&
|
||||
cookieMapping[cookieName] &&
|
||||
!acceptedCategories.includes(cookieMapping[cookieName])
|
||||
) {
|
||||
this.deleteCookie(cookieName, { path: '/' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static cleanupMarketingCookies(): void {
|
||||
const marketingCookies = [
|
||||
'_fbp',
|
||||
'_gcl_au',
|
||||
'_uetsid',
|
||||
'_uetvid',
|
||||
// TODO: Add more marketing cookie names as needed
|
||||
];
|
||||
|
||||
marketingCookies.forEach((cookieName) => {
|
||||
this.deleteCookie(cookieName, { path: '/' });
|
||||
});
|
||||
}
|
||||
|
||||
static getCookiesByCategory(category: CookieCategory): string[] {
|
||||
const cookieMapping: Record<string, CookieCategory> = {
|
||||
_ga: 'analytics',
|
||||
_gid: 'analytics',
|
||||
_fbp: 'marketing',
|
||||
// TODO:Add more cookie mappings as needed
|
||||
};
|
||||
|
||||
return Object.entries(cookieMapping)
|
||||
.filter(([_, cookieCategory]) => cookieCategory === category)
|
||||
.map(([cookieName]) => cookieName);
|
||||
}
|
||||
}
|
||||
|
||||
export default CookieUtils;
|
||||
@@ -1,48 +0,0 @@
|
||||
import { TrackingCategory } from '@coinbase/cookie-manager';
|
||||
|
||||
export type CookieCategory = 'necessary' | 'functional' | 'analytics' | 'marketing';
|
||||
|
||||
export interface CategoryInfo {
|
||||
name: string;
|
||||
description: string;
|
||||
required?: boolean;
|
||||
trackingCategory: TrackingCategory;
|
||||
}
|
||||
|
||||
export interface CookiePreferences {
|
||||
necessary: boolean;
|
||||
analytics: boolean;
|
||||
marketing: boolean;
|
||||
preferences: boolean;
|
||||
}
|
||||
|
||||
export const COOKIE_CATEGORIES: Record<CookieCategory, CategoryInfo> = {
|
||||
necessary: {
|
||||
name: 'Strictly Necessary',
|
||||
description:
|
||||
'These cookies are essential for the website to function properly and cannot be switched off. They are usually only set in response to actions made by you such as setting your privacy preferences, logging in, or filling in forms.',
|
||||
required: true,
|
||||
trackingCategory: TrackingCategory.NECESSARY,
|
||||
},
|
||||
functional: {
|
||||
name: 'Functional',
|
||||
description:
|
||||
'These cookies enable the website to provide enhanced functionality and personalization. They may be set by us or by third-party providers whose services we have added to our pages. If you do not allow these cookies, some or all of these services may not function properly.',
|
||||
trackingCategory: TrackingCategory.FUNCTIONAL,
|
||||
},
|
||||
analytics: {
|
||||
name: 'Analytics & Performance',
|
||||
description:
|
||||
'These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us to know which pages are the most and least popular and see how visitors move around the site. All information these cookies collect is aggregated and therefore anonymous. If you do not allow these cookies we will not know when you have visited our site.',
|
||||
trackingCategory: TrackingCategory.PERFORMANCE,
|
||||
},
|
||||
marketing: {
|
||||
name: 'Marketing & Targeting',
|
||||
description:
|
||||
'These cookies may be set through our site by our advertising partners. They may be used by those companies to build a profile of your interests and show you relevant adverts on other sites. They do not store directly personal information but are based on uniquely identifying your browser and internet device. If you do not allow these cookies, you will experience less targeted advertising.',
|
||||
trackingCategory: TrackingCategory.TARGETING,
|
||||
},
|
||||
};
|
||||
|
||||
export const COOKIE_CONSENT_KEY = 'cookieConsent';
|
||||
export const COOKIE_PREFERENCES_KEY = 'cookiePreferences';
|
||||
@@ -1,18 +0,0 @@
|
||||
// add flags.ts
|
||||
import { statsigAdapter, type StatsigUser } from "@flags-sdk/statsig";
|
||||
import { flag, dedupe } from "flags/next";
|
||||
import type { Identify } from "flags";
|
||||
|
||||
export const identify = dedupe((async () => ({
|
||||
customIDs: { userID: Math.random().toString(36).slice(2) },
|
||||
// add any additional user properties you collect here
|
||||
})) satisfies Identify<StatsigUser>);
|
||||
|
||||
export const createFeatureGate = (key: string) => flag<boolean, StatsigUser>({
|
||||
key,
|
||||
adapter: statsigAdapter.featureGate((gate) => gate.value, { exposureLogging: true }),
|
||||
identify,
|
||||
decide() {
|
||||
return Math.random() > 0.1;
|
||||
},
|
||||
});
|
||||
@@ -8,7 +8,8 @@
|
||||
"build": "react-router build",
|
||||
"start": "wrangler dev --port 3000 --show-interactive-dev-session=false",
|
||||
"types": "wrangler types",
|
||||
"deploy": "wrangler deploy"
|
||||
"deploy": "wrangler deploy",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@11labs/react": "^0.1.3",
|
||||
@@ -43,7 +44,6 @@
|
||||
"@trpc/server": "catalog:",
|
||||
"@trpc/tanstack-react-query": "catalog:",
|
||||
"@zero/db": "workspace:*",
|
||||
"@zero/eslint-config": "workspace:*",
|
||||
"@zero/server": "workspace:*",
|
||||
"accept-language-parser": "^1.5.0",
|
||||
"ai": "^4.3.9",
|
||||
@@ -110,7 +110,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/vite-plugin": "^1.2.0",
|
||||
"@eslint/eslintrc": "3.3.0",
|
||||
"@tailwindcss/typography": "0.5.16",
|
||||
"@types/accept-language-parser": "^1.5.8",
|
||||
"@types/canvas-confetti": "1.9.0",
|
||||
@@ -119,13 +118,11 @@
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"@types/sanitize-html": "2.13.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.26.1",
|
||||
"@typescript-eslint/parser": "8.26.1",
|
||||
"@zero/eslint-config": "workspace:*",
|
||||
"@zero/tsconfig": "workspace:*",
|
||||
"drizzle-kit": "0.31.1",
|
||||
"eslint": "9.22.0",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "5.2.0",
|
||||
"eslint": "^9.27.0",
|
||||
"jiti": "2.4.2",
|
||||
"postcss": "8.5.3",
|
||||
"remeda": "2.21.3",
|
||||
"tailwind-scrollbar": "3.1.0",
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { COOKIE_CATEGORIES, type CookieCategory } from '@/lib/cookies';
|
||||
import CookieUtils from '@/lib/cookie-utils';
|
||||
|
||||
interface CookiePreferences {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
|
||||
interface CookieContextType {
|
||||
preferences: CookiePreferences;
|
||||
isLoaded: boolean;
|
||||
updatePreference: (category: CookieCategory, value: boolean) => void;
|
||||
acceptAll: () => void;
|
||||
rejectAll: () => void;
|
||||
hasConsent: boolean;
|
||||
}
|
||||
|
||||
const CookieContext = createContext<CookieContextType | null>(null);
|
||||
|
||||
const PREFERENCES_COOKIE = 'cookie_preferences';
|
||||
|
||||
export function CookieProvider({ children }: { children: React.ReactNode }) {
|
||||
const [preferences, setPreferences] = useState<CookiePreferences>(() =>
|
||||
Object.keys(COOKIE_CATEGORIES).reduce(
|
||||
(acc, key) => ({
|
||||
...acc,
|
||||
[key]: COOKIE_CATEGORIES[key as CookieCategory].required || false,
|
||||
}),
|
||||
{},
|
||||
),
|
||||
);
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const loadPreferences = () => {
|
||||
const storedPrefs = CookieUtils.getCookie(PREFERENCES_COOKIE);
|
||||
if (storedPrefs) {
|
||||
try {
|
||||
const parsedPrefs = JSON.parse(storedPrefs);
|
||||
Object.entries(COOKIE_CATEGORIES).forEach(([key, info]) => {
|
||||
if (info.required) {
|
||||
parsedPrefs[key] = true;
|
||||
}
|
||||
});
|
||||
setPreferences(parsedPrefs);
|
||||
} catch (error) {
|
||||
console.error('Error parsing cookie preferences:', error);
|
||||
}
|
||||
}
|
||||
setIsLoaded(true);
|
||||
};
|
||||
|
||||
loadPreferences();
|
||||
}, []);
|
||||
|
||||
const savePreferences = (newPreferences: CookiePreferences) => {
|
||||
// Store preferences with a 1-year expiry for GDPR compliance
|
||||
const oneYear = 365 * 24 * 60 * 60 * 1000;
|
||||
CookieUtils.setCookie(PREFERENCES_COOKIE, JSON.stringify(newPreferences), {
|
||||
category: 'necessary',
|
||||
expires: new Date(Date.now() + oneYear),
|
||||
sameSite: 'Lax',
|
||||
secure: true,
|
||||
});
|
||||
|
||||
const acceptedCategories = Object.entries(newPreferences)
|
||||
.filter(([_, accepted]) => accepted)
|
||||
.map(([category]) => category as CookieCategory);
|
||||
|
||||
CookieUtils.cleanupRejectedCookies(acceptedCategories);
|
||||
logConsent(newPreferences);
|
||||
};
|
||||
|
||||
const logConsent = (preferences: CookiePreferences) => {
|
||||
const consentData = {
|
||||
timestamp: new Date().toISOString(),
|
||||
preferences,
|
||||
userAgent: navigator.userAgent,
|
||||
// TODO: Add any other relevant data for compliance
|
||||
};
|
||||
|
||||
console.log('Cookie consent logged:', consentData);
|
||||
};
|
||||
|
||||
const updatePreference = (category: CookieCategory, value: boolean) => {
|
||||
const categoryInfo = COOKIE_CATEGORIES[category];
|
||||
if (categoryInfo.required) return;
|
||||
|
||||
const newPreferences = { ...preferences, [category]: value };
|
||||
setPreferences(newPreferences);
|
||||
savePreferences(newPreferences);
|
||||
|
||||
if (category === 'marketing' && !value) {
|
||||
CookieUtils.cleanupMarketingCookies();
|
||||
}
|
||||
};
|
||||
|
||||
const acceptAll = () => {
|
||||
const newPreferences = Object.keys(COOKIE_CATEGORIES).reduce(
|
||||
(acc, key) => ({ ...acc, [key]: true }),
|
||||
{},
|
||||
);
|
||||
setPreferences(newPreferences);
|
||||
savePreferences(newPreferences);
|
||||
};
|
||||
|
||||
const rejectAll = () => {
|
||||
const newPreferences = Object.keys(COOKIE_CATEGORIES).reduce(
|
||||
(acc, key) => ({
|
||||
...acc,
|
||||
[key]: COOKIE_CATEGORIES[key as CookieCategory].required || false,
|
||||
}),
|
||||
{},
|
||||
);
|
||||
setPreferences(newPreferences);
|
||||
savePreferences(newPreferences);
|
||||
};
|
||||
|
||||
const hasConsent = useMemo(
|
||||
() => Object.values(preferences).some((value) => value),
|
||||
[preferences],
|
||||
);
|
||||
|
||||
const value = {
|
||||
preferences,
|
||||
isLoaded,
|
||||
updatePreference,
|
||||
acceptAll,
|
||||
rejectAll,
|
||||
hasConsent,
|
||||
};
|
||||
|
||||
return <CookieContext.Provider value={value}>{children}</CookieContext.Provider>;
|
||||
}
|
||||
|
||||
export function useCookies() {
|
||||
const context = useContext(CookieContext);
|
||||
if (!context) {
|
||||
throw new Error('useCookies must be used within a CookieProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
@@ -1,21 +1,8 @@
|
||||
{
|
||||
"extends": "@zero/tsconfig/base",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"types": ["node", "vite/client"],
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
},
|
||||
|
||||
3
apps/server/eslint.config.ts
Normal file
3
apps/server/eslint.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import config from '@zero/eslint-config';
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,8 @@
|
||||
"scripts": {
|
||||
"dev": "wrangler dev --show-interactive-dev-session=false --experimental-vectorize-bind-to-prod --env local",
|
||||
"deploy": "wrangler deploy",
|
||||
"types": "wrangler types --env local"
|
||||
"types": "wrangler types --env local",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"exports": {
|
||||
"./trpc": "./src/trpc/index.ts",
|
||||
@@ -15,6 +16,7 @@
|
||||
"dependencies": {
|
||||
"@ai-sdk/google": "^1.2.18",
|
||||
"@ai-sdk/openai": "^1.3.21",
|
||||
"@ai-sdk/ui-utils": "1.2.11",
|
||||
"@coinbase/cookie-manager": "1.1.8",
|
||||
"@googleapis/gmail": "12.0.0",
|
||||
"@googleapis/people": "3.0.9",
|
||||
@@ -58,6 +60,10 @@
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/sanitize-html": "2.13.0",
|
||||
"@zero/eslint-config": "workspace:*",
|
||||
"@zero/tsconfig": "workspace:*",
|
||||
"eslint": "^9.27.0",
|
||||
"jiti": "2.4.2",
|
||||
"typescript": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { isToday, isThisMonth, differenceInCalendarMonths } from 'date-fns';
|
||||
import type { JSONContent } from 'novel';
|
||||
import type { Sender } from '../types';
|
||||
|
||||
export const FOLDERS = {
|
||||
@@ -43,13 +41,6 @@ export const getFolderTags = (folder: string): string[] => {
|
||||
return FOLDER_TAGS[folder] || [];
|
||||
};
|
||||
|
||||
export const getCookie = (key: string): string | null => {
|
||||
const cookies = Object.fromEntries(
|
||||
document.cookie.split('; ').map((v) => v.split(/=(.*)/s).map(decodeURIComponent)),
|
||||
);
|
||||
return cookies?.[key] ?? null;
|
||||
};
|
||||
|
||||
export const cleanEmailAddress = (email: string = '') => {
|
||||
return email.replace(/[<>]/g, '').trim();
|
||||
};
|
||||
@@ -101,112 +92,6 @@ export const getFileIcon = (mimeType: string): string => {
|
||||
return '📎'; // Default icon
|
||||
};
|
||||
|
||||
export const createAIJsonContent = (text: string): JSONContent => {
|
||||
// Try to identify common sign-off patterns with a more comprehensive regex
|
||||
const signOffPatterns = [
|
||||
/\b((?:Best regards|Regards|Sincerely|Thanks|Thank you|Cheers|Best|All the best|Yours truly|Yours sincerely|Kind regards|Cordially)(?:,)?)\s*\n+\s*([A-Za-z][A-Za-z\s.]*)$/i,
|
||||
];
|
||||
|
||||
let mainContent = text;
|
||||
let signatureLines: string[] = [];
|
||||
|
||||
// Extract sign-off if found
|
||||
for (const pattern of signOffPatterns) {
|
||||
const match = text.match(pattern);
|
||||
if (match) {
|
||||
// Find the index where the sign-off starts
|
||||
const signOffIndex = text.lastIndexOf(match[0]);
|
||||
if (signOffIndex > 0) {
|
||||
// Split the content
|
||||
mainContent = text.substring(0, signOffIndex).trim();
|
||||
|
||||
// Split the signature part into separate lines
|
||||
const signature = text.substring(signOffIndex).trim();
|
||||
signatureLines = signature
|
||||
.split(/\n+/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no signature was found with regex but there are newlines at the end,
|
||||
// check if the last lines could be a signature
|
||||
if (signatureLines.length === 0) {
|
||||
const allLines = text.split(/\n+/);
|
||||
if (allLines.length > 1) {
|
||||
// Check if last 1-3 lines might be a signature (short lines at the end)
|
||||
const potentialSigLines = allLines
|
||||
.slice(-3)
|
||||
.filter(
|
||||
(line) =>
|
||||
line.trim().length < 60 && !line.trim().endsWith('?') && !line.trim().endsWith('.'),
|
||||
);
|
||||
|
||||
if (potentialSigLines.length > 0) {
|
||||
signatureLines = potentialSigLines;
|
||||
mainContent = allLines
|
||||
.slice(0, allLines.length - potentialSigLines.length)
|
||||
.join('\n')
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Split the main content into paragraphs
|
||||
const paragraphs = mainContent
|
||||
.split(/\n\s*\n/)
|
||||
.map((p) => p.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
if (paragraphs.length === 0 && signatureLines.length === 0) {
|
||||
// If no paragraphs and no signature were found, treat the whole text as one paragraph
|
||||
paragraphs.push(text);
|
||||
}
|
||||
|
||||
// Create a content array with appropriate spacing between paragraphs
|
||||
const content = [];
|
||||
|
||||
paragraphs.forEach((paragraph, index) => {
|
||||
// Add the content paragraph
|
||||
content.push({
|
||||
type: 'paragraph',
|
||||
content: [{ type: 'text', text: paragraph }],
|
||||
});
|
||||
|
||||
// Add an empty paragraph between main paragraphs
|
||||
if (index < paragraphs.length - 1) {
|
||||
content.push({
|
||||
type: 'paragraph',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// If we found a signature, add it with proper spacing
|
||||
if (signatureLines.length > 0) {
|
||||
// Add spacing before the signature if there was content
|
||||
if (paragraphs.length > 0) {
|
||||
content.push({
|
||||
type: 'paragraph',
|
||||
});
|
||||
}
|
||||
|
||||
// Add each line of the signature as a separate paragraph
|
||||
signatureLines.forEach((line) => {
|
||||
content.push({
|
||||
type: 'paragraph',
|
||||
content: [{ type: 'text', text: line }],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'doc',
|
||||
content: content,
|
||||
};
|
||||
};
|
||||
|
||||
export const generateConversationId = (): string => {
|
||||
return `conv_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
||||
};
|
||||
|
||||
8
apps/server/src/overrides.d.ts
vendored
Normal file
8
apps/server/src/overrides.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
declare namespace Cloudflare {
|
||||
declare interface Env {
|
||||
zero: Fetcher & {
|
||||
subscribe: (data: { connectionId: string; providerId: string }) => Promise<void>;
|
||||
unsubscribe: (data: { connectionId: string; providerId: string }) => Promise<void>;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,4 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "preserve",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"emitDeclarationOnly": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
|
||||
"composite": true,
|
||||
"types": ["@types/node"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "worker-configuration.d.ts"]
|
||||
"extends": "@zero/tsconfig/base",
|
||||
"include": ["src/**/*.ts", "src/overrides.d.ts", "worker-configuration.d.ts"]
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"packageManager": "pnpm@10.11.0",
|
||||
"devDependencies": {
|
||||
"@clack/prompts": "0.10.1",
|
||||
"@zero/tsconfig": "workspace:*",
|
||||
"tiny-glob": "0.2.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
"extends": "@zero/tsconfig/base"
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
{
|
||||
"extends": "@zero/tsconfig/react-library.json",
|
||||
"include": [
|
||||
"src",
|
||||
"migrations"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
"extends": "@zero/tsconfig/base",
|
||||
"include": ["src", "migrations"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
16
packages/eslint-config/config.ts
Normal file
16
packages/eslint-config/config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import reactHooksPlugin from 'eslint-plugin-react-hooks';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores([
|
||||
'**/node_modules/**',
|
||||
'**/dist/**',
|
||||
'**/build/**',
|
||||
'**/.react-router/**',
|
||||
'**/.well-known/**',
|
||||
]),
|
||||
// @ts-expect-error
|
||||
tseslint.configs.recommended,
|
||||
reactHooksPlugin.configs['recommended-latest'],
|
||||
]);
|
||||
@@ -1,76 +0,0 @@
|
||||
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
||||
import tsPlugin from "@typescript-eslint/eslint-plugin";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
import eslint from "eslint";
|
||||
|
||||
/** @type {import("eslint").Linter.Config[]} */
|
||||
const config = [
|
||||
{
|
||||
ignores: ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/.well-known/**"],
|
||||
},
|
||||
{
|
||||
files: ["**/*.{js,mjs,cjs}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["**/*.{ts,tsx,js,jsx}"],
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
project: true,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
// @ts-expect-error - tsPlugin doesn't exactly match the type ESLint.Plugin
|
||||
"@typescript-eslint": tsPlugin,
|
||||
"react-hooks": reactHooksPlugin,
|
||||
},
|
||||
rules: {
|
||||
// Recommended lints
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
"@typescript-eslint/no-misused-promises": [
|
||||
2,
|
||||
{
|
||||
checksVoidReturn: {
|
||||
attributes: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
vars: "all",
|
||||
args: "after-used",
|
||||
caughtErrors: "all",
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
ignoreRestSiblings: false,
|
||||
destructuredArrayIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
|
||||
// Strict lints
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{
|
||||
prefer: "type-imports",
|
||||
fixStyle: "inline-type-imports",
|
||||
disallowTypeAnnotations: true, // This makes non-type imports for types an error
|
||||
},
|
||||
],
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default config;
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from "./eslint.config.mjs";
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"name": "@zero/eslint-config",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./config.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/eslint": "^9.6.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-config-next": "^14.1.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
||||
"@typescript-eslint/parser": "^8.32.1",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-import-resolver-typescript": "^4.3.5",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"typescript-eslint": "8.32.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"extends": "@zero/tsconfig/base.json",
|
||||
"extends": "@zero/tsconfig/base",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["eslint.config.mjs", "index.js"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@zero/tsconfig/base.json",
|
||||
"extends": "@zero/tsconfig/base",
|
||||
"include": ["."],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"declaration": false,
|
||||
"esModuleInterop": true,
|
||||
"incremental": false,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"es2022",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"module": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"moduleResolution": "NodeNext",
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"resolveJsonModule": true,
|
||||
"target": "ESNext",
|
||||
"lib": ["EsNext"],
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "ES2022",
|
||||
"verbatimModuleSyntax": false
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"allowArbitraryExtensions": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"plugins": [{ "name": "next" }],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowJs": true,
|
||||
"jsx": "preserve",
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
{
|
||||
"name": "@zero/tsconfig",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
"exports": {
|
||||
"./base": "./base.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
}
|
||||
886
pnpm-lock.yaml
generated
886
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,14 @@ packages:
|
||||
- packages/*
|
||||
- scripts/*
|
||||
catalog:
|
||||
zod: "^3.24.4"
|
||||
better-auth: "^1.2.8"
|
||||
autumn-js: "^0.0.36"
|
||||
superjson: "^2.2.2"
|
||||
"@trpc/server": "^11.1.2"
|
||||
"@trpc/client": "^11.1.2"
|
||||
"@trpc/tanstack-react-query": "^11.1.2"
|
||||
wrangler: "^4.16.0"
|
||||
typescript: "^5.8.3"
|
||||
zod: ^3.24.4
|
||||
better-auth: ^1.2.8
|
||||
autumn-js: ^0.0.36
|
||||
superjson: ^2.2.2
|
||||
'@trpc/server': ^11.1.2
|
||||
'@trpc/client': ^11.1.2
|
||||
'@trpc/tanstack-react-query': ^11.1.2
|
||||
wrangler: ^4.16.0
|
||||
typescript: ^5.8.3
|
||||
patchedDependencies:
|
||||
novel: patches/novel.patch
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"extends": "@zero/tsconfig/base.json"
|
||||
"extends": "@zero/tsconfig/base"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user