diff --git a/.vscode/settings.json b/.vscode/settings.json index fb314406..6d62e5bc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,7 @@ "source.fixAll.eslint": "explicit", "source.organizeImports": "never" }, + "typescript.preferences.importModuleSpecifier": "relative", "npm.packageManager": "pnpm", "editor.defaultFormatter": "esbenp.prettier-vscode", "[typescript]": { diff --git a/examples/erp/.prettierignore b/examples/erp/.prettierignore new file mode 100644 index 00000000..c16d4020 --- /dev/null +++ b/examples/erp/.prettierignore @@ -0,0 +1,43 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +drizzle diff --git a/examples/erp/package.json b/examples/erp/package.json index d47e0790..77daec38 100644 --- a/examples/erp/package.json +++ b/examples/erp/package.json @@ -10,7 +10,6 @@ "format": "prettier --write .", "format:check": "prettier --check .", "typecheck": "tsc --noEmit", - "test": "vitest run", "db:migrate": "drizzle-kit migrate", "db:generate": "drizzle-kit generate" }, @@ -24,8 +23,8 @@ "next-themes": "^0.4.6", "pg": "^8.14.1", "postcss": "^8.5.3", - "react": "18.3.1", - "react-dom": "18.3.1", + "react": "19.1.0", + "react-dom": "19.1.0", "tailwindcss": "^4.0.14", "zod": "3.24.4" }, @@ -33,8 +32,8 @@ "@internals/project-config": "workspace:^", "@types/node": "^22.13.10", "@types/pg": "^8.11.11", - "@types/react": "18.3.18", - "@types/react-dom": "18.3.5", + "@types/react": "19.1.4", + "@types/react-dom": "19.1.5", "@vitejs/plugin-react": "^4.3.4", "drizzle-kit": "^0.30.6", "type-fest": "^4.38.0", diff --git a/examples/erp/src/app/(admin)/_helper/server.tsx b/examples/erp/src/app/(admin)/_helper/server.tsx index c92026cb..e91852b6 100644 --- a/examples/erp/src/app/(admin)/_helper/server.tsx +++ b/examples/erp/src/app/(admin)/_helper/server.tsx @@ -1,6 +1,6 @@ 'use server' -import { handleServerFunction, ServerFunction } from '@kivotos/next' +import { handleServerFunction, type ServerFunction } from '@kivotos/next' import { serverConfig } from '~/drizzlify/config' diff --git a/examples/erp/src/components/providers.tsx b/examples/erp/src/components/providers.tsx index d12819a0..d8a1b152 100644 --- a/examples/erp/src/components/providers.tsx +++ b/examples/erp/src/components/providers.tsx @@ -1,6 +1,6 @@ 'use client' -import { PropsWithChildren } from 'react' +import type { PropsWithChildren } from 'react' import { ThemeProvider as NextThemesProvider } from 'next-themes' diff --git a/internals/project-config/eslint/base.mjs b/internals/project-config/eslint/base.mjs index ba5f1332..c6eb0fc9 100644 --- a/internals/project-config/eslint/base.mjs +++ b/internals/project-config/eslint/base.mjs @@ -53,6 +53,7 @@ const config = tseslint.config( ], '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-empty-object-type': 'off', + '@typescript-eslint/consistent-type-imports': 'error', }, }, { diff --git a/internals/project-config/tsconfig/base.json b/internals/project-config/tsconfig/base.json index 3cb2d80a..e44b10bb 100644 --- a/internals/project-config/tsconfig/base.json +++ b/internals/project-config/tsconfig/base.json @@ -16,7 +16,8 @@ "preserveWatchOutput": true, "skipLibCheck": true, "strict": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "verbatimModuleSyntax": true }, "exclude": ["node_modules"] } diff --git a/packages/core/src/auth/context.ts b/packages/core/src/auth/context.ts index 384b84e3..e7a61a7e 100644 --- a/packages/core/src/auth/context.ts +++ b/packages/core/src/auth/context.ts @@ -1,11 +1,12 @@ -import { and, AnyTable, asc, Column, desc, eq } from 'drizzle-orm' -import { UndefinedToOptional } from 'type-fest/source/internal' +import type { AnyTable, Column } from 'drizzle-orm' +import { and, asc, desc, eq } from 'drizzle-orm' +import type { UndefinedToOptional } from 'type-fest/source/internal' -import { AnyAccountTable, AnySessionTable, AnyUserTable, AuthConfig } from '.' +import type { AnyAccountTable, AnySessionTable, AnyUserTable, AuthConfig } from '.' import { AccountProvider } from './constant' import { getSessionCookie } from './utils' -import { MinimalContext } from '../config' +import type { MinimalContext } from '../config' type InferTableType> = UndefinedToOptional<{ [K in keyof T['_']['columns']]: T['_']['columns'][K]['_']['notNull'] extends true diff --git a/packages/core/src/auth/handlers/forgot-password.ts b/packages/core/src/auth/handlers/forgot-password.ts index 675b3787..5234028d 100644 --- a/packages/core/src/auth/handlers/forgot-password.ts +++ b/packages/core/src/auth/handlers/forgot-password.ts @@ -1,7 +1,7 @@ import z from 'zod' -import { ApiRouteHandler, ApiRouteSchema, createEndpoint } from '../../endpoint' -import { AuthContext } from '../context' +import { type ApiRouteHandler, type ApiRouteSchema, createEndpoint } from '../../endpoint' +import { type AuthContext } from '../context' interface InternalRouteOptions { prefix?: string diff --git a/packages/core/src/auth/handlers/index.ts b/packages/core/src/auth/handlers/index.ts index 90949c79..6d206e3a 100644 --- a/packages/core/src/auth/handlers/index.ts +++ b/packages/core/src/auth/handlers/index.ts @@ -5,7 +5,7 @@ import { signInEmail } from './sign-in-email' import { signOut } from './sign-out' import { signUp } from './sign-up' -import { AuthConfig } from '..' +import type { AuthConfig } from '..' export function createAuthHandlers(config: TAuthConfig) { const handlers = { diff --git a/packages/core/src/auth/handlers/me.ts b/packages/core/src/auth/handlers/me.ts index fe73bce2..b6e64009 100644 --- a/packages/core/src/auth/handlers/me.ts +++ b/packages/core/src/auth/handlers/me.ts @@ -1,7 +1,7 @@ import z from 'zod' -import { ApiRouteHandler, ApiRouteSchema, createEndpoint } from '../../endpoint' -import { AuthContext } from '../context' +import { type ApiRouteHandler, type ApiRouteSchema, createEndpoint } from '../../endpoint' +import { type AuthContext } from '../context' interface InternalRouteOptions { prefix?: string diff --git a/packages/core/src/auth/handlers/reset-password.ts b/packages/core/src/auth/handlers/reset-password.ts index 2ba1de4e..f503713f 100644 --- a/packages/core/src/auth/handlers/reset-password.ts +++ b/packages/core/src/auth/handlers/reset-password.ts @@ -1,7 +1,7 @@ import z from 'zod' -import { ApiRouteHandler, ApiRouteSchema, createEndpoint } from '../../endpoint' -import { AuthContext } from '../context' +import { type ApiRouteHandler, type ApiRouteSchema, createEndpoint } from '../../endpoint' +import { type AuthContext } from '../context' interface InternalRouteOptions { prefix?: string diff --git a/packages/core/src/auth/handlers/sign-in-email.ts b/packages/core/src/auth/handlers/sign-in-email.ts index 3d11726a..b276bd6e 100644 --- a/packages/core/src/auth/handlers/sign-in-email.ts +++ b/packages/core/src/auth/handlers/sign-in-email.ts @@ -1,8 +1,8 @@ import z from 'zod' -import { ApiRouteHandler, ApiRouteSchema, createEndpoint } from '../../endpoint' +import { type ApiRouteHandler, type ApiRouteSchema, createEndpoint } from '../../endpoint' import { AccountProvider } from '../constant' -import { AuthContext } from '../context' +import { type AuthContext } from '../context' import { setSessionCookie } from '../utils' interface InternalRouteOptions { diff --git a/packages/core/src/auth/handlers/sign-out.ts b/packages/core/src/auth/handlers/sign-out.ts index dcbec6ea..1d3895b6 100644 --- a/packages/core/src/auth/handlers/sign-out.ts +++ b/packages/core/src/auth/handlers/sign-out.ts @@ -1,7 +1,7 @@ import z from 'zod' -import { ApiRouteHandler, ApiRouteSchema, createEndpoint } from '../../endpoint' -import { AuthContext } from '../context' +import { type ApiRouteHandler, type ApiRouteSchema, createEndpoint } from '../../endpoint' +import { type AuthContext } from '../context' import { deleteSessionCookie, getSessionCookie } from '../utils' interface InternalRouteOptions { diff --git a/packages/core/src/auth/handlers/sign-up.ts b/packages/core/src/auth/handlers/sign-up.ts index 6bba3cd9..db57afd5 100644 --- a/packages/core/src/auth/handlers/sign-up.ts +++ b/packages/core/src/auth/handlers/sign-up.ts @@ -1,8 +1,8 @@ import z from 'zod' -import { ApiRouteHandler, ApiRouteSchema, createEndpoint } from '../../endpoint' +import { type ApiRouteHandler, type ApiRouteSchema, createEndpoint } from '../../endpoint' import { AccountProvider } from '../constant' -import { AuthContext } from '../context' +import { type AuthContext } from '../context' interface InternalRouteOptions {} diff --git a/packages/core/src/auth/index.ts b/packages/core/src/auth/index.ts index ac81277f..f3b31545 100644 --- a/packages/core/src/auth/index.ts +++ b/packages/core/src/auth/index.ts @@ -1,12 +1,12 @@ -import { AnyColumn, AnyTable } from 'drizzle-orm' +import type { AnyColumn, AnyTable } from 'drizzle-orm' import * as R from 'remeda' -import { Simplify } from 'type-fest' +import type { Simplify } from 'type-fest' -import { AuthContext, createAuthContext } from './context' +import { type AuthContext, createAuthContext } from './context' import { createAuthHandlers } from './handlers' -import { MinimalContext } from '../config' -import { ApiRouteHandler } from '../endpoint' +import type { MinimalContext } from '../config' +import type { ApiRouteHandler } from '../endpoint' export type AnyTypedColumn = AnyColumn & { _: { data: T; dialect: 'pg' } } export type WithNotNull = T & { _: { notNull: true } } @@ -129,7 +129,7 @@ export type Auth< > } -export function createAuth( +export function createAuth = MinimalContext>( config: AuthConfig, context: TContext ): Auth { diff --git a/packages/core/src/builder.handler.spec.ts b/packages/core/src/builder.handler.spec.ts index e5ec2dbe..71df1f77 100644 --- a/packages/core/src/builder.handler.spec.ts +++ b/packages/core/src/builder.handler.spec.ts @@ -1,5 +1,5 @@ import { eq, or } from 'drizzle-orm' -import { NodePgDatabase } from 'drizzle-orm/node-postgres' +import type { NodePgDatabase } from 'drizzle-orm/node-postgres' import { beforeEach, describe, expect, it, vi } from 'vitest' import * as schema from './__mocks__/test-schema' @@ -166,7 +166,7 @@ describe('ApiHandler', () => { }, ]) expect(tx.insert).toHaveBeenCalledTimes(1) - expect(result).toEqual(postData.id) + expect(result).toEqual({ __pk: postData.id, id: postData.id }) }) it('should (R) read successfully', async () => { @@ -223,7 +223,7 @@ describe('ApiHandler', () => { eq(postCollection.fields.idField._.column, postData.id) ) expect(setMock).toHaveBeenCalledWith([{ nameTs: updatedPostData.name }]) - expect(result).toEqual(postData.id) + expect(result).toEqual({ __pk: postData.id, id: postData.id }) }) it('should (D) delete successfully', async () => { @@ -251,7 +251,7 @@ describe('ApiHandler', () => { }) }) - describe('with relation', () => { + describe.todo('with relation', () => { describe('with "create" mode', () => { describe('with "One" relation', () => { const postWithAuthorCreateCollection = builder.collection('postWithAuthorTs', { @@ -302,7 +302,9 @@ describe('ApiHandler', () => { data: { nameField: postData.name, authorField: { - nameField: authorData.name, + create: { + nameField: authorData.name, + }, }, }, context: { db: mockDb as any }, @@ -392,7 +394,9 @@ describe('ApiHandler', () => { data: { nameField: updatedPostData.name, authorField: { - nameField: updatedAuthorData.name, + create: { + nameField: updatedAuthorData.name, + }, }, }, }) @@ -406,7 +410,7 @@ describe('ApiHandler', () => { expect(whereUpdateMock).toHaveBeenCalledWith( eq(postWithAuthorCreateCollection.fields.idField._.column, postData.id) ) - expect(result).toEqual(postData.id) + expect(result).toEqual({ __pk: postData.id, id: postData.id }) }) it('should (D) delete successfully', async () => { @@ -484,15 +488,17 @@ describe('ApiHandler', () => { context: { db: mockDb as any }, data: { nameField: postData.name, - postsField: [ - mockPostData[0], - mockPostData[1], - mockPostData[2], - mockPostData[3], - mockPostData[4], - ].map((post) => ({ - nameField: post.name, - })), + postsField: { + create: [ + mockPostData[0], + mockPostData[1], + mockPostData[2], + mockPostData[3], + mockPostData[4], + ].map((post) => ({ + nameField: post.name, + })), + }, }, }) @@ -501,7 +507,7 @@ describe('ApiHandler', () => { expect(valuesInsertMock).toHaveBeenCalledWith([ expect.objectContaining({ nameTs: postData.name }), ]) - expect(result).toEqual(authorData.id) + expect(result).toEqual({ __pk: authorData.id, id: authorData.id }) }) it('should (R) read successfully', async () => { @@ -671,7 +677,9 @@ describe('ApiHandler', () => { context: { db: mockDb as any }, data: { nameField: postData.name, - authorField: authorData.id, + authorField: { + connect: authorData.id, + }, }, }) @@ -846,7 +854,9 @@ describe('ApiHandler', () => { context: { db: mockDb as any }, data: { nameField: authorData.name, - postsField: [mockPostData[0].id, mockPostData[1].id, mockPostData[2].id], + postsField: { + connect: [mockPostData[0].id, mockPostData[1].id, mockPostData[2].id], + }, }, }) @@ -951,7 +961,9 @@ describe('ApiHandler', () => { id: updatedAuthorData.id, data: { nameField: updatedAuthorDataField.nameField, - postsField: [1, 2, 3], + postsField: { + connect: [1, 2, 3], + }, }, }) // ====== end user part (field) ====== diff --git a/packages/core/src/builder.handler.ts b/packages/core/src/builder.handler.ts index 8c1a64c2..d6a5e5c3 100644 --- a/packages/core/src/builder.handler.ts +++ b/packages/core/src/builder.handler.ts @@ -1,3 +1,4 @@ +import type { Relation, Table } from 'drizzle-orm' import { eq, getTableColumns, @@ -6,15 +7,13 @@ import { Many, One, or, - Relation, - Table, - TableRelationalConfig, + type TableRelationalConfig, } from 'drizzle-orm' -import { NodePgQueryResultHKT } from 'drizzle-orm/node-postgres' -import { PgTransaction } from 'drizzle-orm/pg-core' -import { RelationalQueryBuilder } from 'drizzle-orm/pg-core/query-builders/query' +import type { NodePgQueryResultHKT } from 'drizzle-orm/node-postgres' +import type { PgTransaction } from 'drizzle-orm/pg-core' +import type { RelationalQueryBuilder } from 'drizzle-orm/pg-core/query-builders/query' -import { +import type { ApiCreateHandler, ApiDeleteHandler, ApiFindManyHandler, @@ -23,8 +22,8 @@ import { CollectionAdminApi, InferFields, } from './collection' -import { MinimalContext } from './config' -import { Field, Fields } from './field' +import type { MinimalContext } from './config' +import type { Field, Fields } from './field' import { createDrizzleQuery, getColumnTsName, @@ -106,7 +105,8 @@ export function createDefaultApiHandlers< }).create(tx, args.data) }) - return id + // TODO: It's not correct, fix this + return { __pk: id, id: id } } const update: ApiUpdateHandler = async (args) => { @@ -121,7 +121,8 @@ export function createDefaultApiHandlers< }).update(args.id, tx, args.data) }) - return args.id + // TODO: It's not correct, fix this + return { __pk: args.id, id: args.id } } // why not just delete? why _delete? diff --git a/packages/core/src/builder.ts b/packages/core/src/builder.ts index c72fd11f..fa1427e0 100644 --- a/packages/core/src/builder.ts +++ b/packages/core/src/builder.ts @@ -1,29 +1,35 @@ import { createTableRelationsHelpers, extractTablesRelationalConfig, - ExtractTablesWithRelations, + type ExtractTablesWithRelations, is, Table, } from 'drizzle-orm' -import { Simplify } from 'type-fest' +import type { Simplify } from 'type-fest' import { createDefaultApiHandlers } from './builder.handler' -import { +import type { Collection, CollectionConfig, FindTableByTableTsName, GetAllTableTsNames, } from './collection' -import { MinimalContext } from './config' +import type { MinimalContext } from './config' import { - ApiRoute, - ApiRouteHandler, - ApiRouter, - ApiRouteSchema, - AppendPrefixPathToApiRoute, + type ApiRoute, + type ApiRouteHandler, + type ApiRouter, + type ApiRouteSchema, + type AppendPrefixPathToApiRoute, createEndpoint, } from './endpoint' -import { FieldBuilder, Fields, FieldsInitial, FieldsWithFieldName, OptionCallback } from './field' +import { + FieldBuilder, + type Fields, + type FieldsInitial, + type FieldsWithFieldName, + type OptionCallback, +} from './field' import { appendFieldNameToFields } from './utils' export class Builder< diff --git a/packages/core/src/collection.ts b/packages/core/src/collection.ts index 7d4d77f3..7aa307f3 100644 --- a/packages/core/src/collection.ts +++ b/packages/core/src/collection.ts @@ -1,22 +1,29 @@ -import { Many, Simplify, Table, TableRelationalConfig } from 'drizzle-orm' -import { ConditionalExcept } from 'type-fest' +import type { Many, Table, TableRelationalConfig } from 'drizzle-orm' +import type { ConditionalExcept, Simplify } from 'type-fest' import z from 'zod' -import { MinimalContext } from './config' -import { ApiRoute, ApiRouteHandler, ApiRouter, ApiRouteSchema, ClientApiRouter } from './endpoint' +import type { MinimalContext } from './config' +import type { + ApiRoute, + ApiRouteHandler, + ApiRouter, + ApiRouteSchema, + ClientApiRouter, +} from './endpoint' import { - Field, - FieldClient, - FieldColumn, - FieldMutateModeCollection, - FieldRelation, - FieldRelationCollection, - Fields, - FieldsInitial, + type Field, + type FieldClient, + type FieldColumn, + type FieldMutateModeCollection, + type FieldRelation, + type FieldRelationCollection, + type Fields, + type FieldsClient, + type FieldsInitial, fieldsToZodObject, - FieldsWithFieldName, + type FieldsWithFieldName, } from './field' -import { JoinArrays, ToZodObject } from './utils' +import type { JoinArrays, ToZodObject } from './utils' type SimplifyConditionalExcept = Simplify> @@ -255,7 +262,7 @@ export type InferField = * * type UserFields = InferFields // => { __pk: string; id: string; profile: string; age: number } */ -export type InferFields> = SimplifyConditionalExcept< +export type InferFields = SimplifyConditionalExcept< { [TKey in keyof TFields]: TFields[TKey] extends FieldClient ? Simplify> diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 0ea83d96..416fda1d 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -1,19 +1,19 @@ -import { Simplify } from 'drizzle-orm' -import { NodePgDatabase } from 'drizzle-orm/node-postgres' +import type { NodePgDatabase } from 'drizzle-orm/node-postgres' import * as R from 'remeda' +import type { Simplify } from 'type-fest' -import { AuthConfig, createAuth } from './auth' +import { type AuthConfig, createAuth } from './auth' import { - ClientCollection, - Collection, - ExtractAllCollectionCustomEndpoints, - ExtractAllCollectionDefaultEndpoints, + type ClientCollection, + type Collection, + type ExtractAllCollectionCustomEndpoints, + type ExtractAllCollectionDefaultEndpoints, getAllCollectionEndpoints, - ToClientCollection, - ToClientCollectionList, + type ToClientCollection, + type ToClientCollectionList, } from './collection' -import { ApiRouter, ClientApiRouter, ToClientApiRouter } from './endpoint' -import { Field, FieldClient } from './field' +import type { ApiRouter, ClientApiRouter, ToClientApiRouter } from './endpoint' +import type { Field, FieldClient } from './field' import { isRelationField } from './utils' export type MinimalContext< @@ -46,8 +46,8 @@ export interface ServerConfig< any, any >[], - TApiRouter extends ApiRouter = ReturnType>['handlers'] & - ApiRouter, + TApiRouter extends ApiRouter = ReturnType>['handlers'] & + ApiRouter, > extends BaseConfig { context: TContext collections: TCollections diff --git a/packages/core/src/endpoint.ts b/packages/core/src/endpoint.ts index 48fcc2eb..083a2da2 100644 --- a/packages/core/src/endpoint.ts +++ b/packages/core/src/endpoint.ts @@ -1,7 +1,7 @@ -import { IsNever, Simplify, SimplifyDeep, ValueOf } from 'type-fest' -import { z, ZodType } from 'zod' +import type { IsNever, Simplify, SimplifyDeep, ValueOf } from 'type-fest' +import type { z, ZodType } from 'zod' -import { MaybePromise } from './collection' +import type { MaybePromise } from './collection' export type ApiHttpStatus = 200 | 201 | 204 | 301 | 302 | 400 | 401 | 403 | 404 | 409 | 422 | 500 diff --git a/packages/core/src/field.ts b/packages/core/src/field.ts index aca83ea6..0f00b538 100644 --- a/packages/core/src/field.ts +++ b/packages/core/src/field.ts @@ -1,18 +1,18 @@ +import type { Column, Relation } from 'drizzle-orm' import { - Column, - FindTableByDBName, + type FindTableByDBName, getTableName, is, One, - Relation, - Simplify, - TableRelationalConfig, + type TableRelationalConfig, } from 'drizzle-orm' -import z, { ZodObject } from 'zod' +import type { Simplify } from 'type-fest' +import type { ZodObject } from 'zod' +import z from 'zod' import { appendFieldNameToFields, - GetPrimaryColumn, + type GetPrimaryColumn, getPrimaryColumn, getPrimaryColumnTsName, } from './utils' @@ -22,7 +22,7 @@ export type OptionCallback< TContext extends Record = {}, > = (args: TContext) => Promise> -export type FieldsWithFieldName>> = { +export type FieldsWithFieldName> = { [TKey in keyof TFields]: TFields[TKey] & { _: { fieldName: string } } } @@ -221,6 +221,11 @@ export type Fields< export type FieldClient = Omit +export type FieldsClientInitial = Record + +export type FieldsClient = + FieldsWithFieldName + export type FieldColumnOptionsFromTable< TColumn extends Column, TContext extends Record = Record, diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 85daa26e..7ad1f7bc 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -2,6 +2,7 @@ export { Builder } from './builder' export type { ApiReturnType, ClientApiArgs, + ClientCollection, Collection, CollectionAdmin, CollectionAdminApi, @@ -10,6 +11,8 @@ export type { CollectionConfig, InferApiRouterFromCollection, InferContextFromCollection, + InferField, + InferFields, InferFieldsFromCollection, InferFullSchemaFromCollection, InferSlugFromCollection, @@ -28,4 +31,4 @@ export type { ClientApiRouter, InferApiRouteResponses, } from './endpoint' -export { type Field, FieldBuilder } from './field' +export type { Field, FieldBase, FieldClient, Fields, FieldsClient } from './field' diff --git a/packages/core/src/integrations/react-query/index.tsx b/packages/core/src/integrations/react-query/index.tsx deleted file mode 100644 index bac76172..00000000 --- a/packages/core/src/integrations/react-query/index.tsx +++ /dev/null @@ -1,190 +0,0 @@ -// import { -// DefaultError, -// DefinedInitialDataOptions, -// QueryClient, -// QueryKey, -// queryOptions, -// useMutation, -// UseMutationOptions, -// UseMutationResult, -// useQuery, -// UseQueryOptions, -// UseQueryResult, -// } from '@tanstack/react-query' -// import { Simplify } from 'drizzle-orm' - -// import { createClientApiHandlers } from '~/core/client' -// import { -// ApiHandlerReturnType, -// ClientApiHandlerParameters, -// Collection, -// CollectionAdminApiHandlerConfig, -// } from '~/core/collection' - -// type ReactQueryClientOptions = { -// baseUrl: string -// collections: TCollections -// } - -// type ReactQueryClient = { -// [K in TCollections[number]['slug']]: ReactQueryClientApiHandler< -// Extract -// > -// } - -// function createReactQueryClientApiHandler( -// baseUrl: string, -// collection: TCollection -// ): ReactQueryClientApiHandler { -// const handlers = createClientApiHandlers(baseUrl, collection) - -// const readOne: ReactQueryClientApiHandler['readOne'] = { -// query: handlers.findOne, -// queryOptions: (args) => -// queryOptions({ -// queryFn: () => handlers.findOne(args), -// queryKey: ['drizzlify', collection.slug, 'readOne'], -// }) as any, -// useQuery: (args, options, queryClient) => -// useQuery( -// { -// ...options, -// queryFn: () => handlers.findOne(args), -// queryKey: ['drizzlify', collection.slug, 'readOne'] as any, -// }, -// queryClient -// ), -// } - -// const readMany: ReactQueryClientApiHandler['readMany'] = { -// query: handlers.findMany, -// queryOptions: (args) => -// queryOptions({ -// queryFn: () => handlers.findMany(args), -// queryKey: ['drizzlify', collection.slug, 'readMany'], -// }) as any, -// useQuery: (args, options, queryClient) => -// useQuery( -// { -// ...options, -// queryFn: () => handlers.findMany(args) as any, -// queryKey: ['drizzlify', collection.slug, 'readMany'] as any, -// }, -// queryClient -// ), -// } - -// const create: ReactQueryClientApiHandler['create'] = { -// mutation: handlers.create, -// useMutation: (args, options) => -// useMutation({ -// ...options, -// mutationFn: () => handlers.create(args) as any, -// mutationKey: ['drizzlify', collection.slug, 'create'] as any, -// }), -// } - -// const update: ReactQueryClientApiHandler['update'] = { -// mutation: handlers.update, -// useMutation: (args, options) => -// useMutation({ -// ...options, -// mutationFn: () => handlers.update(args) as any, -// mutationKey: ['drizzlify', collection.slug, 'update'] as any, -// }), -// } - -// const _delete: ReactQueryClientApiHandler['delete'] = { -// mutation: handlers.delete, -// useMutation: (args, options) => -// useMutation({ -// ...options, -// mutationFn: () => handlers.delete(args) as any, -// mutationKey: ['drizzlify', collection.slug, 'delete'] as any, -// }), -// } - -// const value: ReactQueryClientApiHandler = { -// readOne, -// readMany, -// create, -// update, -// delete: _delete, -// } - -// return value -// } - -// export function reactQueryClient( -// options: ReactQueryClientOptions -// ): ReactQueryClient { -// const { baseUrl, collections } = options - -// const client = Object.fromEntries( -// collections.map((collection) => { -// const slug = collection.slug -// return [slug, createReactQueryClientApiHandler(baseUrl, collection)] -// }) -// ) - -// return client as unknown as ReactQueryClient -// } - -// export type ClientApiHandler< -// TCollection extends Collection, -// TMethod extends keyof CollectionAdminApiHandlerConfig, -// > = ( -// args: Simplify> -// ) => ApiHandlerReturnType - -// type ReactQueryQueryForApi< -// TCollection extends Collection, -// TMethod extends Extract, -// > = { -// query: ClientApiHandler -// queryOptions: ( -// args: Simplify> -// ) => DefinedInitialDataOptions< -// ApiHandlerReturnType, -// DefaultError, -// Simplify>, -// QueryKey -// > -// useQuery: < -// TQueryFnData = ApiHandlerReturnType, -// TError = DefaultError, -// TData = Simplify>, -// TQueryKey extends QueryKey = QueryKey, -// >( -// args: Simplify>, -// options: Omit, 'queryKey' | 'queryFn'>, -// queryClient?: QueryClient -// ) => UseQueryResult -// } - -// type ReactQueryMutationForApi< -// TCollection extends Collection, -// TMethod extends Extract, -// > = { -// mutation: ClientApiHandler -// useMutation: < -// TData = ApiHandlerReturnType, -// TError = DefaultError, -// TVariables = Simplify>, -// TContext = unknown, -// >( -// args: Simplify>, -// options: Omit< -// UseMutationOptions, -// 'mutationKey' | 'mutationFn' -// > -// ) => UseMutationResult -// } - -// export type ReactQueryClientApiHandler = { -// readOne: ReactQueryQueryForApi -// readMany: ReactQueryQueryForApi -// create: ReactQueryMutationForApi -// update: ReactQueryMutationForApi -// delete: ReactQueryMutationForApi -// } diff --git a/packages/core/src/integrations/react-router/api.ts b/packages/core/src/integrations/react-router/api.ts deleted file mode 100644 index 3020ccfe..00000000 --- a/packages/core/src/integrations/react-router/api.ts +++ /dev/null @@ -1,142 +0,0 @@ -// import { ActionFunction, LoaderFunction } from 'react-router' - -// import { NodePgDatabase } from 'drizzle-orm/node-postgres' - -// import { Collection, InferFields } from '~/core/collection' -// import { ServerConfig } from '~/core/config' -// import { createServerApiHandler } from '~/core/server' - -// /* -// Path pattern: -// Read /:prefix/:slug/:id -// ReadMany /:prefix/:slug -// Create /:prefix/:slug/new -// Update /:prefix/:slug/:id/edit -// Delete /:prefix/:slug/:id/delete -// */ -// export function createReactRouterApiHandler< -// TFullSchema extends Record, -// TDatabase extends NodePgDatabase>, -// TContext extends Record, -// TCollections extends Collection[], -// >(config: ServerConfig) { -// const { db, context, collections } = config - -// const collectionApiHandlersMap = new Map( -// collections.map((collection) => { -// return [collection.slug, createServerApiHandler({ collection })] -// }) -// ) - -// const loader: LoaderFunction = async (args) => { -// const { params, request } = args -// const slug = params.slug - -// const url = new URL(request.url) -// const pathname = url.pathname - -// if (!slug) throw new Error('Collection slug is required') - -// const collectionHandler = collectionApiHandlersMap.get(slug) -// if (!collectionHandler) throw new Error(`Collection ${slug} not found`) - -// const collection = collectionHandler.collection - -// // Handle ReadMany route -// if (pathname.endsWith(`/${slug}`)) { -// const limit = parseInt(url.searchParams.get('limit') ?? '10') -// const offset = parseInt(url.searchParams.get('offset') ?? '0') -// const orderBy = url.searchParams.get('orderBy') ?? undefined -// const orderType = (url.searchParams.get('orderType') ?? 'desc') as 'asc' | 'desc' - -// return collectionHandler.findMany({ -// db, -// context, -// fields: collection.fields, -// slug, -// limit, -// offset, -// orderBy, -// orderType, -// }) -// } - -// const id = params.id -// if (!id) throw new Error('ID is required') - -// // Handle ReadOne route -// if (pathname.endsWith(`/${slug}/${id}`)) { -// return collectionHandler.findOne({ -// db, -// context, -// fields: collection.fields, -// slug, -// id, -// }) -// } - -// throw new Error('Invalid route') -// } - -// const action: ActionFunction = async (args) => { -// const { params, request } = args -// const slug = params.slug - -// const url = new URL(request.url) -// const pathname = url.pathname - -// if (!slug) throw new Error('Collection slug is required') - -// const collectionHandler = collectionApiHandlersMap.get(slug) -// if (!collectionHandler) throw new Error(`Collection ${slug} not found`) - -// const collection = collectionHandler.collection -// const method = request.method - -// // Handle Create route -// if (method === 'POST' && pathname.endsWith(`/${slug}`)) { -// const data = await request.json() -// return collectionHandler.create({ -// db, -// context, -// fields: collection.fields, -// slug, -// data: data as InferFields, -// }) -// } - -// const id = params.id -// if (!id) throw new Error('ID is required') - -// // Handle Update route -// if (method === 'PUT' && pathname.endsWith(`/${slug}/${id}`)) { -// const data = await request.json() -// return collectionHandler.update({ -// db, -// context, -// fields: collection.fields, -// slug, -// id, -// data: data as InferFields, -// }) -// } - -// // Handle Delete route -// if (method === 'DELETE' && pathname.endsWith(`/${slug}/${id}`)) { -// return collectionHandler.delete({ -// db, -// context, -// fields: collection.fields, -// slug, -// id, -// }) -// } - -// throw new Error('Invalid route') -// } - -// return { -// loader, -// action, -// } -// } diff --git a/packages/core/src/integrations/react-router/example.tsx b/packages/core/src/integrations/react-router/example.tsx deleted file mode 100644 index ec8dcfbc..00000000 --- a/packages/core/src/integrations/react-router/example.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { authorCollection } from '~/core/spec' - -import { useForm } from './hooks' - -export default function Example() { - const form = useForm({ collection: authorCollection }) - - return ( -
-
- - -
-
- ) -} diff --git a/packages/core/src/integrations/react-router/form.tsx b/packages/core/src/integrations/react-router/form.tsx deleted file mode 100644 index 3e697661..00000000 --- a/packages/core/src/integrations/react-router/form.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { ComponentType, createContext } from 'react' -import { Controller, FormProvider } from 'react-hook-form' -import { ControllerProps, FieldPath, FieldValues } from 'react-hook-form' - -export const Form: typeof FormProvider = FormProvider - -type FormFieldContextValue< - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath, -> = { - name: TName -} - -const FormFieldContext = createContext({} as FormFieldContextValue) - -export const FormField = < - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath, ->( - props: ControllerProps & { component: ComponentType<{ name: TName }> } -) => { - const Component = props.component - - return ( - - } /> - - ) -} diff --git a/packages/core/src/integrations/react-router/hooks.tsx b/packages/core/src/integrations/react-router/hooks.tsx deleted file mode 100644 index 4fb96adb..00000000 --- a/packages/core/src/integrations/react-router/hooks.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { ReactNode, useCallback, useMemo, useRef } from 'react' -import { - type ControllerProps, - type FieldErrors, - type FieldPath, - type FieldValues, - useForm as useReactHookForm, - type UseFormHandleSubmit as UseReactHookFormHandleSubmit, - type UseFormProps as UseReactHookFormProps, - type UseFormReturn as UseReactHookFormReturn, -} from 'react-hook-form' - -import { Collection, InferFields } from '~/core/collection' - -import { Form, FormField as _FormField } from './form' -import { createRequireContext } from './utils' - -type InferFieldFromCollection = - TCollection extends Collection ? InferFields : never - -export type FormSubmitHandler = (data: TSchema) => void - -export type FormSubmitErrorHandler = ( - errors: FieldErrors -) => void - -interface UseFormProps< - TCollection extends Collection, - TContext = any, - TFields extends Record = InferFieldFromCollection, -> extends UseReactHookFormProps { - collection: TCollection - onSubmit?: FormSubmitHandler - onError?: FormSubmitErrorHandler -} - -export type UseFormReturn< - TCollection extends Collection, - TContext = any, - TFields extends Record = InferFieldFromCollection, -> = Omit, 'handleSubmit'> & { - /** - * Encouraged to use `form.onSubmit` instead - * @deprecated - */ - handleSubmit: UseReactHookFormHandleSubmit - Provider: (props: { children: ReactNode }) => JSX.Element - Field: = FieldPath>( - props: Omit, 'control'> - ) => JSX.Element - onSubmit: (event?: React.BaseSyntheticEvent) => Promise | void -} - -function useEffectEvent any>(handler: T): T { - const handlerRef = useRef(handler) - handlerRef.current = handler - return useCallback(((...args) => handlerRef.current(...args)) as T, []) -} - -export function useForm< - TCollection extends Collection, - TContext = any, - TFields extends Record = InferFieldFromCollection, ->( - props: UseFormProps -): UseFormReturn { - const { collection, ...formProps } = props - - const form = useReactHookForm(formProps) - - const Provider = useEffectEvent((props: { children: ReactNode }) => { - return ( - -
{props.children as any}
-
- ) - }) - - const onSubmit = useMemo(() => { - return form.handleSubmit( - ((data: any, event: any) => props?.onSubmit?.(data)) as any, - (errors, event) => props?.onError?.(errors) - ) - }, [form, props?.onSubmit, props?.onError]) - - return { - ...form, - Provider, - Field: _FormField as any, - onSubmit, - } -} - -export const [CollectionContextProvider, useCollectionContext, CollectionContext] = - createRequireContext('CollectionContext') - -export function useReadOne(collection: TCollection) {} - -export function useReadMany(collection: TCollection) {} - -export function useCreate(collection: TCollection) {} - -export function useUpdate(collection: TCollection) {} diff --git a/packages/core/src/integrations/react-router/index.ts b/packages/core/src/integrations/react-router/index.ts deleted file mode 100644 index 336ce12b..00000000 --- a/packages/core/src/integrations/react-router/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {} diff --git a/packages/core/src/integrations/react-router/ui.tsx b/packages/core/src/integrations/react-router/ui.tsx deleted file mode 100644 index c02536cf..00000000 --- a/packages/core/src/integrations/react-router/ui.tsx +++ /dev/null @@ -1,7 +0,0 @@ -interface InputProps { - name: string -} - -export function Input(props: InputProps) { - return -} diff --git a/packages/core/src/integrations/react-router/utils.ts b/packages/core/src/integrations/react-router/utils.ts deleted file mode 100644 index e6f953e5..00000000 --- a/packages/core/src/integrations/react-router/utils.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createContext, useContext as useReactContext } from 'react' - -export function createRequireContext(name: string) { - const Context = createContext(null as TContextValue | null) - const useContext = () => { - const context = useReactContext(Context) - if (!context) { - throw new Error(`use${name}Context must be inside of ${name}ContextProvider`) - } - return context - } - return [ - Context.Provider as React.Provider, - useContext as () => TContextValue, - Context, - ] as const -} diff --git a/packages/core/src/integrations/rest/example.ts b/packages/core/src/integrations/rest/example.ts deleted file mode 100644 index e43121a6..00000000 --- a/packages/core/src/integrations/rest/example.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { authorCollection } from '~/core/spec' - -import { createRestClient } from './index' - -// Example usage of the REST client -async function example() { - // Create the REST client - const client = createRestClient({ - baseUrl: 'https://api.example.com', - collections: [authorCollection], - }) - - // Example: Read a single author - const author = await client.authors.findOne({ id: '123' }) - console.log('Author:', author) - - // Example: Read multiple authors with pagination and sorting - const authors = await client.authors.findMany({ - limit: 10, - offset: 0, - orderBy: 'name', - orderType: 'asc', - }) - - console.log('Authors:', authors) - - // Example: Create a new author - const newAuthor = await client.authors.create({ - data: { - id: 1, - name: 'John Doe', - email: 'john@example.com', - createdAt: new Date(), - updatedAt: new Date(), - postIds: [], - }, - }) - console.log('New author:', newAuthor) - - // Example: Update an author - const updatedAuthor = await client.authors.update({ - id: '123', - data: { - id: 1, - name: 'John Doe', - email: 'john@example.com', - createdAt: new Date(), - updatedAt: new Date(), - postIds: [], - }, - }) - console.log('Updated author:', updatedAuthor) - - // Example: Delete an author - const deletedAuthor = await client.authors.delete({ id: '123' }) - console.log('Deleted author:', deletedAuthor) -} - -// Run the example -example().catch(console.error) diff --git a/packages/core/src/integrations/rest/index.ts b/packages/core/src/integrations/rest/index.ts deleted file mode 100644 index 87c80853..00000000 --- a/packages/core/src/integrations/rest/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ClientApiHandlers } from '~/core/client' -import { createClientApiHandlers } from '~/core/client' -import { Collection } from '~/core/collection' - -type RestClientOptions = { - baseUrl: string - collections: TCollections -} - -type RestClient = { - [K in TCollections[number]['slug']]: ClientApiHandlers> -} - -export function createRestClient( - options: RestClientOptions -): RestClient { - const { baseUrl, collections } = options - const client = Object.fromEntries( - collections.map((collection) => { - const value = createClientApiHandlers(baseUrl, collection) - return [collection.slug, value] - }) - ) - return client as unknown as RestClient -} diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 2aca4707..942d2282 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,8 +1,9 @@ -import { Column, is, Table, TableRelationalConfig } from 'drizzle-orm' -import { IsNever, Simplify, ValueOf } from 'type-fest' -import z, { ZodObject } from 'zod' +import type { Column, TableRelationalConfig } from 'drizzle-orm' +import { is, Table } from 'drizzle-orm' +import type { IsNever, Simplify, ValueOf } from 'type-fest' +import type { ZodObject, ZodOptional, ZodType } from 'zod' -import { Field, FieldRelation, Fields, FieldsInitial, FieldsWithFieldName } from './field' +import type { Field, FieldRelation, Fields, FieldsInitial, FieldsWithFieldName } from './field' export function isRelationField(field: Field): field is FieldRelation { return field._.source === 'relations' @@ -119,6 +120,6 @@ export type JoinArrays = Simplify< export type ToZodObject> = ZodObject<{ [Key in keyof T]-?: T[Key] extends undefined - ? z.ZodOptional>> - : z.ZodType + ? ZodOptional>> + : ZodType }> diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 07fc1be4..724fb08b 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -5,9 +5,6 @@ "jsx": "react-jsx", "lib": ["dom"], "module": "ESNext", - "moduleResolution": "bundler", - "paths": { - "~/*": ["./src/*"] - } + "moduleResolution": "bundler" } } diff --git a/packages/next/package.json b/packages/next/package.json index 85d17f4b..d4f5e904 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -14,8 +14,7 @@ "lint": "eslint .", "format": "prettier --write .", "format:check": "prettier --check .", - "typecheck": "tsc --noEmit", - "test": "vitest run" + "typecheck": "tsc --noEmit" }, "dependencies": { "@intentui/icons": "^1.10.31", diff --git a/packages/next/src/components/auto-field.tsx b/packages/next/src/components/auto-field.tsx index 6fa0e181..9c128e67 100644 --- a/packages/next/src/components/auto-field.tsx +++ b/packages/next/src/components/auto-field.tsx @@ -1,5 +1,4 @@ -import { ServerConfig } from '~/core/config' -import { Field } from '~/core/field' +import type { Field, ServerConfig } from '@kivotos/core' import { Checkbox } from '../intentui/ui/checkbox' import { Select, SelectList, SelectOption, SelectTrigger } from '../intentui/ui/select' @@ -37,7 +36,7 @@ export async function AutoField( case 'switch': return case 'selectText': { - const options = await field.options(props.serverConfig) + const options = await field.options({ db: props.serverConfig.db }) return ( @@ -67,7 +66,7 @@ export async function AutoField( ) } case 'comboboxText': { - const options = await field.options(props.serverConfig) + const options = await field.options({ db: props.serverConfig.db }) return ( {options.map((option) => ( diff --git a/packages/next/src/components/delete-button.tsx b/packages/next/src/components/delete-button.tsx index 4a969cf8..9bd1189c 100644 --- a/packages/next/src/components/delete-button.tsx +++ b/packages/next/src/components/delete-button.tsx @@ -1,7 +1,5 @@ -import { ServerConfig } from '~/core/config' +import type { ServerConfig } from '@kivotos/core' -export function DeleteButton(props: { - serverConfig: TServerConfig -}) { +export function DeleteButton(props: { serverConfig: ServerConfig }) { return } diff --git a/packages/next/src/components/form.tsx b/packages/next/src/components/form.tsx index 06182b48..176c85d0 100644 --- a/packages/next/src/components/form.tsx +++ b/packages/next/src/components/form.tsx @@ -2,29 +2,25 @@ import type { ServerConfig } from '@kivotos/core' -import { useServerFunction } from '~/providers/root' +import { useServerFunction } from '../providers/root' -import { GetServerMethod } from '../server-function' - -export function Form< - TServerConfig extends ServerConfig, - TMethod extends GetServerMethod = GetServerMethod, ->(props: Omit & { id?: string; children: React.ReactNode }) { +// TODO: Fix this +export function Form(props: any) { const serverFunction = useServerFunction() return (
{ - const data = Object.fromEntries(formData) - await serverFunction({ - slug: props.slug, - method: props.method, - payload: { - ...(props.id ? { id: props.id } : {}), - data: data as any, - }, - } as any) - }} + // action={async (formData) => { + // const data = Object.fromEntries(formData) + // await serverFunction({ + // slug: props.slug, + // method: props.method, + // payload: { + // ...(props.id ? { id: props.id } : {}), + // data: data as any, + // }, + // } as any) + // }} > {props.children}
diff --git a/packages/next/src/intentui/ui/button.tsx b/packages/next/src/intentui/ui/button.tsx index 4e93ddcf..9bbe082a 100644 --- a/packages/next/src/intentui/ui/button.tsx +++ b/packages/next/src/intentui/ui/button.tsx @@ -9,7 +9,7 @@ import { type LinkProps as LinkPrimitiveProps, } from 'react-aria-components' -import { tv, VariantProps } from 'tailwind-variants' +import { tv, type VariantProps } from 'tailwind-variants' const buttonStyles = tv({ base: [ diff --git a/packages/next/src/intentui/ui/custom-table.tsx b/packages/next/src/intentui/ui/custom-table.tsx index dc560abe..048d64aa 100644 --- a/packages/next/src/intentui/ui/custom-table.tsx +++ b/packages/next/src/intentui/ui/custom-table.tsx @@ -1,7 +1,14 @@ -import { CSSProperties, ReactNode, RefObject, useEffect, useRef, useState } from 'react' +import { + type CSSProperties, + type ReactNode, + type RefObject, + useEffect, + useRef, + useState, +} from 'react' +import type { Column, Header, Table as TanstackTable } from '@tanstack/react-table' import { flexRender } from '@tanstack/react-table' -import { Column, Header, Table as TanstackTable } from '@tanstack/react-table' import { twMerge } from 'tailwind-merge' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './table' diff --git a/packages/next/src/layouts/root-collection.tsx b/packages/next/src/layouts/root-collection.tsx index 4c528ec1..372939c2 100644 --- a/packages/next/src/layouts/root-collection.tsx +++ b/packages/next/src/layouts/root-collection.tsx @@ -1,7 +1,5 @@ import { type Collection, type ServerConfig } from '@kivotos/core' -import type { ServerFunction } from '~/server-function' - import { RootLayout } from './root' import { @@ -16,6 +14,7 @@ import { SidebarSection, SidebarTrigger, } from '../intentui/ui/sidebar' +import type { ServerFunction } from '../server-function' import { formatSlug } from '../utils/format-slug' interface RootLayoutProps> { diff --git a/packages/next/src/layouts/root.tsx b/packages/next/src/layouts/root.tsx index 08e33f56..55c61c11 100644 --- a/packages/next/src/layouts/root.tsx +++ b/packages/next/src/layouts/root.tsx @@ -1,13 +1,15 @@ -import { getClientConfig, ServerConfig } from '@kivotos/core' +import { type ReactNode } from 'react' -import { UiProviders } from '~/intentui/providers' -import { RootProvider } from '~/providers/root' -import { ServerFunction } from '~/server-function' +import { getClientConfig, type ServerConfig } from '@kivotos/core' + +import { UiProviders } from '../intentui/providers' +import { RootProvider } from '../providers/root' +import type { ServerFunction } from '../server-function' interface RootLayoutProps> { serverConfig: TServerConfig serverFunction: ServerFunction - children: React.ReactNode + children: ReactNode } export function RootLayout>( diff --git a/packages/next/src/pages/root-auth.tsx b/packages/next/src/pages/root-auth.tsx index 7c03baa3..49022141 100644 --- a/packages/next/src/pages/root-auth.tsx +++ b/packages/next/src/pages/root-auth.tsx @@ -1,6 +1,6 @@ -import { ServerConfig } from '@kivotos/core' +import type { ServerConfig } from '@kivotos/core' -import { SignInView } from '~/views/auth/sign-in' +import { SignInView } from '../views/auth/sign-in' interface RootProps { serverConfig: ServerConfig @@ -30,17 +30,17 @@ export async function RootAuthPage(props: RootProps) { return } - if (segments[1] === 'sign-up' && segments.length === 2) { - return - } + // if (segments[1] === 'sign-up' && segments.length === 2) { + // return + // } - if (segments[1] === 'forgot-password' && segments.length === 2) { - return - } + // if (segments[1] === 'forgot-password' && segments.length === 2) { + // return + // } - if (segments[1] === 'reset-password' && segments.length === 2) { - return - } + // if (segments[1] === 'reset-password' && segments.length === 2) { + // return + // } throw new Error(`Invalid path: ${segments.join('/')}`) // TODO: 404 } diff --git a/packages/next/src/pages/root-collection.tsx b/packages/next/src/pages/root-collection.tsx index 85c6034d..1a34406d 100644 --- a/packages/next/src/pages/root-collection.tsx +++ b/packages/next/src/pages/root-collection.tsx @@ -1,4 +1,4 @@ -import { ServerConfig } from '@kivotos/core' +import type { ServerConfig } from '@kivotos/core' import { CreateView } from '../views/collections/create' import { ListView } from '../views/collections/list' diff --git a/packages/next/src/pages/root.tsx b/packages/next/src/pages/root.tsx index d4aada28..dae09254 100644 --- a/packages/next/src/pages/root.tsx +++ b/packages/next/src/pages/root.tsx @@ -1,6 +1,6 @@ import { headers as nextHeaders } from 'next/headers' -import { ServerConfig } from '@kivotos/core' +import type { ServerConfig } from '@kivotos/core' import { RootAuthPage } from './root-auth' import { RootCollectionPage } from './root-collection' diff --git a/packages/next/src/providers/root.tsx b/packages/next/src/providers/root.tsx index 82b4c682..dd217f57 100644 --- a/packages/next/src/providers/root.tsx +++ b/packages/next/src/providers/root.tsx @@ -1,10 +1,10 @@ 'use client' -import { createContext, ReactNode, useContext } from 'react' +import { createContext, type ReactNode, useContext } from 'react' import type { ClientConfig, Collection, ServerConfig } from '@kivotos/core' -import { ServerFunction } from '../server-function' +import type { ServerFunction } from '../server-function' type RootContextValue = { clientConfig: ClientConfig diff --git a/packages/next/src/resource.ts b/packages/next/src/resource.ts index 7c2bf641..ecdf42e6 100644 --- a/packages/next/src/resource.ts +++ b/packages/next/src/resource.ts @@ -1,7 +1,7 @@ import { type NextRequest } from 'next/server' import { createRouter } from 'radix3' -import { ApiRoute, ApiRouter, ServerConfig } from '@kivotos/core' +import type { ApiRoute, ApiRouter, ServerConfig } from '@kivotos/core' function extractHeaders(headers: Headers) { const headersRecord: Record = {} diff --git a/packages/next/src/server-function.ts b/packages/next/src/server-function.ts index 3663ceef..3931a87b 100644 --- a/packages/next/src/server-function.ts +++ b/packages/next/src/server-function.ts @@ -1,6 +1,6 @@ import type { Simplify, ValueOf } from 'type-fest' -import { +import type { ApiRoute, ApiRouteHandlerPayload, ApiRouter, diff --git a/packages/next/src/views/auth/sign-in.client.tsx b/packages/next/src/views/auth/sign-in.client.tsx index e8590a8e..24f9f489 100644 --- a/packages/next/src/views/auth/sign-in.client.tsx +++ b/packages/next/src/views/auth/sign-in.client.tsx @@ -1,36 +1,14 @@ 'use client' -import { redirect } from 'next/navigation' - -import { SubmitButton } from '~/components/submit-button' -import { useServerFunction } from '~/providers/root' +import { SubmitButton } from '../../components/submit-button' interface SignInViewProps {} export function SignInClientForm(props: SignInViewProps) { - const serverFunction = useServerFunction() - - async function action(formData: FormData) { - 'use server' - const email = formData.get('email') as string - const password = formData.get('password') as string - const confirmPassword = formData.get('confirmPassword') as string - - if (password !== confirmPassword) { - throw new Error('Passwords do not match') - } - - await serverFunction('auth.signInEmail', { - body: { email, password }, - }) - - redirect('/collections') - } - return (

Sign In

-
+