diff --git a/apps/collab-server/Dockerfile b/apps/collab-server/Dockerfile index d2816c8..e4a0b10 100644 --- a/apps/collab-server/Dockerfile +++ b/apps/collab-server/Dockerfile @@ -1,4 +1,7 @@ -FROM node:18-alpine AS base + +ARG NODE_VERSION=24-alpine + +FROM node:${NODE_VERSION} AS base EXPOSE 1234 FROM base AS builder @@ -6,7 +9,7 @@ RUN apk add --no-cache libc6-compat RUN apk update # Set working directory WORKDIR /app -RUN npm install --global turbo +RUN npm install --global turbo COPY --chown=node:node . . # https://turbo.build/repo/docs/reference/command-line-reference/prune RUN turbo prune @jotter/collab-server --docker diff --git a/apps/front-end/drizzle/0000_common_umar.sql b/apps/front-end/drizzle/0000_common_umar.sql deleted file mode 100644 index ac60c8b..0000000 --- a/apps/front-end/drizzle/0000_common_umar.sql +++ /dev/null @@ -1,53 +0,0 @@ -CREATE TABLE `account` ( - `userId` text NOT NULL, - `type` text NOT NULL, - `provider` text NOT NULL, - `providerAccountId` text NOT NULL, - `refresh_token` text, - `access_token` text, - `expires_at` integer, - `token_type` text, - `scope` text, - `id_token` text, - `session_state` text, - PRIMARY KEY(`provider`, `providerAccountId`) -); ---> statement-breakpoint -CREATE TABLE `document` ( - `name` text PRIMARY KEY NOT NULL, - `createdOn` integer, - `modifiedOn` integer, - `data` blob, - `id` text NOT NULL -); ---> statement-breakpoint -CREATE TABLE `notebook_document` ( - `notebookId` text PRIMARY KEY NOT NULL, - `documentName` text NOT NULL -); ---> statement-breakpoint -CREATE TABLE `notebook` ( - `id` text PRIMARY KEY NOT NULL, - `authorId` text NOT NULL -); ---> statement-breakpoint -CREATE TABLE `session` ( - `sessionToken` text PRIMARY KEY NOT NULL, - `userId` text NOT NULL, - `expires` integer NOT NULL -); ---> statement-breakpoint -CREATE TABLE `user` ( - `id` text PRIMARY KEY NOT NULL, - `name` text, - `email` text, - `emailVerified` integer, - `image` text -); ---> statement-breakpoint -CREATE TABLE `verificationToken` ( - `identifier` text NOT NULL, - `token` text NOT NULL, - `expires` integer NOT NULL, - PRIMARY KEY(`identifier`, `token`) -); diff --git a/apps/front-end/drizzle/meta/0000_snapshot.json b/apps/front-end/drizzle/meta/0000_snapshot.json deleted file mode 100644 index dd1b684..0000000 --- a/apps/front-end/drizzle/meta/0000_snapshot.json +++ /dev/null @@ -1,310 +0,0 @@ -{ - "version": "5", - "dialect": "sqlite", - "id": "1ac0bbd8-a63d-4ffd-b721-33343040dfb7", - "prevId": "00000000-0000-0000-0000-000000000000", - "tables": { - "account": { - "name": "account", - "columns": { - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "provider": { - "name": "provider", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "providerAccountId": { - "name": "providerAccountId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "access_token": { - "name": "access_token", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "expires_at": { - "name": "expires_at", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "token_type": { - "name": "token_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "id_token": { - "name": "id_token", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "session_state": { - "name": "session_state", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "account_provider_providerAccountId_pk": { - "columns": [ - "provider", - "providerAccountId" - ], - "name": "account_provider_providerAccountId_pk" - } - }, - "uniqueConstraints": {} - }, - "document": { - "name": "document", - "columns": { - "name": { - "name": "name", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "createdOn": { - "name": "createdOn", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "modifiedOn": { - "name": "modifiedOn", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "data": { - "name": "data", - "type": "blob", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "id": { - "name": "id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "notebook_document": { - "name": "notebook_document", - "columns": { - "notebookId": { - "name": "notebookId", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "documentName": { - "name": "documentName", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "notebook": { - "name": "notebook", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "authorId": { - "name": "authorId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "session": { - "name": "session", - "columns": { - "sessionToken": { - "name": "sessionToken", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "expires": { - "name": "expires", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "emailVerified": { - "name": "emailVerified", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "verificationToken": { - "name": "verificationToken", - "columns": { - "identifier": { - "name": "identifier", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "expires": { - "name": "expires", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "verificationToken_identifier_token_pk": { - "columns": [ - "identifier", - "token" - ], - "name": "verificationToken_identifier_token_pk" - } - }, - "uniqueConstraints": {} - } - }, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - } -} \ No newline at end of file diff --git a/apps/front-end/drizzle/meta/_journal.json b/apps/front-end/drizzle/meta/_journal.json deleted file mode 100644 index b4185f8..0000000 --- a/apps/front-end/drizzle/meta/_journal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "5", - "dialect": "sqlite", - "entries": [ - { - "idx": 0, - "version": "5", - "when": 1710150238409, - "tag": "0000_common_umar", - "breakpoints": true - } - ] -} \ No newline at end of file diff --git a/apps/front-end/src/app/DialogCollab.tsx b/apps/front-end/src/app/DialogCollab.tsx index eb24003..f94dfb8 100644 --- a/apps/front-end/src/app/DialogCollab.tsx +++ b/apps/front-end/src/app/DialogCollab.tsx @@ -11,23 +11,31 @@ import { DialogTitle, DialogTrigger, } from "../components/Dialog"; -import { UserAddIcon } from "../components/Icons"; +import { LockIcon, UnlockIcon } from "../components/Icons"; import { IS_BROWSER } from "@/utils"; import { usePathname } from "next/navigation"; +import { useState } from "react"; +import { useIsCollaborationEnabled } from "@/lib/collaboration"; export default function DialogCollab() { const pathname = usePathname(); const fullUrl = `${getOrigin()}${pathname}`; + const [isCollaborationEnabled, setIsCollaborationEnabled] = useIsCollaborationEnabled(); + const [open, setOpen] = useState(false); const copyToClipBoard = () => { navigator.clipboard.writeText(fullUrl); }; + const toggleSharing = () => { + setIsCollaborationEnabled(!isCollaborationEnabled); + }; + return ( - + - @@ -35,12 +43,40 @@ export default function DialogCollab() { Share your notebook - Anyone with this link will have access to your notes. + {isCollaborationEnabled + ? "Anyone with this link will have access to your notes." + : "This notebook is private. Enable sharing to allow others to collaborate."} -
- - +
+ {isCollaborationEnabled && ( +
+ + +
+ )} +
+
+ {isCollaborationEnabled ? ( + <> + + Sharing enabled + + ) : ( + <> + + Sharing disabled + + )} +
+ +
diff --git a/apps/front-end/src/app/Header.tsx b/apps/front-end/src/app/Header.tsx index 353175b..ff8abbe 100644 --- a/apps/front-end/src/app/Header.tsx +++ b/apps/front-end/src/app/Header.tsx @@ -1,3 +1,5 @@ +"use client"; + import ActiveUsers from "./ActiveUsers"; import BreadcrumbsShell from "./BreadcrumbsShell"; import DialogCollab from "./DialogCollab"; diff --git a/apps/front-end/src/app/Providers.tsx b/apps/front-end/src/app/Providers.tsx index 86b6d27..4f1bdc4 100644 --- a/apps/front-end/src/app/Providers.tsx +++ b/apps/front-end/src/app/Providers.tsx @@ -1,6 +1,5 @@ "use client"; import { TooltipProvider } from "@/components/Tooltip"; -import { IdentityProvider } from "@/lib/identity-provider"; import { Provider as AtomProvider } from "jotai"; import { PropsWithChildren } from "react"; @@ -11,9 +10,7 @@ type ProvidersProps = PropsWithChildren<{ export default function Providers({ children }: ProvidersProps) { return ( - {children} - ); } diff --git a/apps/front-end/src/app/[notebookId]/layout.tsx b/apps/front-end/src/app/[notebookId]/layout.tsx index 5766c6d..081f618 100644 --- a/apps/front-end/src/app/[notebookId]/layout.tsx +++ b/apps/front-end/src/app/[notebookId]/layout.tsx @@ -1,7 +1,11 @@ +"use client"; + import { StartCollaboration } from "@/lib/collaboration/StartCollaboration"; -import { PropsWithChildren } from "react"; +import { PropsWithChildren, useEffect } from "react"; import Header from "../Header"; import SideNavigation from "../SideNavigation"; +import { useIsCollaborationEnabled } from "@/lib/collaboration"; +import { useLocalIdentity } from "@/lib/identity-provider"; type LayoutProps = PropsWithChildren<{ params: { @@ -9,7 +13,17 @@ type LayoutProps = PropsWithChildren<{ }; }>; -async function Layout({ children, params }: LayoutProps) { +function Layout({ children, params }: LayoutProps) { + const [isCollaborationEnabled, setIsCollaborationEnabled] = useIsCollaborationEnabled(); + const identity = useLocalIdentity(); + + useEffect(() => { + if (identity.id !== params.notebookId) { + // Enable collaboration by default when accessing a notebook that is not your own + setIsCollaborationEnabled(true); + } + }, [identity.id, params.notebookId, setIsCollaborationEnabled]); + return (
- + {isCollaborationEnabled && } {children}
diff --git a/apps/front-end/src/components/Icons.tsx b/apps/front-end/src/components/Icons.tsx index 7bdbaf3..c072b1b 100644 --- a/apps/front-end/src/components/Icons.tsx +++ b/apps/front-end/src/components/Icons.tsx @@ -7,6 +7,8 @@ import { CiSearch as SearchIcon } from "react-icons/ci"; import { IoClipboardOutline as CopyIcon, IoStop as StopIcon, + IoLockClosed as LockIcon, + IoLockOpen as UnlockIcon, } from "react-icons/io5"; import { RiBold as BoldIcon, @@ -48,6 +50,8 @@ export { FileIcon, HeadingIcon, ItalicIcon, + LockIcon, + UnlockIcon, ParagraphIcon, QuoteIcon, RenameIcon, diff --git a/apps/front-end/src/lib/collaboration/StartCollaboration.tsx b/apps/front-end/src/lib/collaboration/StartCollaboration.tsx index 25e5e75..c418768 100644 --- a/apps/front-end/src/lib/collaboration/StartCollaboration.tsx +++ b/apps/front-end/src/lib/collaboration/StartCollaboration.tsx @@ -17,7 +17,7 @@ export function StartCollaboration({ notebookId }: StartCollaborationProps) { const identity = useLocalIdentity(); const setConnection = useSetAtom(rootConnectionAtom); const provider = useConnection(); - + useEffect(() => { const connectionProvider = createConnection({ name: notebookId, diff --git a/apps/front-end/src/lib/collaboration/hooks.ts b/apps/front-end/src/lib/collaboration/hooks.ts index eb1ac78..314c0fd 100644 --- a/apps/front-end/src/lib/collaboration/hooks.ts +++ b/apps/front-end/src/lib/collaboration/hooks.ts @@ -1,6 +1,6 @@ import { useLocalIdentity } from "@/lib/identity-provider"; import { useState, useEffect } from "react"; -import { AwarenessState, useConnection } from "./store"; +import { AwarenessState, useConnection, useIsCollaborationEnabled } from "./store"; export function useAwareness() { const provider = useConnection(); @@ -29,12 +29,13 @@ export function useSelf() { export function useOthers() { const me = useSelf(); const sharedState = useAwareness(); - return sharedState.filter((state) => state.user.id !== me.id); + return sharedState.filter((state) => state.user && state.user.id !== me.id); } export function useIsSynced() { const provider = useConnection(); - const [isSynced, setIsSynced] = useState(provider.isSynced); + const [isCollaborationEnabled] = useIsCollaborationEnabled(); + const [isSynced, setIsSynced] = useState(provider.isSynced || !isCollaborationEnabled); useEffect(() => { const onSynced = () => setIsSynced(true); diff --git a/apps/front-end/src/lib/collaboration/store.ts b/apps/front-end/src/lib/collaboration/store.ts index d3778d6..ee10063 100644 --- a/apps/front-end/src/lib/collaboration/store.ts +++ b/apps/front-end/src/lib/collaboration/store.ts @@ -4,7 +4,7 @@ import { HocuspocusProvider, HocuspocusProviderConfiguration, } from "@hocuspocus/provider"; -import { atom, useAtomValue } from "jotai"; +import { atom, useAtom, useAtomValue } from "jotai"; import { IndexeddbPersistence } from "y-indexeddb"; import { Doc } from "yjs"; @@ -52,10 +52,16 @@ function createDefaultConnection() { export const rootConnectionAtom = atom(createDefaultConnection()); +export const isCollaborationEnabledAtom = atom(false); + export function useConnection() { return useAtomValue(rootConnectionAtom); } +export function useIsCollaborationEnabled() { + return useAtom(isCollaborationEnabledAtom); +} + export type ConnectionConfiguration = Omit< HocuspocusProviderConfiguration, "url" diff --git a/apps/front-end/src/lib/identity-provider.tsx b/apps/front-end/src/lib/identity-provider.tsx index 547675a..6c5fb12 100644 --- a/apps/front-end/src/lib/identity-provider.tsx +++ b/apps/front-end/src/lib/identity-provider.tsx @@ -1,24 +1,8 @@ "use client"; -import { createContext, PropsWithChildren, useContext, useMemo } from "react"; -import { getOrCreateLocalIdentity, LocalIdentity } from "./local-identity"; - -const IdentityContext = createContext(null); - -export function IdentityProvider({ children }: PropsWithChildren) { - const identity = useMemo(() => getOrCreateLocalIdentity(), []); - - return ( - - {children} - - ); -} +import { useAtomValue } from "jotai"; +import { identityAtom, LocalIdentity } from "./local-identity"; export function useLocalIdentity(): LocalIdentity { - const identity = useContext(IdentityContext); - if (!identity) { - throw new Error("useLocalIdentity must be used within IdentityProvider"); - } - return identity; + return useAtomValue(identityAtom); } diff --git a/apps/front-end/src/lib/local-identity.ts b/apps/front-end/src/lib/local-identity.ts index a7af926..f3b3697 100644 --- a/apps/front-end/src/lib/local-identity.ts +++ b/apps/front-end/src/lib/local-identity.ts @@ -1,6 +1,4 @@ -// Local identity stored in localStorage with adjective-animal names -// Persists until browser history is cleared - +import { atomWithStorage } from "jotai/utils"; import { nanoid } from "nanoid"; const IDENTITY_STORAGE_KEY = "jotter_user_identity"; @@ -68,42 +66,19 @@ export interface LocalIdentity { name: string; } +export const identityAtom = atomWithStorage(IDENTITY_STORAGE_KEY, createLocalIdentity()); + function generateRandomName(): string { const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)]; const animal = ANIMALS[Math.floor(Math.random() * ANIMALS.length)]; return `${adjective}-${animal}`; } -export function getOrCreateLocalIdentity(): LocalIdentity { - if (typeof window === "undefined") { - // Fallback for server-side rendering - return { - id: nanoid(), - name: generateRandomName(), - }; - } - - try { - const stored = localStorage.getItem(IDENTITY_STORAGE_KEY); - if (stored) { - return JSON.parse(stored); - } - } catch { - // localStorage may not be available in some contexts - } - - const identity: LocalIdentity = { +export function createLocalIdentity(): LocalIdentity { + return { id: nanoid(), name: generateRandomName(), }; - - try { - localStorage.setItem(IDENTITY_STORAGE_KEY, JSON.stringify(identity)); - } catch { - // localStorage may not be available - } - - return identity; } export function clearLocalIdentity(): void { diff --git a/apps/front-end/src/plugins/CollaborationPlugin.tsx b/apps/front-end/src/plugins/CollaborationPlugin.tsx index 6797b18..cf57cca 100644 --- a/apps/front-end/src/plugins/CollaborationPlugin.tsx +++ b/apps/front-end/src/plugins/CollaborationPlugin.tsx @@ -2,6 +2,7 @@ import NoSSR from "@/components/NoSSR"; import { ConnectionConfiguration, createConnection, + useIsCollaborationEnabled, useSelf, } from "@/lib/collaboration"; import { CollaborationPlugin as LexicalCollaborationPlugin } from "@lexical/react/LexicalCollaborationPlugin"; @@ -20,8 +21,9 @@ type CollaborationPluginProps = { function CollaborationPlugin({ id }: CollaborationPluginProps) { const user = useSelf(); + const [isCollaborationEnabled] = useIsCollaborationEnabled(); - if (!user) { + if (!isCollaborationEnabled) { return null; } diff --git a/package-lock.json b/package-lock.json index 0b16707..7720699 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@jotter/eslint-config": "*", "@jotter/typescript-config": "*", "prettier": "^3.1.0", - "turbo": "^1.10.16" + "turbo": "^2.7.2" }, "engines": { "node": ">=18" @@ -4870,16 +4870,17 @@ } }, "node_modules/eslint-config-turbo": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/eslint-config-turbo/-/eslint-config-turbo-1.13.4.tgz", - "integrity": "sha512-+we4eWdZlmlEn7LnhXHCIPX/wtujbHCS7XjQM/TN09BHNEl2fZ8id4rHfdfUKIYTSKyy8U/nNyJ0DNoZj5Q8bw==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/eslint-config-turbo/-/eslint-config-turbo-2.7.2.tgz", + "integrity": "sha512-Tj8P1kJFVNFZxH+BaQO9sowg11N5PkpD34aWZ87PImqkWo7Qk8yRGRpshCeqGwdO5YKX631ZyTQfcDvs4bqBMQ==", "dev": true, - "license": "MPL-2.0", + "license": "MIT", "dependencies": { - "eslint-plugin-turbo": "1.13.4" + "eslint-plugin-turbo": "2.7.2" }, "peerDependencies": { - "eslint": ">6.6.0" + "eslint": ">6.6.0", + "turbo": ">2.0.0" } }, "node_modules/eslint-import-resolver-alias": { @@ -5517,16 +5518,17 @@ } }, "node_modules/eslint-plugin-turbo": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-turbo/-/eslint-plugin-turbo-1.13.4.tgz", - "integrity": "sha512-82GfMzrewI/DJB92Bbch239GWbGx4j1zvjk1lqb06lxIlMPnVwUHVwPbAnLfyLG3JuhLv9whxGkO/q1CL18JTg==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-turbo/-/eslint-plugin-turbo-2.7.2.tgz", + "integrity": "sha512-rZs+l0vQcFo/37OiCWDcTIcksrVfvSBwS6/CI41wc3hA/hWxGOAbT1Diy9/+PBrh2VJts0SzBXb80SqGgVFFPQ==", "dev": true, - "license": "MPL-2.0", + "license": "MIT", "dependencies": { "dotenv": "16.0.3" }, "peerDependencies": { - "eslint": ">6.6.0" + "eslint": ">6.6.0", + "turbo": ">2.0.0" } }, "node_modules/eslint-plugin-turbo/node_modules/dotenv": { @@ -12720,102 +12722,103 @@ } }, "node_modules/turbo": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.13.4.tgz", - "integrity": "sha512-1q7+9UJABuBAHrcC4Sxp5lOqYS5mvxRrwa33wpIyM18hlOCpRD/fTJNxZ0vhbMcJmz15o9kkVm743mPn7p6jpQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.7.2.tgz", + "integrity": "sha512-5JIA5aYBAJSAhrhbyag1ZuMSgUZnHtI+Sq3H8D3an4fL8PeF+L1yYvbEJg47akP1PFfATMf5ehkqFnxfkmuwZQ==", "dev": true, - "license": "MPL-2.0", + "license": "MIT", + "peer": true, "bin": { "turbo": "bin/turbo" }, "optionalDependencies": { - "turbo-darwin-64": "1.13.4", - "turbo-darwin-arm64": "1.13.4", - "turbo-linux-64": "1.13.4", - "turbo-linux-arm64": "1.13.4", - "turbo-windows-64": "1.13.4", - "turbo-windows-arm64": "1.13.4" + "turbo-darwin-64": "2.7.2", + "turbo-darwin-arm64": "2.7.2", + "turbo-linux-64": "2.7.2", + "turbo-linux-arm64": "2.7.2", + "turbo-windows-64": "2.7.2", + "turbo-windows-arm64": "2.7.2" } }, "node_modules/turbo-darwin-64": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.13.4.tgz", - "integrity": "sha512-A0eKd73R7CGnRinTiS7txkMElg+R5rKFp9HV7baDiEL4xTG1FIg/56Vm7A5RVgg8UNgG2qNnrfatJtb+dRmNdw==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-2.7.2.tgz", + "integrity": "sha512-dxY3X6ezcT5vm3coK6VGixbrhplbQMwgNsCsvZamS/+/6JiebqW9DKt4NwpgYXhDY2HdH00I7FWs3wkVuan4rA==", "cpu": [ "x64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/turbo-darwin-arm64": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.13.4.tgz", - "integrity": "sha512-eG769Q0NF6/Vyjsr3mKCnkG/eW6dKMBZk6dxWOdrHfrg6QgfkBUk0WUUujzdtVPiUIvsh4l46vQrNVd9EOtbyA==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-2.7.2.tgz", + "integrity": "sha512-1bXmuwPLqNFt3mzrtYcVx1sdJ8UYb124Bf48nIgcpMCGZy3kDhgxNv1503kmuK/37OGOZbsWSQFU4I08feIuSg==", "cpu": [ "arm64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/turbo-linux-64": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.13.4.tgz", - "integrity": "sha512-Bq0JphDeNw3XEi+Xb/e4xoKhs1DHN7OoLVUbTIQz+gazYjigVZvtwCvgrZI7eW9Xo1eOXM2zw2u1DGLLUfmGkQ==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-2.7.2.tgz", + "integrity": "sha512-kP+TiiMaiPugbRlv57VGLfcjFNsFbo8H64wMBCPV2270Or2TpDCBULMzZrvEsvWFjT3pBFvToYbdp8/Kw0jAQg==", "cpu": [ "x64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/turbo-linux-arm64": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.13.4.tgz", - "integrity": "sha512-BJcXw1DDiHO/okYbaNdcWN6szjXyHWx9d460v6fCHY65G8CyqGU3y2uUTPK89o8lq/b2C8NK0yZD+Vp0f9VoIg==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-2.7.2.tgz", + "integrity": "sha512-VDJwQ0+8zjAfbyY6boNaWfP6RIez4ypKHxwkuB6SrWbOSk+vxTyW5/hEjytTwK8w/TsbKVcMDyvpora8tEsRFw==", "cpu": [ "arm64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/turbo-windows-64": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.13.4.tgz", - "integrity": "sha512-OFFhXHOFLN7A78vD/dlVuuSSVEB3s9ZBj18Tm1hk3aW1HTWTuAw0ReN6ZNlVObZUHvGy8d57OAGGxf2bT3etQw==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-2.7.2.tgz", + "integrity": "sha512-rPjqQXVnI6A6oxgzNEE8DNb6Vdj2Wwyhfv3oDc+YM3U9P7CAcBIlKv/868mKl4vsBtz4ouWpTQNXG8vljgJO+w==", "cpu": [ "x64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/turbo-windows-arm64": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.13.4.tgz", - "integrity": "sha512-u5A+VOKHswJJmJ8o8rcilBfU5U3Y1TTAfP9wX8bFh8teYF1ghP0EhtMRLjhtp6RPa+XCxHHVA2CiC3gbh5eg5g==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-2.7.2.tgz", + "integrity": "sha512-tcnHvBhO515OheIFWdxA+qUvZzNqqcHbLVFc1+n+TJ1rrp8prYicQtbtmsiKgMvr/54jb9jOabU62URAobnB7g==", "cpu": [ "arm64" ], "dev": true, - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "win32" @@ -13572,12 +13575,28 @@ "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", "@vercel/style-guide": "^5.1.0", - "eslint-config-prettier": "^9.0.0", - "eslint-config-turbo": "^1.10.12", + "eslint-config-prettier": "^10.1.8", + "eslint-config-turbo": "^2.7.2", "eslint-plugin-only-warn": "^1.1.0", "typescript": "^5.2.2" } }, + "packages/eslint-config/node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "packages/typescript-config": { "name": "@jotter/typescript-config", "version": "0.0.0", diff --git a/package.json b/package.json index 941db03..c98969e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "@jotter/eslint-config": "*", "@jotter/typescript-config": "*", "prettier": "^3.1.0", - "turbo": "^1.10.16" + "turbo": "^2.7.2" }, "engines": { "node": ">=18" diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index a1e8f6b..fcb8c11 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -8,12 +8,12 @@ "react-internal.js" ], "devDependencies": { + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", "@vercel/style-guide": "^5.1.0", - "eslint-config-turbo": "^1.10.12", - "eslint-config-prettier": "^9.0.0", + "eslint-config-prettier": "^10.1.8", + "eslint-config-turbo": "^2.7.2", "eslint-plugin-only-warn": "^1.1.0", - "@typescript-eslint/parser": "^6.11.0", - "@typescript-eslint/eslint-plugin": "^6.11.0", "typescript": "^5.2.2" } } diff --git a/turbo.json b/turbo.json index 30c96a8..abc4268 100644 --- a/turbo.json +++ b/turbo.json @@ -1,13 +1,23 @@ { "$schema": "https://turbo.build/schema.json", - "globalDependencies": ["**/.env.*local"], - "pipeline": { + "globalDependencies": [ + "**/.env.*local" + ], + "tasks": { "build": { - "dependsOn": ["^build"], - "outputs": ["dist/**", ".next/**", "!.next/cache/**"] + "dependsOn": [ + "^build" + ], + "outputs": [ + "dist/**", + ".next/**", + "!.next/cache/**" + ] }, "lint": { - "dependsOn": ["^lint"] + "dependsOn": [ + "^lint" + ] }, "dev": { "cache": false,