refactor: move convex into packages

This commit is contained in:
2025-09-16 23:17:01 +00:00
parent 223a594479
commit 68ca8cbccd
22 changed files with 43 additions and 14 deletions

46
packages/convex/_generated/api.d.ts vendored Normal file
View File

@@ -0,0 +1,46 @@
/* eslint-disable */
/**
* Generated `api` utility.
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* To regenerate, run `npx convex dev`.
* @module
*/
import type {
ApiFromModules,
FilterApi,
FunctionReference,
} from "convex/server";
import type * as files from "../files.js";
import type * as functions from "../functions.js";
import type * as model_directories from "../model/directories.js";
import type * as model_error from "../model/error.js";
import type * as model_user from "../model/user.js";
import type * as users from "../users.js";
/**
* A utility for referencing Convex functions in your app's API.
*
* Usage:
* ```js
* const myFunctionReference = api.myModule.myFunction;
* ```
*/
declare const fullApi: ApiFromModules<{
files: typeof files;
functions: typeof functions;
"model/directories": typeof model_directories;
"model/error": typeof model_error;
"model/user": typeof model_user;
users: typeof users;
}>;
export declare const api: FilterApi<
typeof fullApi,
FunctionReference<any, "public">
>;
export declare const internal: FilterApi<
typeof fullApi,
FunctionReference<any, "internal">
>;

View File

@@ -0,0 +1,22 @@
/* eslint-disable */
/**
* Generated `api` utility.
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* To regenerate, run `npx convex dev`.
* @module
*/
import { anyApi } from "convex/server";
/**
* A utility for referencing Convex functions in your app's API.
*
* Usage:
* ```js
* const myFunctionReference = api.myModule.myFunction;
* ```
*/
export const api = anyApi;
export const internal = anyApi;

View File

@@ -0,0 +1,60 @@
/* eslint-disable */
/**
* Generated data model types.
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* To regenerate, run `npx convex dev`.
* @module
*/
import type {
DataModelFromSchemaDefinition,
DocumentByName,
TableNamesInDataModel,
SystemTableNames,
} from "convex/server";
import type { GenericId } from "convex/values";
import schema from "../schema.js";
/**
* The names of all of your Convex tables.
*/
export type TableNames = TableNamesInDataModel<DataModel>;
/**
* The type of a document stored in Convex.
*
* @typeParam TableName - A string literal type of the table name (like "users").
*/
export type Doc<TableName extends TableNames> = DocumentByName<
DataModel,
TableName
>;
/**
* An identifier for a document in Convex.
*
* Convex documents are uniquely identified by their `Id`, which is accessible
* on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
*
* Documents can be loaded using `db.get(id)` in query and mutation functions.
*
* IDs are just strings at runtime, but this type can be used to distinguish them from other
* strings when type checking.
*
* @typeParam TableName - A string literal type of the table name (like "users").
*/
export type Id<TableName extends TableNames | SystemTableNames> =
GenericId<TableName>;
/**
* A type describing your Convex data model.
*
* This type includes information about what tables you have, the type of
* documents stored in those tables, and the indexes defined on them.
*
* This type is used to parameterize methods like `queryGeneric` and
* `mutationGeneric` to make them type-safe.
*/
export type DataModel = DataModelFromSchemaDefinition<typeof schema>;

142
packages/convex/_generated/server.d.ts vendored Normal file
View File

@@ -0,0 +1,142 @@
/* eslint-disable */
/**
* Generated utilities for implementing server-side Convex query and mutation functions.
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* To regenerate, run `npx convex dev`.
* @module
*/
import {
ActionBuilder,
HttpActionBuilder,
MutationBuilder,
QueryBuilder,
GenericActionCtx,
GenericMutationCtx,
GenericQueryCtx,
GenericDatabaseReader,
GenericDatabaseWriter,
} from "convex/server";
import type { DataModel } from "./dataModel.js";
/**
* Define a query in this Convex app's public API.
*
* This function will be allowed to read your Convex database and will be accessible from the client.
*
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
*/
export declare const query: QueryBuilder<DataModel, "public">;
/**
* Define a query that is only accessible from other Convex functions (but not from the client).
*
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
*
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
*/
export declare const internalQuery: QueryBuilder<DataModel, "internal">;
/**
* Define a mutation in this Convex app's public API.
*
* This function will be allowed to modify your Convex database and will be accessible from the client.
*
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
*/
export declare const mutation: MutationBuilder<DataModel, "public">;
/**
* Define a mutation that is only accessible from other Convex functions (but not from the client).
*
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
*
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
*/
export declare const internalMutation: MutationBuilder<DataModel, "internal">;
/**
* Define an action in this Convex app's public API.
*
* An action is a function which can execute any JavaScript code, including non-deterministic
* code and code with side-effects, like calling third-party services.
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
*
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
*/
export declare const action: ActionBuilder<DataModel, "public">;
/**
* Define an action that is only accessible from other Convex functions (but not from the client).
*
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
*/
export declare const internalAction: ActionBuilder<DataModel, "internal">;
/**
* Define an HTTP action.
*
* This function will be used to respond to HTTP requests received by a Convex
* deployment if the requests matches the path and method where this action
* is routed. Be sure to route your action in `convex/http.js`.
*
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
*/
export declare const httpAction: HttpActionBuilder;
/**
* A set of services for use within Convex query functions.
*
* The query context is passed as the first argument to any Convex query
* function run on the server.
*
* This differs from the {@link MutationCtx} because all of the services are
* read-only.
*/
export type QueryCtx = GenericQueryCtx<DataModel>;
/**
* A set of services for use within Convex mutation functions.
*
* The mutation context is passed as the first argument to any Convex mutation
* function run on the server.
*/
export type MutationCtx = GenericMutationCtx<DataModel>;
/**
* A set of services for use within Convex action functions.
*
* The action context is passed as the first argument to any Convex action
* function run on the server.
*/
export type ActionCtx = GenericActionCtx<DataModel>;
/**
* An interface to read from the database within Convex query functions.
*
* The two entry points are {@link DatabaseReader.get}, which fetches a single
* document by its {@link Id}, or {@link DatabaseReader.query}, which starts
* building a query.
*/
export type DatabaseReader = GenericDatabaseReader<DataModel>;
/**
* An interface to read from and write to the database within Convex mutation
* functions.
*
* Convex guarantees that all writes within a single mutation are
* executed atomically, so you never have to worry about partial writes leaving
* your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)
* for the guarantees Convex provides your functions.
*/
export type DatabaseWriter = GenericDatabaseWriter<DataModel>;

View File

@@ -0,0 +1,89 @@
/* eslint-disable */
/**
* Generated utilities for implementing server-side Convex query and mutation functions.
*
* THIS CODE IS AUTOMATICALLY GENERATED.
*
* To regenerate, run `npx convex dev`.
* @module
*/
import {
actionGeneric,
httpActionGeneric,
queryGeneric,
mutationGeneric,
internalActionGeneric,
internalMutationGeneric,
internalQueryGeneric,
} from "convex/server";
/**
* Define a query in this Convex app's public API.
*
* This function will be allowed to read your Convex database and will be accessible from the client.
*
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
*/
export const query = queryGeneric;
/**
* Define a query that is only accessible from other Convex functions (but not from the client).
*
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
*
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
*/
export const internalQuery = internalQueryGeneric;
/**
* Define a mutation in this Convex app's public API.
*
* This function will be allowed to modify your Convex database and will be accessible from the client.
*
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
*/
export const mutation = mutationGeneric;
/**
* Define a mutation that is only accessible from other Convex functions (but not from the client).
*
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
*
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
*/
export const internalMutation = internalMutationGeneric;
/**
* Define an action in this Convex app's public API.
*
* An action is a function which can execute any JavaScript code, including non-deterministic
* code and code with side-effects, like calling third-party services.
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
*
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
*/
export const action = actionGeneric;
/**
* Define an action that is only accessible from other Convex functions (but not from the client).
*
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
*/
export const internalAction = internalActionGeneric;
/**
* Define a Convex HTTP action.
*
* @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
* as its second.
* @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
*/
export const httpAction = httpActionGeneric;

View File

@@ -0,0 +1,22 @@
const clientId = process.env.WORKOS_CLIENT_ID
const authConfig = {
providers: [
{
type: "customJwt",
issuer: `https://api.workos.com/`,
algorithm: "RS256",
jwks: `https://api.workos.com/sso/jwks/${clientId}`,
applicationID: clientId,
},
{
type: "customJwt",
issuer: `https://api.workos.com/user_management/${clientId}`,
algorithm: "RS256",
jwks: `https://api.workos.com/sso/jwks/${clientId}`,
applicationID: clientId,
},
],
}
export default authConfig

106
packages/convex/files.ts Normal file
View File

@@ -0,0 +1,106 @@
import type { Id } from "@fileone/convex/_generated/dataModel"
import { v } from "convex/values"
import { authenticatedMutation, authenticatedQuery } from "./functions"
import type { DirectoryItem } from "./model/directories"
import * as Directories from "./model/directories"
export const generateUploadUrl = authenticatedMutation({
handler: async (ctx) => {
// ctx.user and ctx.identity are automatically available
return await ctx.storage.generateUploadUrl()
},
})
export const fetchFiles = authenticatedQuery({
args: {
directoryId: v.optional(v.id("directories")),
},
handler: async (ctx, { directoryId }) => {
return await ctx.db
.query("files")
.withIndex("byDirectoryId", (q) =>
q.eq("userId", ctx.user._id).eq("directoryId", directoryId),
)
.collect()
},
})
export const fetchDirectoryContent = authenticatedQuery({
args: {
directoryId: v.optional(v.id("directories")),
},
handler: async (ctx, { directoryId }): Promise<DirectoryItem[]> => {
return await Directories.fetchContent(ctx, directoryId)
},
})
export const createDirectory = authenticatedMutation({
args: {
name: v.string(),
directoryId: v.optional(v.id("directories")),
},
handler: async (ctx, { name, directoryId }): Promise<Id<"directories">> => {
return await Directories.create(ctx, {
name,
parentId: directoryId,
})
},
})
export const saveFile = authenticatedMutation({
args: {
name: v.string(),
size: v.number(),
directoryId: v.optional(v.id("directories")),
storageId: v.id("_storage"),
mimeType: v.optional(v.string()),
},
handler: async (ctx, { name, storageId, directoryId, size, mimeType }) => {
const now = new Date().toISOString()
await ctx.db.insert("files", {
name,
size,
storageId,
directoryId,
userId: ctx.user._id,
mimeType,
createdAt: now,
updatedAt: now,
})
},
})
export const moveToTrash = authenticatedMutation({
args: {
kind: v.union(v.literal("file"), v.literal("directory")),
itemId: v.union(v.id("files"), v.id("directories")),
},
handler: async (ctx, { itemId, kind }) => {
switch (kind) {
case "file": {
const file = await ctx.db.get(itemId as Id<"files">)
if (!file || file.userId !== ctx.user._id) {
throw new Error("File not found or access denied")
}
await ctx.db.patch(itemId, {
deletedAt: new Date().toISOString(),
})
break
}
case "directory": {
const directory = await ctx.db.get(itemId as Id<"directories">)
if (!directory || directory.userId !== ctx.user._id) {
throw new Error("Directory not found or access denied")
}
await Directories.moveToTrashRecursive(
ctx,
itemId as Id<"directories">,
)
break
}
}
return itemId
},
})

View File

@@ -0,0 +1,46 @@
import type { UserIdentity } from "convex/server"
import {
customCtx,
customMutation,
customQuery,
} from "convex-helpers/server/customFunctions"
import type { Doc } from "./_generated/dataModel"
import type { MutationCtx, QueryCtx } from "./_generated/server"
import { mutation, query } from "./_generated/server"
import { userIdentityOrThrow, userOrThrow } from "./model/user"
export type AuthenticatedQueryCtx = QueryCtx & {
user: Doc<"users">
identity: UserIdentity
}
export type AuthenticatedMutationCtx = MutationCtx & {
user: Doc<"users">
identity: UserIdentity
}
/**
* Custom query that automatically provides authenticated user context
* Throws an error if the user is not authenticated
*/
export const authenticatedQuery = customQuery(
query,
customCtx(async (ctx: QueryCtx) => {
const user = await userOrThrow(ctx)
const identity = await userIdentityOrThrow(ctx)
return { user, identity }
}),
)
/**
* Custom mutation that automatically provides authenticated user context
* Throws an error if the user is not authenticated
*/
export const authenticatedMutation = customMutation(
mutation,
customCtx(async (ctx: MutationCtx) => {
const user = await userOrThrow(ctx)
const identity = await userIdentityOrThrow(ctx)
return { user, identity }
}),
)

View File

@@ -0,0 +1,154 @@
import type { Doc, Id } from "@fileone/convex/_generated/dataModel"
import type {
AuthenticatedMutationCtx,
AuthenticatedQueryCtx,
} from "../functions"
import * as Err from "./error"
type Directory = {
kind: "directory"
doc: Doc<"directories">
}
type File = {
kind: "file"
doc: Doc<"files">
}
export type DirectoryItem = Directory | File
export type DirectoryItemKind = DirectoryItem["kind"]
export async function fetchContent(
ctx: AuthenticatedQueryCtx,
directoryId?: Id<"directories">,
): Promise<DirectoryItem[]> {
const [files, directories] = await Promise.all([
ctx.db
.query("files")
.withIndex("byDirectoryId", (q) =>
q
.eq("userId", ctx.user._id)
.eq("directoryId", directoryId)
.eq("deletedAt", undefined),
)
.collect(),
ctx.db
.query("directories")
.withIndex("byParentId", (q) =>
q
.eq("userId", ctx.user._id)
.eq("parentId", directoryId)
.eq("deletedAt", undefined),
)
.collect(),
])
const items: DirectoryItem[] = []
for (const directory of directories) {
items.push({ kind: "directory", doc: directory })
}
for (const file of files) {
items.push({ kind: "file", doc: file })
}
return items
}
export async function create(
ctx: AuthenticatedMutationCtx,
{ name, parentId }: { name: string; parentId?: Id<"directories"> },
): Promise<Id<"directories">> {
let parentDir: Doc<"directories"> | null = null
if (parentId) {
parentDir = await ctx.db.get(parentId)
if (!parentDir) {
throw Err.create(
Err.Code.DirectoryNotFound,
`Parent directory ${parentId} not found`,
)
}
}
const existing = await ctx.db
.query("directories")
.withIndex("uniqueDirectoryInDirectory", (q) =>
q
.eq("userId", ctx.user._id)
.eq("parentId", parentId)
.eq("name", name)
.eq("deletedAt", undefined),
)
.first()
if (existing) {
throw Err.create(
Err.Code.DirectoryExists,
`Directory with name ${name} already exists in ${parentId ? `directory ${parentId}` : "root"}`,
)
}
const now = new Date().toISOString()
return await ctx.db.insert("directories", {
name,
parentId,
userId: ctx.user._id,
createdAt: now,
updatedAt: now,
path: parentDir ? `${parentDir.path}/${name}` : "/",
})
}
export async function moveToTrashRecursive(
ctx: AuthenticatedMutationCtx,
directoryId: Id<"directories">,
): Promise<void> {
const now = new Date().toISOString()
const filesToDelete: Id<"files">[] = []
const directoriesToDelete: Id<"directories">[] = []
const directoryQueue: Id<"directories">[] = [directoryId]
while (directoryQueue.length > 0) {
const currentDirectoryId = directoryQueue.shift()!
directoriesToDelete.push(currentDirectoryId)
const files = await ctx.db
.query("files")
.withIndex("byDirectoryId", (q) =>
q
.eq("userId", ctx.user._id)
.eq("directoryId", currentDirectoryId)
.eq("deletedAt", undefined),
)
.collect()
for (const file of files) {
filesToDelete.push(file._id)
}
const subdirectories = await ctx.db
.query("directories")
.withIndex("byParentId", (q) =>
q
.eq("userId", ctx.user._id)
.eq("parentId", currentDirectoryId)
.eq("deletedAt", undefined),
)
.collect()
for (const subdirectory of subdirectories) {
directoryQueue.push(subdirectory._id)
}
}
const filePatches = filesToDelete.map((fileId) =>
ctx.db.patch(fileId, { deletedAt: now }),
)
const directoryPatches = directoriesToDelete.map((dirId) =>
ctx.db.patch(dirId, { deletedAt: now }),
)
await Promise.all([...filePatches, ...directoryPatches])
}

View File

@@ -0,0 +1,22 @@
import { ConvexError } from "convex/values"
export enum Code {
DirectoryExists = "DirectoryExists",
DirectoryNotFound = "DirectoryNotFound",
FileExists = "FileExists",
Internal = "Internal",
Unauthenticated = "Unauthenticated",
}
export type ApplicationError = ConvexError<{ code: Code; message: string }>
export function isApplicationError(error: unknown): error is ApplicationError {
return error instanceof ConvexError && "code" in error.data
}
export function create(code: Code, message?: string) {
return new ConvexError({
code,
message,
})
}

View File

@@ -0,0 +1,46 @@
import type { Id } from "../_generated/dataModel"
import type { MutationCtx, QueryCtx } from "../_generated/server"
import type { AuthenticatedMutationCtx } from "../functions"
import * as Err from "./error"
/**
* Get the current authenticated user identity
* Throws an error if the user is not authenticated */
export async function userIdentityOrThrow(ctx: QueryCtx | MutationCtx) {
const identity = await ctx.auth.getUserIdentity()
if (!identity) {
throw Err.create(Err.Code.Unauthenticated, "Not authenticated")
}
return identity
}
/**
* Get internal user document from JWT authentication
* Throws an error if the user is not authenticated
*/
export async function userOrThrow(ctx: QueryCtx | MutationCtx) {
const identity = await userIdentityOrThrow(ctx)
// Look for existing user by JWT subject
const user = await ctx.db
.query("users")
.withIndex("byJwtSubject", (q) => q.eq("jwtSubject", identity.subject))
.first()
if (!user) {
throw Err.create(
Err.Code.Unauthenticated,
"User not found - please sync user first",
)
}
return user
}
export async function register(ctx: AuthenticatedMutationCtx) {
await ctx.db.insert("users", {
jwtSubject: ctx.identity.subject,
})
}

View File

@@ -0,0 +1,9 @@
{
"name": "@fileone/convex",
"module": "index.ts",
"type": "module",
"peerDependencies": {
"typescript": "^5",
"convex": "^1.27.0"
}
}

48
packages/convex/schema.ts Normal file
View File

@@ -0,0 +1,48 @@
import { defineSchema, defineTable } from "convex/server"
import { v } from "convex/values"
const schema = defineSchema({
users: defineTable({
jwtSubject: v.string(),
}).index("byJwtSubject", ["jwtSubject"]),
files: defineTable({
storageId: v.id("_storage"),
userId: v.id("users"),
directoryId: v.optional(v.id("directories")),
name: v.string(),
size: v.number(),
mimeType: v.optional(v.string()),
createdAt: v.string(),
updatedAt: v.string(),
deletedAt: v.optional(v.string()),
})
.index("byDirectoryId", ["userId", "directoryId", "deletedAt"])
.index("byUserId", ["userId", "deletedAt"])
.index("byDeletedAt", ["deletedAt"])
.index("uniqueFileInDirectory", [
"userId",
"directoryId",
"name",
"deletedAt",
]),
directories: defineTable({
name: v.string(),
path: v.string(),
userId: v.id("users"),
parentId: v.optional(v.id("directories")),
createdAt: v.string(),
updatedAt: v.string(),
deletedAt: v.optional(v.string()),
})
.index("byUserId", ["userId", "deletedAt"])
.index("byParentId", ["userId", "parentId", "deletedAt"])
.index("uniqueDirectoryInDirectory", [
"userId",
"parentId",
"name",
"deletedAt",
])
.index("byPath", ["path", "deletedAt"]),
})
export default schema

32
packages/convex/users.ts Normal file
View File

@@ -0,0 +1,32 @@
import { mutation } from "./_generated/server"
import { authenticatedQuery } from "./functions"
import * as Err from "./model/error"
export const getCurrentUser = authenticatedQuery({
handler: async (ctx) => {
// ctx.user is the internal Convex user document
return ctx.user
},
})
export const syncUser = mutation({
handler: async (ctx) => {
const identity = await ctx.auth.getUserIdentity()
if (!identity) {
throw Err.create(Err.Code.Unauthenticated)
}
const existingUser = await ctx.db
.query("users")
.withIndex("byJwtSubject", (q) =>
q.eq("jwtSubject", identity.subject),
)
.first()
if (!existingUser) {
await ctx.db.insert("users", {
jwtSubject: identity.subject,
})
}
},
})

View File

@@ -10,6 +10,7 @@
},
"dependencies": {
"@convex-dev/workos": "^0.0.1",
"@fileone/convex": "workspace:*",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-context-menu": "^2.2.16",
"@radix-ui/react-dialog": "^1.1.15",
@@ -42,4 +43,4 @@
"@types/react": "^19",
"@types/react-dom": "^19"
}
}
}

View File

@@ -1,6 +1,5 @@
import { api } from "@convex/_generated/api"
import type { Id } from "@convex/_generated/dataModel"
import type { DirectoryItem } from "@convex/model/directories"
import { api } from "@fileone/convex/_generated/api"
import type { DirectoryItem } from "@fileone/convex/model/directories"
import { useMutation } from "@tanstack/react-query"
import {
type ColumnDef,

View File

@@ -1,4 +1,4 @@
import { api } from "@convex/_generated/api"
import { api } from "@fileone/convex/_generated/api"
import { useMutation } from "@tanstack/react-query"
import { useMutation as useConvexMutation } from "convex/react"
import { useSetAtom } from "jotai"

View File

@@ -1,9 +1,9 @@
import { atom } from "jotai"
import type { Id } from "@convex/_generated/dataModel"
import type { Id } from "@fileone/convex/_generated/dataModel"
import type {
DirectoryItem,
DirectoryItemKind,
} from "@convex/model/directories"
} from "@fileone/convex/model/directories"
import { atom } from "jotai"
export const contextMenuTargeItemAtom = atom<DirectoryItem | null>(null)
export const optimisticDeletedItemsAtom = atom(

View File

@@ -1,5 +1,8 @@
import {
Code as ErrorCode,
isApplicationError,
} from "@fileone/convex/model/error"
import { toast } from "sonner"
import { Code as ErrorCode, isApplicationError } from "@convex/model/error"
const ERROR_MESSAGE = {
[ErrorCode.DirectoryExists]: "Directory already exists",

View File

@@ -1,4 +1,4 @@
import { api } from "@convex/_generated/api"
import { api } from "@fileone/convex/_generated/api"
import { useMutation } from "@tanstack/react-query"
import { createFileRoute, useNavigate } from "@tanstack/react-router"
import { useConvexAuth, useMutation as useConvexMutation } from "convex/react"

View File

@@ -23,8 +23,7 @@
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@convex/*": ["../../convex/*"]
"@/*": ["./src/*"]
},
// Some stricter flags (disabled by default)