diff --git a/.github/workflows/lambda-deploy.yml b/.github/workflows/lambda-deploy.yml index a298c2e2..e0dab286 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/types/**' jobs: detect-changes: diff --git a/.github/workflows/regenerate-db-types.yaml b/.github/workflows/regenerate-db-types.yaml index 72e8ae7e..6e9840b1 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/types" SOURCE_FILE="apps/backend/db/db-types.d.ts" + TARGET_FILE="shared/types/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/types/db-types.d.ts || { + echo "Error: shared/types/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/types/db-types.d.ts - if git diff --exit-code apps/backend/lambdas/*/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 @@ -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/types/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/types/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/types/db-types.d.ts\` - The updated types are now in sync with 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, @@ -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/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/.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..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 './db-types' +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 a117d8cb..fd2fff88 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/types": "file:../../../../shared/types", "@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/types": { + "name": "@branch/types", + "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/types": { + "resolved": "../../../../shared/types", + "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..ff26cd65 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/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 6b70cf46..2bd29110 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/types'; 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..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 './db-types' +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 a254a95a..6b435862 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/types": "file:../../../../shared/types", "@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/types": { + "name": "@branch/types", + "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/types": { + "resolved": "../../../../shared/types", + "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..23e8c3ad 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/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 5d64d0dd..63bb9855 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/types'; 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..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 './db-types' +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 fadb02af..e82a51bc 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/types": "file:../../../../shared/types", "@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/types": { + "name": "@branch/types", + "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/types": { + "resolved": "../../../../shared/types", + "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..9f89226f 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/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 d1b8d662..ce0a5fb4 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/types'; 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..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 './db-types' +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 2b4b6bca..514da2fe 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/types": "file:../../../../shared/types", "@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/types": { + "name": "@branch/types", + "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/types": { + "resolved": "../../../../shared/types", + "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..58d7072a 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/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 69cfd57c..94b95822 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/types'; 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..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 './db-types' +import type { DB } from '@branch/types' 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..1f01b75b 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/types": "file:../../../../shared/types", "@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/types": { + "name": "@branch/types", + "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/types": { + "resolved": "../../../../shared/types", + "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..896ea770 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/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 fd0ccb05..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 +- `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 5e7d2347..95e7c7f0 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/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 0fd2e84d..f5ada346 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/types'; 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..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 './db-types' +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 a5ed3360..0d06bbc0 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/types": "file:../../../../shared/types", "@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/types": { + "name": "@branch/types", + "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/types": { + "resolved": "../../../../shared/types", + "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..ee1f932e 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/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/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' }; 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/types/README.md b/shared/types/README.md new file mode 100644 index 00000000..fccc673f --- /dev/null +++ b/shared/types/README.md @@ -0,0 +1,39 @@ +# @branch/types + +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 + +| 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/types": "file:../../../../shared/types" +} +``` + +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/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. + +## 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/types/auth-types.d.ts b/shared/types/auth-types.d.ts new file mode 100644 index 00000000..eccc244e --- /dev/null +++ b/shared/types/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/types/db-types.d.ts similarity index 83% rename from apps/backend/lambdas/reports/db-types.d.ts rename to shared/types/db-types.d.ts index f5ce7754..fea62bf6 100644 --- a/apps/backend/lambdas/reports/db-types.d.ts +++ b/shared/types/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/types/index.d.ts b/shared/types/index.d.ts new file mode 100644 index 00000000..f988d9c8 --- /dev/null +++ b/shared/types/index.d.ts @@ -0,0 +1,2 @@ +export * from './db-types'; +export * from './auth-types'; 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" + ] +}