From f97d963b30faef47db2ce5e1f68b58956e60cee7 Mon Sep 17 00:00:00 2001 From: nourshoreibah Date: Tue, 9 Jun 2026 20:18:19 -0400 Subject: [PATCH 1/3] Create shared @branch/dtos package to deduplicate DTOs across lambdas Replaces the per-lambda copies of db-types.d.ts and the duplicated auth DTO interfaces with a single types-only package in shared/dtos, installed in every lambda via a file: dependency. Since the package ships only .d.ts files, imports are erased at compile time and the deployed lambda.zip artifacts remain fully self contained. The lambda CLI now adds the package to new handlers, and the regenerate-db-types workflow writes the generated types into shared/dtos instead of copying them into each lambda. The unused shared git submodule is replaced by a regular directory. Co-authored-by: Cursor --- .github/workflows/lambda-deploy.yml | 1 + .github/workflows/regenerate-db-types.yaml | 123 ++++++------------ .gitmodules | 3 - apps/backend/lambdas/auth/db-types.d.ts | 79 ----------- apps/backend/lambdas/auth/db.ts | 2 +- apps/backend/lambdas/auth/package-lock.json | 42 +++--- apps/backend/lambdas/auth/package.json | 1 + apps/backend/lambdas/donors/auth.ts | 16 +-- apps/backend/lambdas/donors/db-types.d.ts | 79 ----------- apps/backend/lambdas/donors/db.ts | 2 +- apps/backend/lambdas/donors/package-lock.json | 42 +++--- apps/backend/lambdas/donors/package.json | 1 + apps/backend/lambdas/expenditures/auth.ts | 16 +-- .../lambdas/expenditures/db-types.d.ts | 81 ------------ apps/backend/lambdas/expenditures/db.ts | 2 +- .../lambdas/expenditures/package-lock.json | 10 ++ .../backend/lambdas/expenditures/package.json | 1 + apps/backend/lambdas/projects/auth.ts | 16 +-- apps/backend/lambdas/projects/db-types.d.ts | 78 ----------- apps/backend/lambdas/projects/db.ts | 2 +- .../lambdas/projects/package-lock.json | 42 +++--- apps/backend/lambdas/projects/package.json | 1 + apps/backend/lambdas/reports/auth.ts | 16 +-- apps/backend/lambdas/reports/db.ts | 2 +- apps/backend/lambdas/reports/handler.ts | 2 +- .../backend/lambdas/reports/package-lock.json | 42 +++--- apps/backend/lambdas/reports/package.json | 1 + apps/backend/lambdas/tools/README.md | 2 +- apps/backend/lambdas/tools/lambda-cli.js | 1 + apps/backend/lambdas/users/auth.ts | 31 ++--- apps/backend/lambdas/users/db-types.d.ts | 80 ------------ apps/backend/lambdas/users/db.ts | 2 +- apps/backend/lambdas/users/package-lock.json | 42 +++--- apps/backend/lambdas/users/package.json | 1 + shared | 1 - shared/dtos/README.md | 39 ++++++ shared/dtos/auth-types.d.ts | 23 ++++ .../reports => shared/dtos}/db-types.d.ts | 13 +- shared/dtos/index.d.ts | 2 + shared/dtos/package.json | 10 ++ 40 files changed, 305 insertions(+), 645 deletions(-) delete mode 100644 .gitmodules delete mode 100644 apps/backend/lambdas/auth/db-types.d.ts delete mode 100644 apps/backend/lambdas/donors/db-types.d.ts delete mode 100644 apps/backend/lambdas/expenditures/db-types.d.ts delete mode 100644 apps/backend/lambdas/projects/db-types.d.ts delete mode 100644 apps/backend/lambdas/users/db-types.d.ts delete mode 160000 shared create mode 100644 shared/dtos/README.md create mode 100644 shared/dtos/auth-types.d.ts rename {apps/backend/lambdas/reports => shared/dtos}/db-types.d.ts (83%) create mode 100644 shared/dtos/index.d.ts create mode 100644 shared/dtos/package.json diff --git a/.github/workflows/lambda-deploy.yml b/.github/workflows/lambda-deploy.yml index a298c2e2..88de626e 100644 --- a/.github/workflows/lambda-deploy.yml +++ b/.github/workflows/lambda-deploy.yml @@ -5,6 +5,7 @@ on: branches: [main] paths: - 'apps/backend/lambdas/**' + - 'shared/dtos/**' jobs: detect-changes: diff --git a/.github/workflows/regenerate-db-types.yaml b/.github/workflows/regenerate-db-types.yaml index 72e8ae7e..ace29a4c 100644 --- a/.github/workflows/regenerate-db-types.yaml +++ b/.github/workflows/regenerate-db-types.yaml @@ -110,65 +110,46 @@ jobs: echo "Type generation successful" - - name: Copy generated types to lambda functions + - name: Copy generated types to shared DTOs package run: | - echo "Copying generated types to lambda functions" + echo "Copying generated types to shared/dtos" SOURCE_FILE="apps/backend/db/db-types.d.ts" + TARGET_FILE="shared/dtos/db-types.d.ts" - # verify the source file exists - if [ ! -f "$SOURCE_FILE" ]; then - echo "Error: Generated types file not found at $SOURCE_FILE" - exit 1 - fi - + # verify the source file exists and is not empty if [ ! -s "$SOURCE_FILE" ]; then - echo "Error: Generated types file is empty" + echo "Error: Generated types file not found or empty at $SOURCE_FILE" exit 1 fi - # Define target lambda directories - LAMBDA_DIRS=() - for dir in apps/backend/lambdas/*; do - if [ -d "$dir" ]; then - LAMBDA_DIRS+=("$dir") - echo " Found: $dir" - fi - done - - if [ ${#LAMBDA_DIRS[@]} -eq 0 ]; then - echo "Error: No lambda directories found in apps/backend/lambdas/" - exit 1 - fi + # Replace the kysely import with a local, structurally identical + # ColumnType so the shared package stays dependency-free and the + # lambdas stay fully self contained. + node -e ' + const fs = require("fs"); + const [src, target] = process.argv.slice(1); + const kyselyImport = `import type { ColumnType } from "kysely";`; + const localColumnType = [ + "/**", + " * Structurally identical to kysely'"'"'s ColumnType, defined locally so this", + " * package has no dependencies and lambdas stay fully self contained.", + " */", + "type ColumnType = {", + " readonly __select__: SelectType;", + " readonly __insert__: InsertType;", + " readonly __update__: UpdateType;", + "};", + ].join("\n"); + const contents = fs.readFileSync(src, "utf8"); + if (!contents.includes(kyselyImport)) { + console.error("Error: expected kysely ColumnType import not found in " + src); + process.exit(1); + } + fs.writeFileSync(target, contents.replace(kyselyImport, localColumnType)); + ' "$SOURCE_FILE" "$TARGET_FILE" - # Track success and failures - SUCCESS_COUNT=0 - FAIL_COUNT=0 - - for dir in "${LAMBDA_DIRS[@]}"; do - if [ -d "$dir" ]; then - echo "Copying to $dir/db-types.d.ts" - cp "$SOURCE_FILE" "$dir/db-types.d.ts" - - if [ $? -eq 0 ]; then - ((SUCCESS_COUNT++)) - else - echo "Failed to copy to $dir" - ((FAIL_COUNT++)) - fi - else - echo "Warning: Directory $dir does not exist" - ((FAIL_COUNT++)) - fi - done - - echo "" - echo "Copy summary: $SUCCESS_COUNT succeeded, $FAIL_COUNT failed" - - if [ $SUCCESS_COUNT -eq 0 ]; then - echo "Error: Failed to copy types to any lambda function" - exit 1 - fi + echo "Wrote $TARGET_FILE" - name: Verify TypeScript compilation run: | @@ -181,14 +162,10 @@ jobs: echo "Performing basic syntax check on generated types..." # Ensure the file is valid TypeScript - for file in apps/backend/lambdas/*/db-types.d.ts; do - if [ -f "$file" ]; then - npx tsc --noEmit --skipLibCheck "$file" || { - echo "Error: $file contains TypeScript errors" - exit 1 - } - fi - done + npx tsc --noEmit --skipLibCheck shared/dtos/db-types.d.ts || { + echo "Error: shared/dtos/db-types.d.ts contains TypeScript errors" + exit 1 + } else npx tsc --noEmit --skipLibCheck || { echo "Error: TypeScript compilation failed" @@ -202,9 +179,9 @@ jobs: - name: Check for changes id: git-check run: | - git add -N apps/backend/lambdas/*/db-types.d.ts + git add -N shared/dtos/db-types.d.ts - if git diff --exit-code apps/backend/lambdas/*/db-types.d.ts; then + if git diff --exit-code shared/dtos/db-types.d.ts; then echo "changes=false" >> $GITHUB_OUTPUT echo "No changes detected in generated types" else @@ -212,7 +189,7 @@ jobs: echo "Changes detected in generated types" echo "Changed files:" - git diff --name-only apps/backend/lambdas/*/db-types.d.ts + git diff --name-only shared/dtos/db-types.d.ts fi - name: Get PR author information @@ -242,7 +219,7 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add apps/backend/lambdas/*/db-types.d.ts + git add shared/dtos/db-types.d.ts COMMIT_MESSAGE="chore: auto-regenerate database types from schema changes" @@ -263,22 +240,13 @@ jobs: uses: actions/github-script@v7 with: script: | - const { execSync } = require('child_process'); - const files = execSync('git diff --name-only apps/backend/lambdas/*/db-types.d.ts') - .toString() - .trim() - .split('\n') - .filter(f => f) - .map(f => `- \`${f}\``) - .join('\n'); - const comment = `**Database Types Auto-Regenerated** - The database schema has changed and the Typescript definitions for these lambda functions were regenerated: + The database schema has changed and the shared TypeScript definitions were regenerated: - ${files} + - \`shared/dtos/db-types.d.ts\` - The updated types are now in sync with schema changes.`; + All lambdas consume these types through the \`@branch/dtos\` package, so they are now in sync with the schema changes.`; github.rest.issues.createComment({ issue_number: context.issue.number, @@ -316,12 +284,7 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "The following files were updated and committed:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - - for file in apps/backend/lambdas/*/db-types.d.ts; do - if [ -f "$file" ]; then - echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY - fi - done + echo "- \`shared/dtos/db-types.d.ts\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Next Steps:** The changes have been automatically committed to this PR. Review the updated types and merge when ready." >> $GITHUB_STEP_SUMMARY diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 74e8987e..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "shared"] - path = shared - url = https://github.com/Code-4-Community/shared.git diff --git a/apps/backend/lambdas/auth/db-types.d.ts b/apps/backend/lambdas/auth/db-types.d.ts deleted file mode 100644 index 5ca734e3..00000000 --- a/apps/backend/lambdas/auth/db-types.d.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * This file was generated by kysely-codegen. - * Please do not edit it manually. - */ - -import type { ColumnType } from "kysely"; - -export type Generated = T extends ColumnType - ? ColumnType - : ColumnType; - -export type Numeric = ColumnType; - -export type Timestamp = ColumnType; - -export interface BranchDonors { - contact_email: string | null; - contact_name: string | null; - created_at: Generated; - donor_id: Generated; - organization: string; -} - -export interface BranchExpenditures { - amount: Numeric; - category: string | null; - created_at: Generated; - description: string | null; - entered_by: number | null; - expenditure_id: Generated; - project_id: number; - spent_on: Generated; -} - -export interface BranchProjectDonations { - amount: Numeric; - donated_at: Generated; - donation_id: Generated; - donor_id: number; - project_id: number; -} - -export interface BranchProjectMemberships { - hours: Numeric | null; - membership_id: Generated; - project_id: number; - role: string; - start_date: Timestamp | null; - user_id: number; -} - -export interface BranchProjects { - created_at: Generated; - currency: Generated; - end_date: Timestamp | null; - description: string; - name: string; - project_id: Generated; - start_date: Timestamp | null; - total_budget: Numeric | null; -} - -export interface BranchUsers { - cognito_sub: string | null; - created_at: Generated; - email: string; - is_admin: Generated; - name: string; - user_id: Generated; -} - -export interface DB { - "branch.donors": BranchDonors; - "branch.expenditures": BranchExpenditures; - "branch.project_donations": BranchProjectDonations; - "branch.project_memberships": BranchProjectMemberships; - "branch.projects": BranchProjects; - "branch.users": BranchUsers; -} diff --git a/apps/backend/lambdas/auth/db.ts b/apps/backend/lambdas/auth/db.ts index 0e8d5a80..42860745 100644 --- a/apps/backend/lambdas/auth/db.ts +++ b/apps/backend/lambdas/auth/db.ts @@ -1,7 +1,7 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from './db-types' +import type { DB } from '@branch/dtos' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/auth/package-lock.json b/apps/backend/lambdas/auth/package-lock.json index a117d8cb..5fcf8709 100644 --- a/apps/backend/lambdas/auth/package-lock.json +++ b/apps/backend/lambdas/auth/package-lock.json @@ -16,6 +16,7 @@ "pg": "^8.17.2" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", @@ -28,6 +29,11 @@ "typescript": "^5.4.5" } }, + "../../../../shared/dtos": { + "name": "@branch/dtos", + "version": "1.0.0", + "dev": true + }, "node_modules/@aws-crypto/sha256-browser": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", @@ -1163,11 +1169,15 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, + "node_modules/@branch/dtos": { + "resolved": "../../../../shared/dtos", + "link": true + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -1180,7 +1190,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -2354,28 +2364,28 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -2773,7 +2783,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2786,7 +2796,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -3402,7 +3412,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -3482,7 +3492,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -5048,7 +5058,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { @@ -6202,7 +6212,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -6246,7 +6256,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/tslib": { @@ -6280,7 +6290,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -6384,7 +6394,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -6671,7 +6681,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/apps/backend/lambdas/auth/package.json b/apps/backend/lambdas/auth/package.json index 06572f60..23115894 100644 --- a/apps/backend/lambdas/auth/package.json +++ b/apps/backend/lambdas/auth/package.json @@ -10,6 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", diff --git a/apps/backend/lambdas/donors/auth.ts b/apps/backend/lambdas/donors/auth.ts index 6b70cf46..295cbd72 100644 --- a/apps/backend/lambdas/donors/auth.ts +++ b/apps/backend/lambdas/donors/auth.ts @@ -1,6 +1,9 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; +import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; import db from './db'; +export type { AuthenticatedUser, AuthContext }; + const COGNITO_USER_POOL_ID = process.env.COGNITO_USER_POOL_ID!; const COGNITO_CLIENT_ID = process.env.COGNITO_APP_CLIENT_ID!; @@ -21,19 +24,6 @@ function getVerifier() { return verifier; } -export interface AuthenticatedUser { - cognitoSub: string; - userId?: number; - email: string; - isAdmin?: boolean; - cognitoGroups?: string[]; -} - -export interface AuthContext { - user?: AuthenticatedUser; - isAuthenticated: boolean; -} - /** * Encode a JWT token */ diff --git a/apps/backend/lambdas/donors/db-types.d.ts b/apps/backend/lambdas/donors/db-types.d.ts deleted file mode 100644 index 5ca734e3..00000000 --- a/apps/backend/lambdas/donors/db-types.d.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * This file was generated by kysely-codegen. - * Please do not edit it manually. - */ - -import type { ColumnType } from "kysely"; - -export type Generated = T extends ColumnType - ? ColumnType - : ColumnType; - -export type Numeric = ColumnType; - -export type Timestamp = ColumnType; - -export interface BranchDonors { - contact_email: string | null; - contact_name: string | null; - created_at: Generated; - donor_id: Generated; - organization: string; -} - -export interface BranchExpenditures { - amount: Numeric; - category: string | null; - created_at: Generated; - description: string | null; - entered_by: number | null; - expenditure_id: Generated; - project_id: number; - spent_on: Generated; -} - -export interface BranchProjectDonations { - amount: Numeric; - donated_at: Generated; - donation_id: Generated; - donor_id: number; - project_id: number; -} - -export interface BranchProjectMemberships { - hours: Numeric | null; - membership_id: Generated; - project_id: number; - role: string; - start_date: Timestamp | null; - user_id: number; -} - -export interface BranchProjects { - created_at: Generated; - currency: Generated; - end_date: Timestamp | null; - description: string; - name: string; - project_id: Generated; - start_date: Timestamp | null; - total_budget: Numeric | null; -} - -export interface BranchUsers { - cognito_sub: string | null; - created_at: Generated; - email: string; - is_admin: Generated; - name: string; - user_id: Generated; -} - -export interface DB { - "branch.donors": BranchDonors; - "branch.expenditures": BranchExpenditures; - "branch.project_donations": BranchProjectDonations; - "branch.project_memberships": BranchProjectMemberships; - "branch.projects": BranchProjects; - "branch.users": BranchUsers; -} diff --git a/apps/backend/lambdas/donors/db.ts b/apps/backend/lambdas/donors/db.ts index 57202d48..36750d1c 100644 --- a/apps/backend/lambdas/donors/db.ts +++ b/apps/backend/lambdas/donors/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from './db-types' +import type { DB } from '@branch/dtos' const db = new Kysely({ diff --git a/apps/backend/lambdas/donors/package-lock.json b/apps/backend/lambdas/donors/package-lock.json index a254a95a..e9623a92 100644 --- a/apps/backend/lambdas/donors/package-lock.json +++ b/apps/backend/lambdas/donors/package-lock.json @@ -14,6 +14,7 @@ "pg": "^8.17.2" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", @@ -24,6 +25,11 @@ "typescript": "^5.4.5" } }, + "../../../../shared/dtos": { + "name": "@branch/dtos", + "version": "1.0.0", + "dev": true + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -485,11 +491,15 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, + "node_modules/@branch/dtos": { + "resolved": "../../../../shared/dtos", + "link": true + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -502,7 +512,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1035,28 +1045,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -1454,7 +1464,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1467,7 +1477,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -1535,7 +1545,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -1951,7 +1961,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -2021,7 +2031,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -3237,7 +3247,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { @@ -4213,7 +4223,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -4285,7 +4295,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -4383,7 +4393,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -4634,7 +4644,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/apps/backend/lambdas/donors/package.json b/apps/backend/lambdas/donors/package.json index 5bc32066..06fdd191 100644 --- a/apps/backend/lambdas/donors/package.json +++ b/apps/backend/lambdas/donors/package.json @@ -10,6 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", diff --git a/apps/backend/lambdas/expenditures/auth.ts b/apps/backend/lambdas/expenditures/auth.ts index 5d64d0dd..74240efb 100644 --- a/apps/backend/lambdas/expenditures/auth.ts +++ b/apps/backend/lambdas/expenditures/auth.ts @@ -1,6 +1,9 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; +import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; import db from './db'; +export type { AuthenticatedUser, AuthContext }; + // Load from environment variables const COGNITO_USER_POOL_ID = process.env.COGNITO_USER_POOL_ID || ''; const COGNITO_CLIENT_ID = process.env.COGNITO_CLIENT_ID || ''; @@ -22,19 +25,6 @@ function getVerifier() { return verifier; } -export interface AuthenticatedUser { - cognitoSub: string; - userId?: number; - email?: string; - isAdmin: boolean; - cognitoGroups?: string[]; -} - -export interface AuthContext { - user?: AuthenticatedUser; - isAuthenticated: boolean; -} - /** * Extract JWT token from Authorization header */ diff --git a/apps/backend/lambdas/expenditures/db-types.d.ts b/apps/backend/lambdas/expenditures/db-types.d.ts deleted file mode 100644 index 18fcb702..00000000 --- a/apps/backend/lambdas/expenditures/db-types.d.ts +++ /dev/null @@ -1,81 +0,0 @@ -/** - * This file was generated by kysely-codegen. - * Please do not edit it manually. - */ - -import type { ColumnType } from "kysely"; - -export type Generated = T extends ColumnType - ? ColumnType - : ColumnType; - -export type Numeric = ColumnType; - -export type Timestamp = ColumnType; - -export interface BranchDonors { - contact_email: string | null; - contact_name: string | null; - created_at: Generated; - donor_id: Generated; - organization: string; -} - -export interface BranchExpenditures { - amount: Numeric; - category: string | null; - created_at: Generated; - description: string | null; - entered_by: number | null; - expenditure_id: Generated; - project_id: number; - receipt_url: string | null; - spent_on: Generated; - status: Generated; -} - -export interface BranchProjectDonations { - amount: Numeric; - donated_at: Generated; - donation_id: Generated; - donor_id: number; - project_id: number; -} - -export interface BranchProjectMemberships { - hours: Numeric | null; - membership_id: Generated; - project_id: number; - role: string; - start_date: Timestamp | null; - user_id: number; -} - -export interface BranchProjects { - created_at: Generated; - currency: Generated; - end_date: Timestamp | null; - description: string; - name: string; - project_id: Generated; - start_date: Timestamp | null; - total_budget: Numeric | null; -} - -export interface BranchUsers { - cognito_sub: string | null; - created_at: Generated; - email: string; - is_admin: Generated; - name: string; - user_id: Generated; -} - -export interface DB { - "branch.donors": BranchDonors; - "branch.expenditures": BranchExpenditures; - "branch.project_donations": BranchProjectDonations; - "branch.project_memberships": BranchProjectMemberships; - "branch.projects": BranchProjects; - "branch.users": BranchUsers; -} diff --git a/apps/backend/lambdas/expenditures/db.ts b/apps/backend/lambdas/expenditures/db.ts index 38f9b85a..7b3cb6df 100644 --- a/apps/backend/lambdas/expenditures/db.ts +++ b/apps/backend/lambdas/expenditures/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from './db-types' +import type { DB } from '@branch/dtos' const db = new Kysely({ diff --git a/apps/backend/lambdas/expenditures/package-lock.json b/apps/backend/lambdas/expenditures/package-lock.json index fadb02af..4b551cf7 100644 --- a/apps/backend/lambdas/expenditures/package-lock.json +++ b/apps/backend/lambdas/expenditures/package-lock.json @@ -15,6 +15,7 @@ "pg": "^8.16.3" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", @@ -27,6 +28,11 @@ "typescript": "^5.4.5" } }, + "../../../../shared/dtos": { + "name": "@branch/dtos", + "version": "1.0.0", + "dev": true + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -488,6 +494,10 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, + "node_modules/@branch/dtos": { + "resolved": "../../../../shared/dtos", + "link": true + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", diff --git a/apps/backend/lambdas/expenditures/package.json b/apps/backend/lambdas/expenditures/package.json index 0ac91c62..382bb0c9 100644 --- a/apps/backend/lambdas/expenditures/package.json +++ b/apps/backend/lambdas/expenditures/package.json @@ -11,6 +11,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", diff --git a/apps/backend/lambdas/projects/auth.ts b/apps/backend/lambdas/projects/auth.ts index d1b8d662..9564c969 100644 --- a/apps/backend/lambdas/projects/auth.ts +++ b/apps/backend/lambdas/projects/auth.ts @@ -1,6 +1,9 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; +import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; import db from './db'; +export type { AuthenticatedUser, AuthContext }; + const COGNITO_USER_POOL_ID = process.env.COGNITO_USER_POOL_ID!; const COGNITO_CLIENT_ID = process.env.COGNITO_APP_CLIENT_ID!; @@ -21,19 +24,6 @@ function getVerifier() { return verifier; } -export interface AuthenticatedUser { - cognitoSub: string; - userId?: number; - email: string; - isAdmin?: boolean; - cognitoGroups?: string[]; -} - -export interface AuthContext { - user?: AuthenticatedUser; - isAuthenticated: boolean; -} - /** * Encode a JWT token (for testing purposes) * Creates a mock JWT with the standard three-part format diff --git a/apps/backend/lambdas/projects/db-types.d.ts b/apps/backend/lambdas/projects/db-types.d.ts deleted file mode 100644 index a44eaf8f..00000000 --- a/apps/backend/lambdas/projects/db-types.d.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * This file was generated by kysely-codegen. - * Please do not edit it manually. - */ - -import type { ColumnType } from "kysely"; - -export type Generated = T extends ColumnType - ? ColumnType - : ColumnType; - -export type Numeric = ColumnType; - -export type Timestamp = ColumnType; - -export interface BranchDonors { - contact_email: string | null; - contact_name: string | null; - created_at: Generated; - donor_id: Generated; - organization: string; -} - -export interface BranchExpenditures { - amount: Numeric; - category: string | null; - created_at: Generated; - description: string | null; - entered_by: number | null; - expenditure_id: Generated; - project_id: number; - spent_on: Generated; -} - -export interface BranchProjectDonations { - amount: Numeric; - donated_at: Generated; - donation_id: Generated; - donor_id: number; - project_id: number; -} - -export interface BranchProjectMemberships { - hours: Numeric | null; - membership_id: Generated; - project_id: number; - role: string; - start_date: Timestamp | null; - user_id: number; -} - -export interface BranchProjects { - created_at: Generated; - currency: Generated; - end_date: Timestamp | null; - description: string; - name: string; - project_id: Generated; - start_date: Timestamp | null; - total_budget: Numeric | null; -} - -export interface BranchUsers { - created_at: Generated; - email: string; - is_admin: Generated; - name: string; - user_id: Generated; -} - -export interface DB { - "branch.donors": BranchDonors; - "branch.expenditures": BranchExpenditures; - "branch.project_donations": BranchProjectDonations; - "branch.project_memberships": BranchProjectMemberships; - "branch.projects": BranchProjects; - "branch.users": BranchUsers; -} diff --git a/apps/backend/lambdas/projects/db.ts b/apps/backend/lambdas/projects/db.ts index 73ffb54e..ba73b760 100644 --- a/apps/backend/lambdas/projects/db.ts +++ b/apps/backend/lambdas/projects/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from './db-types' +import type { DB } from '@branch/dtos' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/projects/package-lock.json b/apps/backend/lambdas/projects/package-lock.json index 2b4b6bca..11dd7341 100644 --- a/apps/backend/lambdas/projects/package-lock.json +++ b/apps/backend/lambdas/projects/package-lock.json @@ -14,6 +14,7 @@ "pg": "^8.16.3" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", @@ -25,6 +26,11 @@ "typescript": "^5.4.5" } }, + "../../../../shared/dtos": { + "name": "@branch/dtos", + "version": "1.0.0", + "dev": true + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -496,11 +502,15 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, + "node_modules/@branch/dtos": { + "resolved": "../../../../shared/dtos", + "link": true + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -1071,7 +1081,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1147,28 +1157,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -1566,7 +1576,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1579,7 +1589,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -1647,7 +1657,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -2126,7 +2136,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -2206,7 +2216,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -3704,7 +3714,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { @@ -4827,7 +4837,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -4899,7 +4909,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -4997,7 +5007,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -5278,7 +5288,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/apps/backend/lambdas/projects/package.json b/apps/backend/lambdas/projects/package.json index 5c9c92d7..138c8679 100644 --- a/apps/backend/lambdas/projects/package.json +++ b/apps/backend/lambdas/projects/package.json @@ -10,6 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", diff --git a/apps/backend/lambdas/reports/auth.ts b/apps/backend/lambdas/reports/auth.ts index 69cfd57c..0de856a2 100644 --- a/apps/backend/lambdas/reports/auth.ts +++ b/apps/backend/lambdas/reports/auth.ts @@ -1,6 +1,9 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; +import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; import db from './db'; +export type { AuthenticatedUser, AuthContext }; + const COGNITO_USER_POOL_ID = process.env.COGNITO_USER_POOL_ID || ''; const COGNITO_CLIENT_ID = process.env.COGNITO_CLIENT_ID || ''; @@ -20,19 +23,6 @@ function getVerifier() { return verifier; } -export interface AuthenticatedUser { - cognitoSub: string; - userId?: number; - email?: string; - isAdmin: boolean; - cognitoGroups?: string[]; -} - -export interface AuthContext { - user?: AuthenticatedUser; - isAuthenticated: boolean; -} - function extractToken(event: any): string | null { const authHeader = event.headers?.Authorization || event.headers?.authorization; diff --git a/apps/backend/lambdas/reports/db.ts b/apps/backend/lambdas/reports/db.ts index 43a33d19..4f1628ff 100644 --- a/apps/backend/lambdas/reports/db.ts +++ b/apps/backend/lambdas/reports/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from './db-types' +import type { DB } from '@branch/dtos' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/reports/handler.ts b/apps/backend/lambdas/reports/handler.ts index 3e603d6c..2e8a8112 100644 --- a/apps/backend/lambdas/reports/handler.ts +++ b/apps/backend/lambdas/reports/handler.ts @@ -54,7 +54,7 @@ export const handler = async (event: any): Promise => { return json(404, { message: 'Project not found' }); } - const hasAccess = await checkProjectAccess(user.userId!, projectId, user.isAdmin); + const hasAccess = await checkProjectAccess(user.userId!, projectId, user.isAdmin ?? false); if (!hasAccess) { return json(403, { message: 'You do not have access to generate reports for this project' }); } diff --git a/apps/backend/lambdas/reports/package-lock.json b/apps/backend/lambdas/reports/package-lock.json index 134a4d2a..4296e031 100644 --- a/apps/backend/lambdas/reports/package-lock.json +++ b/apps/backend/lambdas/reports/package-lock.json @@ -19,6 +19,7 @@ "pg": "^8.18.0" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", @@ -32,6 +33,11 @@ "typescript": "^5.4.5" } }, + "../../../../shared/dtos": { + "name": "@branch/dtos", + "version": "1.0.0", + "dev": true + }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", @@ -1344,11 +1350,15 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, + "node_modules/@branch/dtos": { + "resolved": "../../../../shared/dtos", + "link": true + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -1361,7 +1371,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -2707,28 +2717,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -3147,7 +3157,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3160,7 +3170,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -3228,7 +3238,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -3881,7 +3891,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -3984,7 +3994,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -5775,7 +5785,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { @@ -7098,7 +7108,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -7169,7 +7179,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7324,7 +7334,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -7696,7 +7706,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/apps/backend/lambdas/reports/package.json b/apps/backend/lambdas/reports/package.json index 104252d4..0e6fc738 100644 --- a/apps/backend/lambdas/reports/package.json +++ b/apps/backend/lambdas/reports/package.json @@ -11,6 +11,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", diff --git a/apps/backend/lambdas/tools/README.md b/apps/backend/lambdas/tools/README.md index fd0ccb05..0acd1c92 100644 --- a/apps/backend/lambdas/tools/README.md +++ b/apps/backend/lambdas/tools/README.md @@ -26,7 +26,7 @@ node tools/lambda-cli.js init-handler users This creates a new handler directory with: - `handler.ts` - Main Lambda function -- `package.json` - Dependencies and scripts +- `package.json` - Dependencies and scripts (includes the shared `@branch/dtos` types package from `shared/dtos`) - `tsconfig.json` - TypeScript configuration - `openapi.yaml` - Swagger/OpenAPI specification - `swagger-utils.ts` - Swagger utilities (dev only) diff --git a/apps/backend/lambdas/tools/lambda-cli.js b/apps/backend/lambdas/tools/lambda-cli.js index 5e7d2347..d6cfd823 100644 --- a/apps/backend/lambdas/tools/lambda-cli.js +++ b/apps/backend/lambdas/tools/lambda-cli.js @@ -48,6 +48,7 @@ function templatePackageJson() { "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@types/aws-lambda": "^8.10.131", "@types/node": "^20.11.30", "ts-node": "^10.9.2", diff --git a/apps/backend/lambdas/users/auth.ts b/apps/backend/lambdas/users/auth.ts index 0fd2e84d..2f22ed76 100644 --- a/apps/backend/lambdas/users/auth.ts +++ b/apps/backend/lambdas/users/auth.ts @@ -1,7 +1,15 @@ import { APIGatewayProxyEvent } from 'aws-lambda'; import { CognitoJwtVerifier } from 'aws-jwt-verify'; +import type { + AuthenticatedUser, + AuthContext, + AccessLevel, + AuthorizationCheck, +} from '@branch/dtos'; import db from './db'; +export type { AuthenticatedUser, AuthContext, AccessLevel, AuthorizationCheck }; + // Load from environment variables const COGNITO_USER_POOL_ID = process.env.COGNITO_USER_POOL_ID || ''; const COGNITO_REGION = process.env.AWS_REGION || 'us-east-2'; @@ -24,19 +32,6 @@ function getVerifier() { return verifier; } -export interface AuthenticatedUser { - cognitoSub: string; - userId?: number; - email?: string; - isAdmin: boolean; - cognitoGroups?: string[]; -} - -export interface AuthContext { - user?: AuthenticatedUser; - isAuthenticated: boolean; -} - /** * Extract JWT token from Authorization header */ @@ -101,16 +96,6 @@ export async function authenticateRequest(event: any): Promise { } } -/** - * Authorization helpers for different access levels - */ -export type AccessLevel = 'PUBLIC' | 'AUTHENTICATED' | 'ADMIN' | 'SELF' | 'ADMIN_OR_SELF'; - -export interface AuthorizationCheck { - allowed: boolean; - reason?: string; -} - /** * Check if user is authorized for a given access level * @param authContext - The authentication context diff --git a/apps/backend/lambdas/users/db-types.d.ts b/apps/backend/lambdas/users/db-types.d.ts deleted file mode 100644 index f08f3c38..00000000 --- a/apps/backend/lambdas/users/db-types.d.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * This file was generated by kysely-codegen. - * Please do not edit it manually. - */ - -import type { ColumnType } from "kysely"; - -export type Generated = T extends ColumnType - ? ColumnType - : ColumnType; - -export type Numeric = ColumnType; - -export type Timestamp = ColumnType; - -export interface BranchDonors { - contact_email: string | null; - contact_name: string | null; - created_at: Generated; - donor_id: Generated; - organization: string; -} - -export interface BranchExpenditures { - amount: Numeric; - category: string | null; - created_at: Generated; - description: string | null; - entered_by: number | null; - expenditure_id: Generated; - project_id: number; - spent_on: Generated; -} - -export interface BranchProjectDonations { - amount: Numeric; - donated_at: Generated; - donation_id: Generated; - donor_id: number; - project_id: number; -} - -export interface BranchProjectMemberships { - hours: Numeric | null; - membership_id: Generated; - project_id: number; - role: string; - start_date: Timestamp | null; - user_id: number; -} - -export interface BranchProjects { - created_at: Generated; - currency: Generated; - end_date: Timestamp | null; - description: string; - name: string; - project_id: Generated; - start_date: Timestamp | null; - total_budget: Numeric | null; -} - -export interface BranchUsers { - cognito_sub: string | null; - created_at: Generated; - email: string; - is_admin: Generated; - name: string; - user_id: Generated; - profile_image: string | null; -} - -export interface DB { - "branch.donors": BranchDonors; - "branch.expenditures": BranchExpenditures; - "branch.project_donations": BranchProjectDonations; - "branch.project_memberships": BranchProjectMemberships; - "branch.projects": BranchProjects; - "branch.users": BranchUsers; -} diff --git a/apps/backend/lambdas/users/db.ts b/apps/backend/lambdas/users/db.ts index 0e8d5a80..42860745 100644 --- a/apps/backend/lambdas/users/db.ts +++ b/apps/backend/lambdas/users/db.ts @@ -1,7 +1,7 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from './db-types' +import type { DB } from '@branch/dtos' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/users/package-lock.json b/apps/backend/lambdas/users/package-lock.json index a5ed3360..c3285202 100644 --- a/apps/backend/lambdas/users/package-lock.json +++ b/apps/backend/lambdas/users/package-lock.json @@ -14,6 +14,7 @@ "pg": "^8.16.3" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", @@ -25,6 +26,11 @@ "typescript": "^5.4.5" } }, + "../../../../shared/dtos": { + "name": "@branch/dtos", + "version": "1.0.0", + "dev": true + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -486,11 +492,15 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, + "node_modules/@branch/dtos": { + "resolved": "../../../../shared/dtos", + "link": true + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -503,7 +513,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1097,28 +1107,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -1516,7 +1526,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1529,7 +1539,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -1597,7 +1607,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -2076,7 +2086,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -2156,7 +2166,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3656,7 +3666,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { @@ -4773,7 +4783,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -4845,7 +4855,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -4943,7 +4953,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -5226,7 +5236,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/apps/backend/lambdas/users/package.json b/apps/backend/lambdas/users/package.json index 7bf6fe23..1f316ba8 100644 --- a/apps/backend/lambdas/users/package.json +++ b/apps/backend/lambdas/users/package.json @@ -10,6 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", diff --git a/shared b/shared deleted file mode 160000 index c311d649..00000000 --- a/shared +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c311d649544727cd5f196644751fa45320eda80a diff --git a/shared/dtos/README.md b/shared/dtos/README.md new file mode 100644 index 00000000..0a5e7b3a --- /dev/null +++ b/shared/dtos/README.md @@ -0,0 +1,39 @@ +# @branch/dtos + +Shared DTO type definitions for the Branch lambdas. This replaces the per-lambda copies of `db-types.d.ts` and the duplicated auth interfaces (`AuthenticatedUser`, `AuthContext`, etc.). + +## What's in here + +| File | Contents | +|------|----------| +| `db-types.d.ts` | Kysely row types generated from `apps/backend/db/db_setup.sql` (`DB`, `BranchUsers`, `BranchProjects`, ...) | +| `auth-types.d.ts` | Auth DTOs (`AuthenticatedUser`, `AuthContext`, `AccessLevel`, `AuthorizationCheck`) | + +## How it works + +The package is **types-only** — it contains no runtime code and has no dependencies. Each lambda references it via a `file:` dependency in its `package.json`: + +```json +"devDependencies": { + "@branch/dtos": "file:../../../../shared/dtos" +} +``` + +Because the package only ships `.d.ts` files, all imports are erased at compile time. The deployed `lambda.zip` (built from `dist/`) is unaffected, so lambdas remain fully self contained. + +## Usage + +```ts +import type { DB } from '@branch/dtos'; +import type { AuthContext, AuthenticatedUser } from '@branch/dtos'; +``` + +Note: `db-types.d.ts` defines a local `ColumnType` that is structurally identical to kysely's, so the package itself does not depend on kysely. + +## Regenerating DB types + +`db-types.d.ts` is regenerated automatically by the `regenerate-db-types` GitHub workflow whenever `apps/backend/db/db_setup.sql` changes. Do not edit it manually. + +## New lambdas + +`tools/lambda-cli.js init-handler ` adds this package to new lambdas automatically. diff --git a/shared/dtos/auth-types.d.ts b/shared/dtos/auth-types.d.ts new file mode 100644 index 00000000..eccc244e --- /dev/null +++ b/shared/dtos/auth-types.d.ts @@ -0,0 +1,23 @@ +/** + * Shared auth DTOs used by every lambda's auth.ts. + */ + +export interface AuthenticatedUser { + cognitoSub: string; + userId?: number; + email?: string; + isAdmin?: boolean; + cognitoGroups?: string[]; +} + +export interface AuthContext { + user?: AuthenticatedUser; + isAuthenticated: boolean; +} + +export type AccessLevel = 'PUBLIC' | 'AUTHENTICATED' | 'ADMIN' | 'SELF' | 'ADMIN_OR_SELF'; + +export interface AuthorizationCheck { + allowed: boolean; + reason?: string; +} diff --git a/apps/backend/lambdas/reports/db-types.d.ts b/shared/dtos/db-types.d.ts similarity index 83% rename from apps/backend/lambdas/reports/db-types.d.ts rename to shared/dtos/db-types.d.ts index f5ce7754..fea62bf6 100644 --- a/apps/backend/lambdas/reports/db-types.d.ts +++ b/shared/dtos/db-types.d.ts @@ -3,7 +3,15 @@ * Please do not edit it manually. */ -import type { ColumnType } from "kysely"; +/** + * Structurally identical to kysely's ColumnType, defined locally so this + * package has no dependencies and lambdas stay fully self contained. + */ +type ColumnType = { + readonly __select__: SelectType; + readonly __insert__: InsertType; + readonly __update__: UpdateType; +}; export type Generated = T extends ColumnType ? ColumnType @@ -29,7 +37,9 @@ export interface BranchExpenditures { entered_by: number | null; expenditure_id: Generated; project_id: number; + receipt_url: string | null; spent_on: Generated; + status: Generated; } export interface BranchProjectDonations { @@ -73,6 +83,7 @@ export interface BranchUsers { email: string; is_admin: Generated; name: string; + profile_image: string | null; user_id: Generated; } diff --git a/shared/dtos/index.d.ts b/shared/dtos/index.d.ts new file mode 100644 index 00000000..f988d9c8 --- /dev/null +++ b/shared/dtos/index.d.ts @@ -0,0 +1,2 @@ +export * from './db-types'; +export * from './auth-types'; diff --git a/shared/dtos/package.json b/shared/dtos/package.json new file mode 100644 index 00000000..5041a308 --- /dev/null +++ b/shared/dtos/package.json @@ -0,0 +1,10 @@ +{ + "name": "@branch/dtos", + "version": "1.0.0", + "private": true, + "description": "Shared DTO type definitions for Branch lambdas", + "types": "index.d.ts", + "files": [ + "*.d.ts" + ] +} From 1b2c5104349a6b51fba8401d924e1d7d993d6292 Mon Sep 17 00:00:00 2001 From: nourshoreibah Date: Tue, 9 Jun 2026 20:27:40 -0400 Subject: [PATCH 2/3] Rename @branch/dtos to @branch/types The package mostly contains kysely DB row types (closer to ORM models than DTOs), so name it for what it holds: shared/types exporting @branch/types. Co-authored-by: Cursor --- .github/workflows/lambda-deploy.yml | 2 +- .github/workflows/regenerate-db-types.yaml | 22 +++++++++---------- apps/backend/lambdas/auth/db.ts | 2 +- apps/backend/lambdas/auth/package-lock.json | 10 ++++----- apps/backend/lambdas/auth/package.json | 2 +- apps/backend/lambdas/donors/auth.ts | 2 +- apps/backend/lambdas/donors/db.ts | 2 +- apps/backend/lambdas/donors/package-lock.json | 10 ++++----- apps/backend/lambdas/donors/package.json | 2 +- apps/backend/lambdas/expenditures/auth.ts | 2 +- apps/backend/lambdas/expenditures/db.ts | 2 +- .../lambdas/expenditures/package-lock.json | 10 ++++----- .../backend/lambdas/expenditures/package.json | 2 +- apps/backend/lambdas/projects/auth.ts | 2 +- apps/backend/lambdas/projects/db.ts | 2 +- .../lambdas/projects/package-lock.json | 10 ++++----- apps/backend/lambdas/projects/package.json | 2 +- apps/backend/lambdas/reports/auth.ts | 2 +- apps/backend/lambdas/reports/db.ts | 2 +- .../backend/lambdas/reports/package-lock.json | 10 ++++----- apps/backend/lambdas/reports/package.json | 2 +- apps/backend/lambdas/tools/README.md | 2 +- apps/backend/lambdas/tools/lambda-cli.js | 2 +- apps/backend/lambdas/users/auth.ts | 2 +- apps/backend/lambdas/users/db.ts | 2 +- apps/backend/lambdas/users/package-lock.json | 10 ++++----- apps/backend/lambdas/users/package.json | 2 +- shared/dtos/package.json | 10 --------- shared/{dtos => types}/README.md | 10 ++++----- shared/{dtos => types}/auth-types.d.ts | 0 shared/{dtos => types}/db-types.d.ts | 0 shared/{dtos => types}/index.d.ts | 0 shared/types/package.json | 10 +++++++++ 33 files changed, 76 insertions(+), 76 deletions(-) delete mode 100644 shared/dtos/package.json rename shared/{dtos => types}/README.md (76%) rename shared/{dtos => types}/auth-types.d.ts (100%) rename shared/{dtos => types}/db-types.d.ts (100%) rename shared/{dtos => types}/index.d.ts (100%) create mode 100644 shared/types/package.json diff --git a/.github/workflows/lambda-deploy.yml b/.github/workflows/lambda-deploy.yml index 88de626e..e0dab286 100644 --- a/.github/workflows/lambda-deploy.yml +++ b/.github/workflows/lambda-deploy.yml @@ -5,7 +5,7 @@ on: branches: [main] paths: - 'apps/backend/lambdas/**' - - 'shared/dtos/**' + - 'shared/types/**' jobs: detect-changes: diff --git a/.github/workflows/regenerate-db-types.yaml b/.github/workflows/regenerate-db-types.yaml index ace29a4c..6e9840b1 100644 --- a/.github/workflows/regenerate-db-types.yaml +++ b/.github/workflows/regenerate-db-types.yaml @@ -112,10 +112,10 @@ jobs: - name: Copy generated types to shared DTOs package run: | - echo "Copying generated types to shared/dtos" + echo "Copying generated types to shared/types" SOURCE_FILE="apps/backend/db/db-types.d.ts" - TARGET_FILE="shared/dtos/db-types.d.ts" + TARGET_FILE="shared/types/db-types.d.ts" # verify the source file exists and is not empty if [ ! -s "$SOURCE_FILE" ]; then @@ -162,8 +162,8 @@ jobs: echo "Performing basic syntax check on generated types..." # Ensure the file is valid TypeScript - npx tsc --noEmit --skipLibCheck shared/dtos/db-types.d.ts || { - echo "Error: shared/dtos/db-types.d.ts contains TypeScript errors" + npx tsc --noEmit --skipLibCheck shared/types/db-types.d.ts || { + echo "Error: shared/types/db-types.d.ts contains TypeScript errors" exit 1 } else @@ -179,9 +179,9 @@ jobs: - name: Check for changes id: git-check run: | - git add -N shared/dtos/db-types.d.ts + git add -N shared/types/db-types.d.ts - if git diff --exit-code shared/dtos/db-types.d.ts; then + if git diff --exit-code shared/types/db-types.d.ts; then echo "changes=false" >> $GITHUB_OUTPUT echo "No changes detected in generated types" else @@ -189,7 +189,7 @@ jobs: echo "Changes detected in generated types" echo "Changed files:" - git diff --name-only shared/dtos/db-types.d.ts + git diff --name-only shared/types/db-types.d.ts fi - name: Get PR author information @@ -219,7 +219,7 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add shared/dtos/db-types.d.ts + git add shared/types/db-types.d.ts COMMIT_MESSAGE="chore: auto-regenerate database types from schema changes" @@ -244,9 +244,9 @@ jobs: The database schema has changed and the shared TypeScript definitions were regenerated: - - \`shared/dtos/db-types.d.ts\` + - \`shared/types/db-types.d.ts\` - All lambdas consume these types through the \`@branch/dtos\` package, so they are now in sync with the schema changes.`; + All lambdas consume these types through the \`@branch/types\` package, so they are now in sync with the schema changes.`; github.rest.issues.createComment({ issue_number: context.issue.number, @@ -284,7 +284,7 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "The following files were updated and committed:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "- \`shared/dtos/db-types.d.ts\`" >> $GITHUB_STEP_SUMMARY + echo "- \`shared/types/db-types.d.ts\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Next Steps:** The changes have been automatically committed to this PR. Review the updated types and merge when ready." >> $GITHUB_STEP_SUMMARY diff --git a/apps/backend/lambdas/auth/db.ts b/apps/backend/lambdas/auth/db.ts index 42860745..a7a0a232 100644 --- a/apps/backend/lambdas/auth/db.ts +++ b/apps/backend/lambdas/auth/db.ts @@ -1,7 +1,7 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from '@branch/dtos' +import type { DB } from '@branch/types' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/auth/package-lock.json b/apps/backend/lambdas/auth/package-lock.json index 5fcf8709..fd2fff88 100644 --- a/apps/backend/lambdas/auth/package-lock.json +++ b/apps/backend/lambdas/auth/package-lock.json @@ -16,7 +16,7 @@ "pg": "^8.17.2" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", @@ -29,8 +29,8 @@ "typescript": "^5.4.5" } }, - "../../../../shared/dtos": { - "name": "@branch/dtos", + "../../../../shared/types": { + "name": "@branch/types", "version": "1.0.0", "dev": true }, @@ -1169,8 +1169,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, - "node_modules/@branch/dtos": { - "resolved": "../../../../shared/dtos", + "node_modules/@branch/types": { + "resolved": "../../../../shared/types", "link": true }, "node_modules/@cspotcode/source-map-support": { diff --git a/apps/backend/lambdas/auth/package.json b/apps/backend/lambdas/auth/package.json index 23115894..ff26cd65 100644 --- a/apps/backend/lambdas/auth/package.json +++ b/apps/backend/lambdas/auth/package.json @@ -10,7 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", diff --git a/apps/backend/lambdas/donors/auth.ts b/apps/backend/lambdas/donors/auth.ts index 295cbd72..2bd29110 100644 --- a/apps/backend/lambdas/donors/auth.ts +++ b/apps/backend/lambdas/donors/auth.ts @@ -1,5 +1,5 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; -import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; +import type { AuthenticatedUser, AuthContext } from '@branch/types'; import db from './db'; export type { AuthenticatedUser, AuthContext }; diff --git a/apps/backend/lambdas/donors/db.ts b/apps/backend/lambdas/donors/db.ts index 36750d1c..9a64580e 100644 --- a/apps/backend/lambdas/donors/db.ts +++ b/apps/backend/lambdas/donors/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from '@branch/dtos' +import type { DB } from '@branch/types' const db = new Kysely({ diff --git a/apps/backend/lambdas/donors/package-lock.json b/apps/backend/lambdas/donors/package-lock.json index e9623a92..6b435862 100644 --- a/apps/backend/lambdas/donors/package-lock.json +++ b/apps/backend/lambdas/donors/package-lock.json @@ -14,7 +14,7 @@ "pg": "^8.17.2" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", @@ -25,8 +25,8 @@ "typescript": "^5.4.5" } }, - "../../../../shared/dtos": { - "name": "@branch/dtos", + "../../../../shared/types": { + "name": "@branch/types", "version": "1.0.0", "dev": true }, @@ -491,8 +491,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, - "node_modules/@branch/dtos": { - "resolved": "../../../../shared/dtos", + "node_modules/@branch/types": { + "resolved": "../../../../shared/types", "link": true }, "node_modules/@cspotcode/source-map-support": { diff --git a/apps/backend/lambdas/donors/package.json b/apps/backend/lambdas/donors/package.json index 06fdd191..23e8c3ad 100644 --- a/apps/backend/lambdas/donors/package.json +++ b/apps/backend/lambdas/donors/package.json @@ -10,7 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", diff --git a/apps/backend/lambdas/expenditures/auth.ts b/apps/backend/lambdas/expenditures/auth.ts index 74240efb..63bb9855 100644 --- a/apps/backend/lambdas/expenditures/auth.ts +++ b/apps/backend/lambdas/expenditures/auth.ts @@ -1,5 +1,5 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; -import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; +import type { AuthenticatedUser, AuthContext } from '@branch/types'; import db from './db'; export type { AuthenticatedUser, AuthContext }; diff --git a/apps/backend/lambdas/expenditures/db.ts b/apps/backend/lambdas/expenditures/db.ts index 7b3cb6df..adb4bd07 100644 --- a/apps/backend/lambdas/expenditures/db.ts +++ b/apps/backend/lambdas/expenditures/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from '@branch/dtos' +import type { DB } from '@branch/types' const db = new Kysely({ diff --git a/apps/backend/lambdas/expenditures/package-lock.json b/apps/backend/lambdas/expenditures/package-lock.json index 4b551cf7..e82a51bc 100644 --- a/apps/backend/lambdas/expenditures/package-lock.json +++ b/apps/backend/lambdas/expenditures/package-lock.json @@ -15,7 +15,7 @@ "pg": "^8.16.3" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", @@ -28,8 +28,8 @@ "typescript": "^5.4.5" } }, - "../../../../shared/dtos": { - "name": "@branch/dtos", + "../../../../shared/types": { + "name": "@branch/types", "version": "1.0.0", "dev": true }, @@ -494,8 +494,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, - "node_modules/@branch/dtos": { - "resolved": "../../../../shared/dtos", + "node_modules/@branch/types": { + "resolved": "../../../../shared/types", "link": true }, "node_modules/@cspotcode/source-map-support": { diff --git a/apps/backend/lambdas/expenditures/package.json b/apps/backend/lambdas/expenditures/package.json index 382bb0c9..9f89226f 100644 --- a/apps/backend/lambdas/expenditures/package.json +++ b/apps/backend/lambdas/expenditures/package.json @@ -11,7 +11,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", diff --git a/apps/backend/lambdas/projects/auth.ts b/apps/backend/lambdas/projects/auth.ts index 9564c969..ce0a5fb4 100644 --- a/apps/backend/lambdas/projects/auth.ts +++ b/apps/backend/lambdas/projects/auth.ts @@ -1,5 +1,5 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; -import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; +import type { AuthenticatedUser, AuthContext } from '@branch/types'; import db from './db'; export type { AuthenticatedUser, AuthContext }; diff --git a/apps/backend/lambdas/projects/db.ts b/apps/backend/lambdas/projects/db.ts index ba73b760..56067105 100644 --- a/apps/backend/lambdas/projects/db.ts +++ b/apps/backend/lambdas/projects/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from '@branch/dtos' +import type { DB } from '@branch/types' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/projects/package-lock.json b/apps/backend/lambdas/projects/package-lock.json index 11dd7341..514da2fe 100644 --- a/apps/backend/lambdas/projects/package-lock.json +++ b/apps/backend/lambdas/projects/package-lock.json @@ -14,7 +14,7 @@ "pg": "^8.16.3" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", @@ -26,8 +26,8 @@ "typescript": "^5.4.5" } }, - "../../../../shared/dtos": { - "name": "@branch/dtos", + "../../../../shared/types": { + "name": "@branch/types", "version": "1.0.0", "dev": true }, @@ -502,8 +502,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, - "node_modules/@branch/dtos": { - "resolved": "../../../../shared/dtos", + "node_modules/@branch/types": { + "resolved": "../../../../shared/types", "link": true }, "node_modules/@cspotcode/source-map-support": { diff --git a/apps/backend/lambdas/projects/package.json b/apps/backend/lambdas/projects/package.json index 138c8679..58d7072a 100644 --- a/apps/backend/lambdas/projects/package.json +++ b/apps/backend/lambdas/projects/package.json @@ -10,7 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", diff --git a/apps/backend/lambdas/reports/auth.ts b/apps/backend/lambdas/reports/auth.ts index 0de856a2..94b95822 100644 --- a/apps/backend/lambdas/reports/auth.ts +++ b/apps/backend/lambdas/reports/auth.ts @@ -1,5 +1,5 @@ import { CognitoJwtVerifier } from 'aws-jwt-verify'; -import type { AuthenticatedUser, AuthContext } from '@branch/dtos'; +import type { AuthenticatedUser, AuthContext } from '@branch/types'; import db from './db'; export type { AuthenticatedUser, AuthContext }; diff --git a/apps/backend/lambdas/reports/db.ts b/apps/backend/lambdas/reports/db.ts index 4f1628ff..544f5b59 100644 --- a/apps/backend/lambdas/reports/db.ts +++ b/apps/backend/lambdas/reports/db.ts @@ -1,6 +1,6 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from '@branch/dtos' +import type { DB } from '@branch/types' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/reports/package-lock.json b/apps/backend/lambdas/reports/package-lock.json index 4296e031..1f01b75b 100644 --- a/apps/backend/lambdas/reports/package-lock.json +++ b/apps/backend/lambdas/reports/package-lock.json @@ -19,7 +19,7 @@ "pg": "^8.18.0" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", @@ -33,8 +33,8 @@ "typescript": "^5.4.5" } }, - "../../../../shared/dtos": { - "name": "@branch/dtos", + "../../../../shared/types": { + "name": "@branch/types", "version": "1.0.0", "dev": true }, @@ -1350,8 +1350,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, - "node_modules/@branch/dtos": { - "resolved": "../../../../shared/dtos", + "node_modules/@branch/types": { + "resolved": "../../../../shared/types", "link": true }, "node_modules/@cspotcode/source-map-support": { diff --git a/apps/backend/lambdas/reports/package.json b/apps/backend/lambdas/reports/package.json index 0e6fc738..896ea770 100644 --- a/apps/backend/lambdas/reports/package.json +++ b/apps/backend/lambdas/reports/package.json @@ -11,7 +11,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@jest/globals": "^30.2.0", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", diff --git a/apps/backend/lambdas/tools/README.md b/apps/backend/lambdas/tools/README.md index 0acd1c92..4e3e32d9 100644 --- a/apps/backend/lambdas/tools/README.md +++ b/apps/backend/lambdas/tools/README.md @@ -26,7 +26,7 @@ node tools/lambda-cli.js init-handler users This creates a new handler directory with: - `handler.ts` - Main Lambda function -- `package.json` - Dependencies and scripts (includes the shared `@branch/dtos` types package from `shared/dtos`) +- `package.json` - Dependencies and scripts (includes the shared `@branch/types` package from `shared/types`) - `tsconfig.json` - TypeScript configuration - `openapi.yaml` - Swagger/OpenAPI specification - `swagger-utils.ts` - Swagger utilities (dev only) diff --git a/apps/backend/lambdas/tools/lambda-cli.js b/apps/backend/lambdas/tools/lambda-cli.js index d6cfd823..95e7c7f0 100644 --- a/apps/backend/lambdas/tools/lambda-cli.js +++ b/apps/backend/lambdas/tools/lambda-cli.js @@ -48,7 +48,7 @@ function templatePackageJson() { "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@types/aws-lambda": "^8.10.131", "@types/node": "^20.11.30", "ts-node": "^10.9.2", diff --git a/apps/backend/lambdas/users/auth.ts b/apps/backend/lambdas/users/auth.ts index 2f22ed76..f5ada346 100644 --- a/apps/backend/lambdas/users/auth.ts +++ b/apps/backend/lambdas/users/auth.ts @@ -5,7 +5,7 @@ import type { AuthContext, AccessLevel, AuthorizationCheck, -} from '@branch/dtos'; +} from '@branch/types'; import db from './db'; export type { AuthenticatedUser, AuthContext, AccessLevel, AuthorizationCheck }; diff --git a/apps/backend/lambdas/users/db.ts b/apps/backend/lambdas/users/db.ts index 42860745..a7a0a232 100644 --- a/apps/backend/lambdas/users/db.ts +++ b/apps/backend/lambdas/users/db.ts @@ -1,7 +1,7 @@ import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' -import type { DB } from '@branch/dtos' +import type { DB } from '@branch/types' const db = new Kysely({ dialect: new PostgresDialect({ diff --git a/apps/backend/lambdas/users/package-lock.json b/apps/backend/lambdas/users/package-lock.json index c3285202..0d06bbc0 100644 --- a/apps/backend/lambdas/users/package-lock.json +++ b/apps/backend/lambdas/users/package-lock.json @@ -14,7 +14,7 @@ "pg": "^8.16.3" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", @@ -26,8 +26,8 @@ "typescript": "^5.4.5" } }, - "../../../../shared/dtos": { - "name": "@branch/dtos", + "../../../../shared/types": { + "name": "@branch/types", "version": "1.0.0", "dev": true }, @@ -492,8 +492,8 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "license": "MIT" }, - "node_modules/@branch/dtos": { - "resolved": "../../../../shared/dtos", + "node_modules/@branch/types": { + "resolved": "../../../../shared/types", "link": true }, "node_modules/@cspotcode/source-map-support": { diff --git a/apps/backend/lambdas/users/package.json b/apps/backend/lambdas/users/package.json index 1f316ba8..ee1f932e 100644 --- a/apps/backend/lambdas/users/package.json +++ b/apps/backend/lambdas/users/package.json @@ -10,7 +10,7 @@ "package": "npm run build && cd dist && zip -r ../lambda.zip . -x '*.map' 'dev-server.*' 'swagger-utils.*'" }, "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos", + "@branch/types": "file:../../../../shared/types", "@types/aws-lambda": "^8.10.131", "@types/jest": "^30.0.0", "@types/node": "^20.11.30", diff --git a/shared/dtos/package.json b/shared/dtos/package.json deleted file mode 100644 index 5041a308..00000000 --- a/shared/dtos/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@branch/dtos", - "version": "1.0.0", - "private": true, - "description": "Shared DTO type definitions for Branch lambdas", - "types": "index.d.ts", - "files": [ - "*.d.ts" - ] -} diff --git a/shared/dtos/README.md b/shared/types/README.md similarity index 76% rename from shared/dtos/README.md rename to shared/types/README.md index 0a5e7b3a..fccc673f 100644 --- a/shared/dtos/README.md +++ b/shared/types/README.md @@ -1,6 +1,6 @@ -# @branch/dtos +# @branch/types -Shared DTO type definitions for the Branch lambdas. This replaces the per-lambda copies of `db-types.d.ts` and the duplicated auth interfaces (`AuthenticatedUser`, `AuthContext`, etc.). +Shared type definitions for the Branch lambdas. This replaces the per-lambda copies of `db-types.d.ts` and the duplicated auth interfaces (`AuthenticatedUser`, `AuthContext`, etc.). ## What's in here @@ -15,7 +15,7 @@ The package is **types-only** — it contains no runtime code and has no depende ```json "devDependencies": { - "@branch/dtos": "file:../../../../shared/dtos" + "@branch/types": "file:../../../../shared/types" } ``` @@ -24,8 +24,8 @@ Because the package only ships `.d.ts` files, all imports are erased at compile ## Usage ```ts -import type { DB } from '@branch/dtos'; -import type { AuthContext, AuthenticatedUser } from '@branch/dtos'; +import type { DB } from '@branch/types'; +import type { AuthContext, AuthenticatedUser } from '@branch/types'; ``` Note: `db-types.d.ts` defines a local `ColumnType` that is structurally identical to kysely's, so the package itself does not depend on kysely. diff --git a/shared/dtos/auth-types.d.ts b/shared/types/auth-types.d.ts similarity index 100% rename from shared/dtos/auth-types.d.ts rename to shared/types/auth-types.d.ts diff --git a/shared/dtos/db-types.d.ts b/shared/types/db-types.d.ts similarity index 100% rename from shared/dtos/db-types.d.ts rename to shared/types/db-types.d.ts diff --git a/shared/dtos/index.d.ts b/shared/types/index.d.ts similarity index 100% rename from shared/dtos/index.d.ts rename to shared/types/index.d.ts diff --git a/shared/types/package.json b/shared/types/package.json new file mode 100644 index 00000000..154c7d00 --- /dev/null +++ b/shared/types/package.json @@ -0,0 +1,10 @@ +{ + "name": "@branch/types", + "version": "1.0.0", + "private": true, + "description": "Shared type definitions (DB row types and DTOs) for Branch lambdas", + "types": "index.d.ts", + "files": [ + "*.d.ts" + ] +} From 12ce8b2f1ec28732a4c54d50fad088a6df29bb24 Mon Sep 17 00:00:00 2001 From: nourshoreibah Date: Tue, 9 Jun 2026 20:28:29 -0400 Subject: [PATCH 3/3] Fix users test mocks after isAdmin became optional in shared types Coerce isAdmin to a boolean when building AuthorizationCheck mocks so allowed is always boolean, matching the shared type definition. Co-authored-by: Cursor --- apps/backend/lambdas/users/test/user.unit.test.ts | 7 ++++--- apps/backend/lambdas/users/test/users.test.ts | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/backend/lambdas/users/test/user.unit.test.ts b/apps/backend/lambdas/users/test/user.unit.test.ts index 97d73278..e7fed8be 100644 --- a/apps/backend/lambdas/users/test/user.unit.test.ts +++ b/apps/backend/lambdas/users/test/user.unit.test.ts @@ -23,14 +23,15 @@ mockCheckAuthorization.mockImplementation((authContext, requiredAccess, resource } if (requiredAccess === 'ADMIN') { + const isAdmin = authContext.user.isAdmin ?? false; return { - allowed: authContext.user.isAdmin, - reason: authContext.user.isAdmin ? undefined : 'Admin access required' + allowed: isAdmin, + reason: isAdmin ? undefined : 'Admin access required' }; } if (requiredAccess === 'ADMIN_OR_SELF') { - const allowed = authContext.user.isAdmin || authContext.user.userId === Number(resourceUserId); + const allowed = (authContext.user.isAdmin ?? false) || authContext.user.userId === Number(resourceUserId); return { allowed, reason: allowed ? undefined : 'Admin access or resource ownership required' diff --git a/apps/backend/lambdas/users/test/users.test.ts b/apps/backend/lambdas/users/test/users.test.ts index 6d111334..e6b67618 100644 --- a/apps/backend/lambdas/users/test/users.test.ts +++ b/apps/backend/lambdas/users/test/users.test.ts @@ -14,9 +14,12 @@ const mockCheckAuthorization = checkAuthorization as jest.MockedFunction { if (requiredAccess === 'PUBLIC') return { allowed: true }; if (!authContext.isAuthenticated || !authContext.user) return { allowed: false, reason: 'Authentication required' }; - if (requiredAccess === 'ADMIN') return { allowed: authContext.user.isAdmin, reason: authContext.user.isAdmin ? undefined : 'Admin access required' }; + if (requiredAccess === 'ADMIN') { + const isAdmin = authContext.user.isAdmin ?? false; + return { allowed: isAdmin, reason: isAdmin ? undefined : 'Admin access required' }; + } if (requiredAccess === 'ADMIN_OR_SELF') { - const allowed = authContext.user.isAdmin || authContext.user.userId === Number(resourceUserId); + const allowed = (authContext.user.isAdmin ?? false) || authContext.user.userId === Number(resourceUserId); return { allowed, reason: allowed ? undefined : 'Admin access or resource ownership required' }; } return { allowed: false, reason: 'Unknown access level' };