diff --git a/apps/server-doj/vitest.config.ts b/apps/server-doj/vitest.config.ts index 55f8f580..3d88ce35 100644 --- a/apps/server-doj/vitest.config.ts +++ b/apps/server-doj/vitest.config.ts @@ -1,5 +1,5 @@ import { defineConfig } from 'vitest/config'; -import { getDatabaseTestContainerGlobalSetupPath } from '@atj/database'; +import { getVitestDatabaseContainerGlobalSetupPath } from '@atj/database'; import sharedTestConfig from '../../vitest.shared'; @@ -7,6 +7,6 @@ export default defineConfig({ ...sharedTestConfig, test: { ...sharedTestConfig.test, - globalSetup: [getDatabaseTestContainerGlobalSetupPath()], + globalSetup: [getVitestDatabaseContainerGlobalSetupPath()], }, }); diff --git a/apps/spotlight/src/context.ts b/apps/spotlight/src/context.ts index 36e51e2f..970fe13a 100644 --- a/apps/spotlight/src/context.ts +++ b/apps/spotlight/src/context.ts @@ -38,9 +38,9 @@ const createAppContext = (env: any): AppContext => { const createAppFormService = () => { if (globalThis.window) { - const db = new BrowserFormRepository(window.localStorage); + const repository = new BrowserFormRepository(window.localStorage); return createFormService({ - db, + repository, config: defaultFormConfig, }); } else { diff --git a/packages/auth/src/context/base.ts b/packages/auth/src/context/base.ts index dd3e26d6..e4181e4f 100644 --- a/packages/auth/src/context/base.ts +++ b/packages/auth/src/context/base.ts @@ -1,12 +1,14 @@ import { Cookie, Lucia } from 'lucia'; -import { AuthRepository } from '@atj/database'; +import { type AuthServiceContext, type UserSession } from '../index.js'; +import { + createPostgresLuciaAdapter, + createSqliteLuciaAdapter, +} from '../lucia.js'; +import { LoginGov } from '../provider.js'; +import { type AuthRepository } from '../repository/index.js'; -import { type AuthContext, type UserSession } from '..'; -import { createPostgresLuciaAdapter, createSqliteLuciaAdapter } from '../lucia'; -import { LoginGov } from '../provider'; - -export class BaseAuthContext implements AuthContext { +export class BaseAuthContext implements AuthServiceContext { private lucia?: Lucia; constructor( diff --git a/packages/auth/src/context/test.ts b/packages/auth/src/context/test.ts index 23404a44..0c1e08bd 100644 --- a/packages/auth/src/context/test.ts +++ b/packages/auth/src/context/test.ts @@ -1,15 +1,15 @@ import { Cookie, Lucia } from 'lucia'; import { vi } from 'vitest'; +import { createInMemoryDatabaseContext } from '@atj/database'; + +import { AuthServiceContext, UserSession } from '../index.js'; +import { createSqliteLuciaAdapter } from '../lucia.js'; +import { LoginGov } from '../provider.js'; import { + createAuthRepository, type AuthRepository, - createInMemoryDatabaseContext, - createDatabaseGateway, -} from '@atj/database'; - -import { type AuthContext, type UserSession } from '..'; -import { createSqliteLuciaAdapter } from '../lucia'; -import { LoginGov } from '../provider'; +} from '../repository/index.js'; type Options = { getCookie: (name: string) => string | undefined; @@ -26,9 +26,9 @@ export const createTestAuthContext = async (opts?: Partial) => { isUserAuthorized: opts?.isUserAuthorized || vi.fn(async () => true), }; const dbContext = await createInMemoryDatabaseContext(); - const database = createDatabaseGateway(dbContext); + const authRepo = createAuthRepository(dbContext); return new TestAuthContext( - database.auth, + authRepo, new LoginGov({ loginGovUrl: 'https://idp.int.identitysandbox.gov', clientId: @@ -43,7 +43,7 @@ export const createTestAuthContext = async (opts?: Partial) => { ); }; -export class TestAuthContext implements AuthContext { +export class TestAuthContext implements AuthServiceContext { private lucia?: Lucia; constructor( diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index 542ae507..20cc9d97 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -1,27 +1,17 @@ -import { type Cookie, type User, type Session, type Lucia } from 'lucia'; +import { type User, type Session } from 'lucia'; -import { type AuthRepository } from '@atj/database'; +import { type LoginGovOptions, LoginGov } from './provider.js'; -export { BaseAuthContext } from './context/base'; -import { type LoginGovOptions, LoginGov } from './provider'; +export { BaseAuthContext } from './context/base.js'; export { type LoginGovOptions, LoginGov }; -export { getProviderRedirect } from './services/get-provider-redirect'; -export { logOut } from './services/logout'; -export { processProviderCallback } from './services/process-provider-callback'; -export { processSessionCookie } from './services/process-session-cookie'; +export { getProviderRedirect } from './services/get-provider-redirect.js'; +export { logOut } from './services/logout.js'; +export { processProviderCallback } from './services/process-provider-callback.js'; +export { processSessionCookie } from './services/process-session-cookie.js'; export { User, Session }; +export type { AuthServiceContext } from './services/index.js'; export type UserSession = { user: User | null; session: Session | null; }; - -export type AuthContext = { - db: AuthRepository; - provider: LoginGov; - getCookie: (name: string) => string | undefined; - setCookie: (cookie: Cookie) => void; - setUserSession: (userSession: UserSession) => void; - getLucia: () => Promise; - isUserAuthorized: (email: string) => Promise; -}; diff --git a/packages/database/src/gateways/auth/create-session.test.ts b/packages/auth/src/repository/create-session.test.ts similarity index 90% rename from packages/database/src/gateways/auth/create-session.test.ts rename to packages/auth/src/repository/create-session.test.ts index 20d6c86f..369eac2c 100644 --- a/packages/database/src/gateways/auth/create-session.test.ts +++ b/packages/auth/src/repository/create-session.test.ts @@ -1,7 +1,7 @@ import { expect, it } from 'vitest'; -import { type DbTestContext, describeDatabase } from '../../testing.js'; -import { createUser } from '../auth/create-user.js'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; +import { createUser } from './create-user.js'; import { createSession } from './create-session.js'; describeDatabase('create session', () => { diff --git a/packages/database/src/gateways/auth/create-session.ts b/packages/auth/src/repository/create-session.ts similarity index 83% rename from packages/database/src/gateways/auth/create-session.ts rename to packages/auth/src/repository/create-session.ts index a2fd9691..752c2a0a 100644 --- a/packages/database/src/gateways/auth/create-session.ts +++ b/packages/auth/src/repository/create-session.ts @@ -1,5 +1,4 @@ -import { dateValue } from '../../clients/kysely/db-helpers.js'; -import { type DatabaseContext } from '../../context/types.js'; +import { type DatabaseContext, dateValue } from '@atj/database'; type Session = { id: string; diff --git a/packages/database/src/gateways/auth/create-user.test.ts b/packages/auth/src/repository/create-user.test.ts similarity index 94% rename from packages/database/src/gateways/auth/create-user.test.ts rename to packages/auth/src/repository/create-user.test.ts index 501f60d8..3b429a42 100644 --- a/packages/database/src/gateways/auth/create-user.test.ts +++ b/packages/auth/src/repository/create-user.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { describeDatabase, type DbTestContext } from '../../testing.js'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; import { createUser } from './create-user.js'; diff --git a/packages/database/src/gateways/auth/create-user.ts b/packages/auth/src/repository/create-user.ts similarity index 87% rename from packages/database/src/gateways/auth/create-user.ts rename to packages/auth/src/repository/create-user.ts index 0208b8e9..8f618538 100644 --- a/packages/database/src/gateways/auth/create-user.ts +++ b/packages/auth/src/repository/create-user.ts @@ -1,6 +1,6 @@ import { randomUUID } from 'crypto'; -import { type DatabaseContext } from '../../context/types.js'; +import { type DatabaseContext } from '@atj/database'; export const createUser = async (ctx: DatabaseContext, email: string) => { const id = randomUUID(); diff --git a/packages/database/src/gateways/auth/get-user-id.test.ts b/packages/auth/src/repository/get-user-id.test.ts similarity index 90% rename from packages/database/src/gateways/auth/get-user-id.test.ts rename to packages/auth/src/repository/get-user-id.test.ts index 8dbaa102..03840cc0 100644 --- a/packages/database/src/gateways/auth/get-user-id.test.ts +++ b/packages/auth/src/repository/get-user-id.test.ts @@ -1,7 +1,7 @@ import { randomUUID } from 'crypto'; import { expect, it } from 'vitest'; -import { type DbTestContext, describeDatabase } from '../../testing.js'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; import { getUserId } from './get-user-id.js'; diff --git a/packages/database/src/gateways/auth/get-user-id.ts b/packages/auth/src/repository/get-user-id.ts similarity index 86% rename from packages/database/src/gateways/auth/get-user-id.ts rename to packages/auth/src/repository/get-user-id.ts index f4e6506a..4d4af6f3 100644 --- a/packages/database/src/gateways/auth/get-user-id.ts +++ b/packages/auth/src/repository/get-user-id.ts @@ -1,4 +1,4 @@ -import { type DatabaseContext } from '../../index.js'; +import { type DatabaseContext } from '@atj/database'; export const getUserId = async (ctx: DatabaseContext, email: string) => { const db = await ctx.getKysely(); diff --git a/packages/database/src/gateways/auth/index.ts b/packages/auth/src/repository/index.ts similarity index 56% rename from packages/database/src/gateways/auth/index.ts rename to packages/auth/src/repository/index.ts index e2166e13..c6119491 100644 --- a/packages/database/src/gateways/auth/index.ts +++ b/packages/auth/src/repository/index.ts @@ -1,10 +1,9 @@ import { createService } from '@atj/common'; +import type { DatabaseContext } from '@atj/database'; -import type { DatabaseContext } from '../../context/types'; - -import { createSession } from './create-session'; -import { createUser } from './create-user'; -import { getUserId } from './get-user-id'; +import { createSession } from './create-session.js'; +import { createUser } from './create-user.js'; +import { getUserId } from './get-user-id.js'; export const createAuthRepository = (ctx: DatabaseContext) => createService(ctx, { diff --git a/packages/auth/src/services/get-provider-redirect.test.ts b/packages/auth/src/services/get-provider-redirect.test.ts index 8626273e..63e6ee41 100644 --- a/packages/auth/src/services/get-provider-redirect.test.ts +++ b/packages/auth/src/services/get-provider-redirect.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from 'vitest'; -import { createTestAuthContext } from '../context/test'; +import { createTestAuthContext } from '../context/test.js'; -import { getProviderRedirect } from './get-provider-redirect'; +import { getProviderRedirect } from './get-provider-redirect.js'; describe('getProviderRedirect database gateway', () => { it('returns cookies and redirect url', async () => { diff --git a/packages/auth/src/services/get-provider-redirect.ts b/packages/auth/src/services/get-provider-redirect.ts index 6cd8efb1..3988664d 100644 --- a/packages/auth/src/services/get-provider-redirect.ts +++ b/packages/auth/src/services/get-provider-redirect.ts @@ -1,7 +1,7 @@ import { generateCodeVerifier, generateState } from 'arctic'; -import { AuthContext } from '..'; +import { type AuthServiceContext } from './index.js'; -export const getProviderRedirect = async (ctx: AuthContext) => { +export const getProviderRedirect = async (ctx: AuthServiceContext) => { const state = generateState(); const codeVerifier = generateCodeVerifier(); const nonceCode = generateCodeVerifier(); diff --git a/packages/auth/src/services/index.ts b/packages/auth/src/services/index.ts new file mode 100644 index 00000000..d791ab9e --- /dev/null +++ b/packages/auth/src/services/index.ts @@ -0,0 +1,36 @@ +import { Cookie, Lucia } from 'lucia'; + +import { createService } from '@atj/common'; + +import { + type UserSession, + getProviderRedirect, + logOut, + processProviderCallback, + processSessionCookie, +} from '../index.js'; +import { LoginGov } from '../provider.js'; +import { type AuthRepository } from '../repository/index.js'; + +export type AuthServiceContext = { + db: AuthRepository; + provider: LoginGov; + getCookie: (name: string) => string | undefined; + setCookie: (cookie: Cookie) => void; + setUserSession: (userSession: UserSession) => void; + getLucia: () => Promise; + isUserAuthorized: (email: string) => Promise; +}; + +export const createAuthService = (ctx: AuthServiceContext) => + createService(ctx, { + getProviderRedirect, + logOut, + processProviderCallback, + processSessionCookie, + }); + +export type AuthService = Omit< + ReturnType, + 'getContext' +>; diff --git a/packages/auth/src/services/logout.test.ts b/packages/auth/src/services/logout.test.ts index bda56c67..a33efc12 100644 --- a/packages/auth/src/services/logout.test.ts +++ b/packages/auth/src/services/logout.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from 'vitest'; -import { createTestAuthContext } from '../context/test'; -import { logOut } from './logout'; +import { createTestAuthContext } from '../context/test.js'; +import { logOut } from './logout.js'; describe('logOut database gateway', () => { it('works', async () => { diff --git a/packages/auth/src/services/logout.ts b/packages/auth/src/services/logout.ts index bfba9bf5..00179c70 100644 --- a/packages/auth/src/services/logout.ts +++ b/packages/auth/src/services/logout.ts @@ -1,7 +1,7 @@ import { type Session } from 'lucia'; -import { type AuthContext } from '..'; +import { type AuthServiceContext } from './index.js'; -export const logOut = async (ctx: AuthContext, session: Session) => { +export const logOut = async (ctx: AuthServiceContext, session: Session) => { const lucia = await ctx.getLucia(); await lucia.invalidateSession(session.id); const sessionCookie = lucia.createBlankSessionCookie(); diff --git a/packages/auth/src/services/process-provider-callback.test.ts b/packages/auth/src/services/process-provider-callback.test.ts index 5a9595cf..9a777472 100644 --- a/packages/auth/src/services/process-provider-callback.test.ts +++ b/packages/auth/src/services/process-provider-callback.test.ts @@ -1,11 +1,11 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { processProviderCallback } from './process-provider-callback'; -import { createTestAuthContext } from '../context/test'; -import { AuthContext } from '..'; +import { processProviderCallback } from './process-provider-callback.js'; +import { createTestAuthContext } from '../context/test.js'; +import { type AuthServiceContext } from './index.js'; describe('processProviderCallback', () => { - let ctx: AuthContext; + let ctx: AuthServiceContext; beforeEach(async () => { // Set up global mocks diff --git a/packages/auth/src/services/process-provider-callback.ts b/packages/auth/src/services/process-provider-callback.ts index b4ba5919..4d5ac9b2 100644 --- a/packages/auth/src/services/process-provider-callback.ts +++ b/packages/auth/src/services/process-provider-callback.ts @@ -1,8 +1,8 @@ import { OAuth2RequestError } from 'arctic'; +import { randomUUID } from 'crypto'; import * as r from '@atj/common'; -import { type AuthContext } from '..'; -import { randomUUID } from 'crypto'; +import { type AuthServiceContext } from './index.js'; type LoginGovUser = { sub: string; @@ -19,7 +19,7 @@ type Params = { }; export const processProviderCallback = async ( - ctx: AuthContext, + ctx: AuthServiceContext, params: Params, storedParams: Params & { nonce: string | null }, fetchUserData: typeof fetchUserDataImpl = fetchUserDataImpl diff --git a/packages/auth/src/services/process-session-cookie.test.ts b/packages/auth/src/services/process-session-cookie.test.ts index b85b4428..3865760c 100644 --- a/packages/auth/src/services/process-session-cookie.test.ts +++ b/packages/auth/src/services/process-session-cookie.test.ts @@ -1,8 +1,8 @@ import { randomUUID } from 'crypto'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { createTestAuthContext } from '../context/test'; -import { processSessionCookie } from './process-session-cookie'; +import { createTestAuthContext } from '../context/test.js'; +import { processSessionCookie } from './process-session-cookie.js'; describe('processSessionCookie', () => { const today = new Date(2020, 1, 1); diff --git a/packages/auth/src/services/process-session-cookie.ts b/packages/auth/src/services/process-session-cookie.ts index 8bc66dcd..401a7122 100644 --- a/packages/auth/src/services/process-session-cookie.ts +++ b/packages/auth/src/services/process-session-cookie.ts @@ -2,10 +2,10 @@ import { verifyRequestOrigin } from 'lucia'; import { type VoidResult } from '@atj/common'; -import { type AuthContext } from '..'; +import { type AuthServiceContext } from './index.js'; export const processSessionCookie = async ( - ctx: AuthContext, + ctx: AuthServiceContext, request: Request ): Promise> => { if (request.method !== 'GET') { diff --git a/packages/auth/tsconfig.json b/packages/auth/tsconfig.json index 24abc391..0efd82a1 100644 --- a/packages/auth/tsconfig.json +++ b/packages/auth/tsconfig.json @@ -2,6 +2,8 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "emitDeclarationOnly": false, + "module": "NodeNext", + "moduleResolution": "NodeNext", "outDir": "./dist", "rootDir": "./src" }, diff --git a/packages/auth/vitest.config.ts b/packages/auth/vitest.config.ts index 90197569..68cf95c0 100644 --- a/packages/auth/vitest.config.ts +++ b/packages/auth/vitest.config.ts @@ -1,11 +1,13 @@ import { defineConfig, mergeConfig } from 'vitest/config'; +import { getVitestDatabaseContainerGlobalSetupPath } from '@atj/database'; import sharedTestConfig from '../../vitest.shared'; export default mergeConfig( sharedTestConfig, defineConfig({ test: { + globalSetup: [getVitestDatabaseContainerGlobalSetupPath()], setupFiles: ['./vitest.setup.ts'], }, }) diff --git a/packages/database/package.json b/packages/database/package.json index 439e13b8..fb91fe1d 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -41,7 +41,6 @@ "rollup": "^4.20.0", "rollup-plugin-typescript2": "^0.36.0", "testcontainers": "^10.11.0", - "typescript": "^5.5.4", "vite-tsconfig-paths": "^4.3.2" } } diff --git a/packages/database/src/gateways/forms/index.ts b/packages/database/src/gateways/forms/index.ts deleted file mode 100644 index 4afb12ee..00000000 --- a/packages/database/src/gateways/forms/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { createService, type Result, type VoidResult } from '@atj/common'; - -import type { DatabaseContext } from '../../context/types'; -import { addForm } from './add-form'; -import { deleteForm } from './delete-form'; -import { getFormList } from './get-form-list'; -import { getForm } from './get-form'; -import { saveForm } from './save-form'; - -export interface FormRepository { - addForm( - form: any /*Blueprint*/ - ): Promise>; - deleteForm(formId: string): Promise; - getForm(id?: string): Promise; - getFormList(): Promise< - | { - id: string; - title: string; - description: string; - }[] - | null - >; - saveForm(formId: string, form: /*Blueprint*/ any): Promise; -} - -export const createFormsRepository = (ctx: DatabaseContext): FormRepository => - createService(ctx, { - addForm, - deleteForm, - getFormList, - getForm, - saveForm, - }); diff --git a/packages/database/src/index.ts b/packages/database/src/index.ts index f2cb0ce4..479ea9da 100644 --- a/packages/database/src/index.ts +++ b/packages/database/src/index.ts @@ -1,22 +1,7 @@ import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; -import { DatabaseContext } from './context/types.js'; -import { - type FormRepository, - createFormsRepository, -} from './gateways/forms/index.js'; -import { - type AuthRepository, - createAuthRepository, -} from './gateways/auth/index.js'; - -export { - type AuthRepository, - type FormRepository, - createAuthRepository, - createFormsRepository, -}; +export { dateValue } from './clients/kysely/db-helpers.js'; export { type FilesystemDatabaseContext, createFilesystemDatabaseContext, @@ -27,15 +12,6 @@ export { type Database } from './clients/kysely/types.js'; export { type DatabaseContext } from './context/types.js'; export { migrateDatabase } from './management/migrate-database.js'; -export const getDatabaseTestContainerGlobalSetupPath = () => { +export const getVitestDatabaseContainerGlobalSetupPath = () => { return join(dirname(fileURLToPath(import.meta.url)), '../../vitest.setup.ts'); }; - -export const createDatabaseGateway = (ctx: DatabaseContext) => { - return { - auth: createAuthRepository(ctx), - forms: createFormsRepository(ctx), - }; -}; - -export type DatabaseGateway = ReturnType; diff --git a/packages/forms/src/context/browser/form-repo.ts b/packages/forms/src/context/browser/form-repo.ts index 92a6cce5..cdfbfcea 100644 --- a/packages/forms/src/context/browser/form-repo.ts +++ b/packages/forms/src/context/browser/form-repo.ts @@ -1,7 +1,7 @@ -import { failure, Result, VoidResult } from '@atj/common'; -import type { FormRepository } from '@atj/database'; +import { type Result, type VoidResult, failure } from '@atj/common'; import { type Blueprint } from '../../index.js'; +import { FormRepository } from '../../repository/index.js'; export class BrowserFormRepository implements FormRepository { constructor(private storage: Storage) {} diff --git a/packages/forms/src/context/index.ts b/packages/forms/src/context/index.ts index b64a595e..fadd1ef2 100644 --- a/packages/forms/src/context/index.ts +++ b/packages/forms/src/context/index.ts @@ -1,7 +1,7 @@ -import type { FormRepository } from '@atj/database'; import { type FormConfig } from '../pattern.js'; +import type { FormRepository } from '../repository/index.js'; export type FormServiceContext = { - db: FormRepository; + repository: FormRepository; config: FormConfig; }; diff --git a/packages/forms/src/context/test/index.ts b/packages/forms/src/context/test/index.ts index 2398102e..3e1a38f0 100644 --- a/packages/forms/src/context/test/index.ts +++ b/packages/forms/src/context/test/index.ts @@ -6,9 +6,9 @@ import { BrowserFormRepository } from '../browser/form-repo.js'; // In tests, use the browser form service with fakes injected. export const createTestFormService = (testData: TestData = {}) => { const storage = createTestStorage(testData); - const db = new BrowserFormRepository(storage); + const repository = new BrowserFormRepository(storage); const formService = createFormService({ - db, + repository, config: defaultFormConfig, }); if (testData) { diff --git a/packages/forms/src/index.ts b/packages/forms/src/index.ts index 5173d24b..14c917bc 100644 --- a/packages/forms/src/index.ts +++ b/packages/forms/src/index.ts @@ -24,6 +24,7 @@ export * from './session.js'; export { type FormService, createFormService } from './services/index.js'; export { type FormServiceContext } from './context/index.js'; export { createTestFormService } from './context/test/index.js'; +export { type FormRepository } from './repository/index.js'; export type Blueprint = { summary: FormSummary; diff --git a/packages/database/src/gateways/forms/add-form.test.ts b/packages/forms/src/repository/add-form.test.ts similarity index 94% rename from packages/database/src/gateways/forms/add-form.test.ts rename to packages/forms/src/repository/add-form.test.ts index a07eabfa..17f8b5c7 100644 --- a/packages/database/src/gateways/forms/add-form.test.ts +++ b/packages/forms/src/repository/add-form.test.ts @@ -1,6 +1,6 @@ import { beforeAll, expect, it, vi } from 'vitest'; -import { type DbTestContext, describeDatabase } from '../../testing.js'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; import { addForm } from './add-form.js'; describeDatabase('add form', () => { diff --git a/packages/database/src/gateways/forms/add-form.ts b/packages/forms/src/repository/add-form.ts similarity index 83% rename from packages/database/src/gateways/forms/add-form.ts rename to packages/forms/src/repository/add-form.ts index c1adfd51..93ddfeed 100644 --- a/packages/database/src/gateways/forms/add-form.ts +++ b/packages/forms/src/repository/add-form.ts @@ -1,7 +1,7 @@ import { type Result, failure, success } from '@atj/common'; -import { type DatabaseContext } from '../../context/types'; -import { stringifyForm } from './serialize'; +import { type DatabaseContext } from '@atj/database'; +import { stringifyForm } from './serialize.js'; export const addForm = async ( ctx: DatabaseContext, diff --git a/packages/database/src/gateways/forms/delete-form.test.ts b/packages/forms/src/repository/delete-form.test.ts similarity index 94% rename from packages/database/src/gateways/forms/delete-form.test.ts rename to packages/forms/src/repository/delete-form.test.ts index 1e088a3e..5b104bb6 100644 --- a/packages/database/src/gateways/forms/delete-form.test.ts +++ b/packages/forms/src/repository/delete-form.test.ts @@ -1,6 +1,6 @@ import { beforeAll, expect, it, vi } from 'vitest'; -import { type DbTestContext, describeDatabase } from '../../testing.js'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; import { deleteForm } from './delete-form.js'; describeDatabase('delete form', () => { diff --git a/packages/database/src/gateways/forms/delete-form.ts b/packages/forms/src/repository/delete-form.ts similarity index 87% rename from packages/database/src/gateways/forms/delete-form.ts rename to packages/forms/src/repository/delete-form.ts index d62fbc48..6ac2f2fe 100644 --- a/packages/database/src/gateways/forms/delete-form.ts +++ b/packages/forms/src/repository/delete-form.ts @@ -1,6 +1,6 @@ import { type VoidResult, failure } from '@atj/common'; -import { type DatabaseContext } from '../../context/types'; +import { type DatabaseContext } from '@atj/database'; export const deleteForm = async ( ctx: DatabaseContext, diff --git a/packages/database/src/gateways/forms/get-form-list.test.ts b/packages/forms/src/repository/get-form-list.test.ts similarity index 89% rename from packages/database/src/gateways/forms/get-form-list.test.ts rename to packages/forms/src/repository/get-form-list.test.ts index ba374f5d..33841208 100644 --- a/packages/database/src/gateways/forms/get-form-list.test.ts +++ b/packages/forms/src/repository/get-form-list.test.ts @@ -1,8 +1,8 @@ import { expect, it } from 'vitest'; -import { DbTestContext, describeDatabase } from '../../testing'; -import { getForm } from './get-form'; -import { getFormList } from './get-form-list'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; +import { getForm } from './get-form.js'; +import { getFormList } from './get-form-list.js'; describeDatabase('getFormList', () => { it('retrieves form list successfully', async ({ db }) => { diff --git a/packages/database/src/gateways/forms/get-form-list.ts b/packages/forms/src/repository/get-form-list.ts similarity index 77% rename from packages/database/src/gateways/forms/get-form-list.ts rename to packages/forms/src/repository/get-form-list.ts index d8ff4544..745beda3 100644 --- a/packages/database/src/gateways/forms/get-form-list.ts +++ b/packages/forms/src/repository/get-form-list.ts @@ -1,5 +1,4 @@ -//import { type Blueprint } from '@atj/forms'; -import { type DatabaseContext } from '../../context/types'; +import { type DatabaseContext } from '@atj/database'; export const getFormList = async (ctx: DatabaseContext) => { const db = await ctx.getKysely(); diff --git a/packages/database/src/gateways/forms/get-form.test.ts b/packages/forms/src/repository/get-form.test.ts similarity index 90% rename from packages/database/src/gateways/forms/get-form.test.ts rename to packages/forms/src/repository/get-form.test.ts index 8d07cfb9..b9d943b9 100644 --- a/packages/database/src/gateways/forms/get-form.test.ts +++ b/packages/forms/src/repository/get-form.test.ts @@ -1,7 +1,7 @@ import { expect, it } from 'vitest'; -import { DbTestContext, describeDatabase } from '../../testing'; -import { getForm } from './get-form'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; +import { getForm } from './get-form.js'; describeDatabase('getForm', () => { it('retrieves form successfully', async ({ db }) => { diff --git a/packages/database/src/gateways/forms/get-form.ts b/packages/forms/src/repository/get-form.ts similarity index 88% rename from packages/database/src/gateways/forms/get-form.ts rename to packages/forms/src/repository/get-form.ts index 3c54873f..42c751b2 100644 --- a/packages/database/src/gateways/forms/get-form.ts +++ b/packages/forms/src/repository/get-form.ts @@ -1,6 +1,6 @@ -//import { Blueprint } from '@atj/forms'; -type Blueprint = any; -import { DatabaseContext } from '../../context/types'; +import { type DatabaseContext } from '@atj/database'; + +import { type Blueprint } from '../index.js'; export const getForm = async ( ctx: DatabaseContext, diff --git a/packages/forms/src/repository/index.ts b/packages/forms/src/repository/index.ts new file mode 100644 index 00000000..47b74e2b --- /dev/null +++ b/packages/forms/src/repository/index.ts @@ -0,0 +1,34 @@ +import { createService, type Result, type VoidResult } from '@atj/common'; +import type { DatabaseContext } from '@atj/database'; + +import { Blueprint } from '../index.js'; + +import { addForm } from './add-form.js'; +import { deleteForm } from './delete-form.js'; +import { getFormList } from './get-form-list.js'; +import { getForm } from './get-form.js'; +import { saveForm } from './save-form.js'; + +export interface FormRepository { + addForm(form: Blueprint): Promise>; + deleteForm(formId: string): Promise; + getForm(id?: string): Promise; + getFormList(): Promise< + | { + id: string; + title: string; + description: string; + }[] + | null + >; + saveForm(formId: string, form: Blueprint): Promise; +} + +export const createFormsRepository = (ctx: DatabaseContext): FormRepository => + createService(ctx, { + addForm, + deleteForm, + getFormList, + getForm, + saveForm, + }); diff --git a/packages/database/src/gateways/forms/save-form.test.ts b/packages/forms/src/repository/save-form.test.ts similarity index 88% rename from packages/database/src/gateways/forms/save-form.test.ts rename to packages/forms/src/repository/save-form.test.ts index 1b2b7801..600a60de 100644 --- a/packages/database/src/gateways/forms/save-form.test.ts +++ b/packages/forms/src/repository/save-form.test.ts @@ -1,8 +1,9 @@ import { expect, it } from 'vitest'; -import { type DbTestContext, describeDatabase } from '../../testing'; -import { saveForm } from './save-form'; -import { addForm } from './add-form'; +import { type DbTestContext, describeDatabase } from '@atj/database/testing'; + +import { saveForm } from './save-form.js'; +import { addForm } from './add-form.js'; const TEST_FORM = { summary: { diff --git a/packages/database/src/gateways/forms/save-form.ts b/packages/forms/src/repository/save-form.ts similarity index 72% rename from packages/database/src/gateways/forms/save-form.ts rename to packages/forms/src/repository/save-form.ts index 6b3ffcb2..b84b8adc 100644 --- a/packages/database/src/gateways/forms/save-form.ts +++ b/packages/forms/src/repository/save-form.ts @@ -1,8 +1,8 @@ -//import { type Blueprint } from '@atj/forms'; -type Blueprint = any; -import { type DatabaseContext } from '../../context/types'; -import { stringifyForm } from './serialize'; import { failure, success } from '@atj/common'; +import { type DatabaseContext } from '@atj/database'; + +import { type Blueprint } from '../index.js'; +import { stringifyForm } from './serialize.js'; export const saveForm = async ( ctx: DatabaseContext, diff --git a/packages/database/src/gateways/forms/serialize.ts b/packages/forms/src/repository/serialize.ts similarity index 100% rename from packages/database/src/gateways/forms/serialize.ts rename to packages/forms/src/repository/serialize.ts diff --git a/packages/forms/src/services/add-form.ts b/packages/forms/src/services/add-form.ts index bd2c10e7..d14f69e7 100644 --- a/packages/forms/src/services/add-form.ts +++ b/packages/forms/src/services/add-form.ts @@ -7,5 +7,5 @@ export const addForm = async ( ctx: FormServiceContext, form: Blueprint ): Promise> => { - return ctx.db.addForm(form); + return ctx.repository.addForm(form); }; diff --git a/packages/forms/src/services/delete-form.ts b/packages/forms/src/services/delete-form.ts index a3166a00..0dd96f0e 100644 --- a/packages/forms/src/services/delete-form.ts +++ b/packages/forms/src/services/delete-form.ts @@ -6,14 +6,14 @@ export const deleteForm = async ( ctx: FormServiceContext, formId: string ): Promise => { - const form = await ctx.db.getForm(formId); + const form = await ctx.repository.getForm(formId); if (form === null) { return { success: false, error: `form '${formId} does not exist`, }; } - ctx.db.deleteForm(formId); + ctx.repository.deleteForm(formId); return { success: true, }; diff --git a/packages/forms/src/services/get-form-list.ts b/packages/forms/src/services/get-form-list.ts index 00121e65..4144a5b6 100644 --- a/packages/forms/src/services/get-form-list.ts +++ b/packages/forms/src/services/get-form-list.ts @@ -11,7 +11,7 @@ export type FormListItem = { export const getFormList = async ( ctx: FormServiceContext ): Promise> => { - const forms = await ctx.db.getFormList(); + const forms = await ctx.repository.getFormList(); if (forms === null) { return { success: false, diff --git a/packages/forms/src/services/get-form.ts b/packages/forms/src/services/get-form.ts index 7e704148..96da58c6 100644 --- a/packages/forms/src/services/get-form.ts +++ b/packages/forms/src/services/get-form.ts @@ -7,7 +7,7 @@ export const getForm = async ( ctx: FormServiceContext, formId: string ): Promise> => { - const result = await ctx.db.getForm(formId); + const result = await ctx.repository.getForm(formId); if (result === null) { return { success: false, diff --git a/packages/forms/src/services/index.ts b/packages/forms/src/services/index.ts index 711681a4..1fcb89b1 100644 --- a/packages/forms/src/services/index.ts +++ b/packages/forms/src/services/index.ts @@ -1,6 +1,11 @@ import { createService } from '@atj/common'; import { type FormServiceContext } from '../context/index.js'; +import { type FormConfig } from '../pattern.js'; +import { + type FormRepository, + createFormsRepository, +} from '../repository/index.js'; import { addForm } from './add-form.js'; import { deleteForm } from './delete-form.js'; diff --git a/packages/forms/src/services/save-form.ts b/packages/forms/src/services/save-form.ts index 071fa99e..bb2ace17 100644 --- a/packages/forms/src/services/save-form.ts +++ b/packages/forms/src/services/save-form.ts @@ -8,7 +8,7 @@ export const saveForm = async ( formId: string, form: Blueprint ): Promise> => { - const result = await ctx.db.saveForm(formId, form); + const result = await ctx.repository.saveForm(formId, form); if (result.success === false) { return { success: false, diff --git a/packages/forms/src/services/submit-form.test.ts b/packages/forms/src/services/submit-form.test.ts index 84363db3..2ec22c4e 100644 --- a/packages/forms/src/services/submit-form.test.ts +++ b/packages/forms/src/services/submit-form.test.ts @@ -7,7 +7,9 @@ describe('submitForm', () => { it('succeeds with empty form', async () => { const service = await createTestFormService(); const testForm = createForm({ title: 'test', description: 'description' }); - const addFormResult = await service.getContext().db.addForm(testForm); + const addFormResult = await service + .getContext() + .repository.addForm(testForm); if (addFormResult.success === false) { expect.fail('addForm failed'); } diff --git a/packages/forms/src/services/submit-form.ts b/packages/forms/src/services/submit-form.ts index bbee94e5..9cca6d8d 100644 --- a/packages/forms/src/services/submit-form.ts +++ b/packages/forms/src/services/submit-form.ts @@ -24,7 +24,7 @@ export const submitForm = async ( }[] > > => { - const form = await ctx.db.getForm(formId); + const form = await ctx.repository.getForm(formId); if (form === null) { return Promise.resolve({ success: false, diff --git a/packages/server/package.json b/packages/server/package.json index 844230b5..31407042 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -29,8 +29,7 @@ "jwt-decode": "^4.0.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-error-boundary": "^4.0.13", - "typescript": "^5.5.4" + "react-error-boundary": "^4.0.13" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/packages/server/src/context.ts b/packages/server/src/context.ts index c6758edb..ba41274c 100644 --- a/packages/server/src/context.ts +++ b/packages/server/src/context.ts @@ -3,19 +3,24 @@ import { fileURLToPath } from 'url'; import { type APIContext, type AstroGlobal } from 'astro'; -import type { AuthContext, LoginGovOptions } from '@atj/auth'; -import { type DatabaseGateway } from '@atj/database'; +import type { AuthServiceContext, LoginGovOptions } from '@atj/auth'; import { type FormConfig, + type FormRepository, type FormService, createFormService, defaultFormConfig, } from '@atj/forms'; import { type GithubRepository } from './lib/github.js'; +import { + AuthRepository, + createAuthRepository, +} from '@atj/auth/dist/repository/index.js'; +import { createFormsRepository } from '@atj/forms/src/repository/index.js'; export type AppContext = { - auth: AuthContext; + auth: AuthServiceContext; baseUrl: `${string}/`; formConfig: FormConfig; formService: FormService; @@ -26,7 +31,10 @@ export type AppContext = { export type ServerOptions = { title: string; - db: DatabaseGateway; + db: { + auth: AuthRepository; + forms: FormRepository; + }; loginGovOptions: LoginGovOptions; isUserAuthorized: (email: string) => Promise; }; @@ -46,14 +54,14 @@ const createAstroAppContext = async ( return { auth: await createDefaultAuthContext({ Astro, - db: serverOptions.db, + authRepository: serverOptions.db.auth, loginGovOptions: serverOptions.loginGovOptions, isUserAuthorized: serverOptions.isUserAuthorized, }), baseUrl: env.BASE_URL, formConfig: defaultFormConfig, formService: createFormService({ - db: serverOptions.db.forms, + repository: serverOptions.db.forms, config: defaultFormConfig, }), github: env.GITHUB, @@ -87,12 +95,14 @@ const getServerOptions = async (Astro: AstroGlobal | APIContext) => { const getDirname = () => dirname(fileURLToPath(import.meta.url)); const createDefaultDatabaseGateway = async () => { - const { createDatabaseGateway, createFilesystemDatabaseContext } = - await import('@atj/database'); + const { createFilesystemDatabaseContext } = await import('@atj/database'); const ctx = await createFilesystemDatabaseContext( join(getDirname(), '../main.db') ); - const gateway = createDatabaseGateway(ctx); + const gateway = { + auth: createAuthRepository(ctx), + forms: createFormsRepository(ctx), + }; return Promise.resolve(gateway); }; @@ -106,18 +116,18 @@ const getOriginFromRequest = (Astro: AstroGlobal | APIContext) => { const createDefaultAuthContext = async ({ Astro, - db, + authRepository, loginGovOptions, isUserAuthorized, }: { Astro: AstroGlobal | APIContext; - db: DatabaseGateway; + authRepository: AuthRepository; loginGovOptions: LoginGovOptions; isUserAuthorized: (email: string) => Promise; }) => { const { LoginGov, BaseAuthContext } = await import('@atj/auth'); return new BaseAuthContext( - db.auth, + authRepository, new LoginGov({ ...loginGovOptions, redirectURI: `${getOriginFromRequest(Astro)}/signin/callback`, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d1f0a46..73c798fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -285,9 +285,6 @@ importers: testcontainers: specifier: ^10.11.0 version: 10.11.0 - typescript: - specifier: ^5.5.4 - version: 5.5.4 vite-tsconfig-paths: specifier: ^4.3.2 version: 4.3.2(typescript@5.5.4) @@ -528,9 +525,6 @@ importers: react-error-boundary: specifier: ^4.0.13 version: 4.0.13(react@18.3.1) - typescript: - specifier: ^5.5.4 - version: 5.5.4 devDependencies: '@types/express': specifier: ^4.17.21 @@ -10009,7 +10003,7 @@ packages: dependencies: semver: 7.6.3 shelljs: 0.8.5 - typescript: 5.7.0-dev.20240821 + typescript: 5.7.0-dev.20240822 dev: false /dset@3.1.3: @@ -19064,8 +19058,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - /typescript@5.7.0-dev.20240821: - resolution: {integrity: sha512-0Fy9p2k7DxC6OWPSXqJbrzkaxL4R7N+VRaxHnFeWnYSqwLfKQTX2JeARy+MGcSphRP9KKe/DtMGXYdoULHjMHw==} + /typescript@5.7.0-dev.20240822: + resolution: {integrity: sha512-JL60efPDEbshbweVXX18Ic5g+9iVbf2Nc3xh3eBGbLjrt5+x6KZzB3c2d+J5PoqOzPjbFATCT2FQ3W8vEGOXTg==} engines: {node: '>=14.17'} hasBin: true dev: false