Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
7f1166e
chore(deps): bump the prod-deps group across 1 directory with 9 updates
dependabot[bot] Dec 4, 2025
e1d4912
feat: add rate limiting (#983)
annarhughes Dec 17, 2025
6f62240
Merge branch 'develop' into dependabot/npm_and_yarn/prod-deps-ecdf118d0e
annarhughes Dec 17, 2025
94a9a3b
Merge pull request #965 from chaynHQ/dependabot/npm_and_yarn/prod-dep…
annarhughes Dec 17, 2025
87bf1d0
chore(deps-dev): bump the dev-deps group across 1 directory with 10 u…
dependabot[bot] Dec 17, 2025
d7739a5
chore(deps): bump the actions-deps group across 1 directory with 7 up…
dependabot[bot] Dec 17, 2025
8c5a555
chore(deps): bump node-forge from 1.3.1 to 1.3.3 (#971)
dependabot[bot] Dec 17, 2025
338eda3
chore(deps-dev): bump the dev-deps group with 3 updates (#985)
dependabot[bot] Dec 17, 2025
36b4ca8
chore(deps): bump the prod-deps group with 2 updates (#986)
dependabot[bot] Dec 17, 2025
cc9055c
chore(deps): bump uuid from 11.1.0 to 13.0.0 (#987)
dependabot[bot] Dec 17, 2025
fcff598
chore(deps): bump dotenv from 16.6.1 to 17.2.3 (#989)
dependabot[bot] Dec 17, 2025
0cf041f
chore(deps): bump firebase from 11.10.0 to 12.7.0 (#988)
dependabot[bot] Dec 17, 2025
e1efac4
deps: upgrade nest + packages (#990)
annarhughes Dec 17, 2025
4a57ce5
chore(deps): bump the actions-deps group with 3 updates (#993)
dependabot[bot] Dec 22, 2025
8cc46de
chore(deps): bump the prod-deps group with 5 updates (#992)
dependabot[bot] Dec 22, 2025
ee12326
chore(deps-dev): bump @nestjs/testing in the dev-deps group (#991)
dependabot[bot] Dec 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/.ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ jobs:
STORYBLOK_PUBLIC_TOKEN: ${{ secrets.STORYBLOK_PUBLIC_TOKEN }}
STORYBLOK_WEBHOOK_SECRET: ${{ secrets.STORYBLOK_WEBHOOK_SECRET }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache node_modules
uses: actions/cache@v4
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Use NodeJs
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '22.x'
- name: Install dependencies
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -56,7 +56,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v4

# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
Expand All @@ -69,4 +69,4 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
4 changes: 2 additions & 2 deletions .github/workflows/community-issue-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
steps:
- name: Post assignee issue comment
id: assigned-comment
uses: actions/github-script@v7 # https://github.com/actions/github-script
uses: actions/github-script@v8 # https://github.com/actions/github-script
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
steps:
- name: Post stale issue comment
id: stale-label-comment
uses: actions/github-script@v7 # https://github.com/actions/github-script
uses: actions/github-script@v8 # https://github.com/actions/github-script
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/community-slack-activity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
issues: read
steps:
- name: Checkout repository
uses: actions/checkout@v4 # https://github.com/actions/checkout
uses: actions/checkout@v6 # https://github.com/actions/checkout

- name: Set up Node.js
uses: actions/setup-node@v4 # https://github.com/actions/setup-node
uses: actions/setup-node@v6 # https://github.com/actions/setup-node
with:
node-version: '20'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/community-stale-management.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
pull-requests: write

steps:
- uses: actions/stale@v9 # https://github.com/actions/stale
- uses: actions/stale@v10 # https://github.com/actions/stale
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-label: 'stale'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/create-release-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Create Pull Request
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
script: |
const { repo, owner } = context.repo;
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: 'Dependency Review'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/newrelic-release-tracking.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
run: echo "COMMIT_REF=${{ github.ref_name }}" >> $GITHUB_ENV
# This step creates a new Change Tracking Marker
- name: New Relic Application Deployment Marker
uses: newrelic/deployment-marker-action@v2.5.1
uses: newrelic/deployment-marker-action@v2.6.2
with:
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
region: 'EU'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scan-and-label-forks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
steps:
- name: Label PR for Sensitive Files
# https://github.com/actions/labeler
uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9
uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/configs/labeler.yml
67 changes: 34 additions & 33 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,64 +30,65 @@
"dependencies": {
"@mailchimp/mailchimp_marketing": "^3.0.80",
"@nestjs/axios": "^4.0.1",
"@nestjs/common": "^11.1.6",
"@nestjs/common": "^11.1.10",
"@nestjs/config": "^4.0.1",
"@nestjs/core": "^10.4.15",
"@nestjs/platform-express": "^10.4.12",
"@nestjs/swagger": "^7.4.0",
"@nestjs/core": "^11.1.10",
"@nestjs/platform-express": "^11.1.10",
"@nestjs/swagger": "^11.2.3",
"@nestjs/terminus": "^11.0.0",
"@nestjs/throttler": "^6.5.0",
"@nestjs/typeorm": "^11.0.0",
"@storyblok/js": "^4.2.5",
"axios": "^1.11.0",
"@storyblok/js": "^4.4.3",
"axios": "^1.13.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.2",
"crisp-api": "^9.10.0",
"class-validator": "^0.14.3",
"crisp-api": "^10.2.0",
"date-fns": "^4.1.0",
"dompurify": "^3.3.0",
"dotenv": "^16.5.0",
"firebase": "^11.9.1",
"firebase-admin": "^13.5.0",
"jsdom": "^27.2.0",
"dompurify": "^3.3.1",
"dotenv": "^17.2.3",
"firebase": "^12.7.0",
"firebase-admin": "^13.6.0",
"jsdom": "^27.3.0",
"lodash": "^4.17.21",
"nestjs-cls": "^6.0.1",
"newrelic": "^12.21.0",
"nestjs-cls": "^6.1.0",
"newrelic": "^13.8.1",
"pg": "^8.16.3",
"pg-connection-string": "^2.7.0",
"reflect-metadata": "^0.2.1",
"rimraf": "^6.0.1",
"rollbar": "^2.26.4",
"rimraf": "^6.1.2",
"rollbar": "^2.26.5",
"rxjs": "^7.8.1",
"typeorm": "^0.3.26",
"uuid": "^11.0.3",
"validator": "^13.15.23"
"typeorm": "^0.3.28",
"uuid": "^13.0.0",
"validator": "^13.15.26"
},
"devDependencies": {
"@eslint/js": "^9.34.0",
"@eslint/js": "^9.39.2",
"@golevelup/ts-jest": "^0.7.0",
"@nestjs/cli": "^11.0.10",
"@nestjs/schematics": "^11.0.7",
"@nestjs/testing": "^10.4.15",
"@nestjs/cli": "^11.0.14",
"@nestjs/schematics": "^11.0.9",
"@nestjs/testing": "^11.1.10",
"@types/date-fns": "^2.6.0",
"@types/dompurify": "^3.2.0",
"@types/express": "^5.0.3",
"@types/jest": "^29.5.13",
"@types/express": "^5.0.6",
"@types/jest": "^30.0.0",
"@types/jsdom": "^27.0.0",
"@types/lodash": "^4.17.20",
"@types/node": "^22.15.29",
"@types/lodash": "^4.17.21",
"@types/node": "^25.0.3",
"@types/supertest": "^6.0.2",
"@types/validator": "^13.15.10",
"eslint": "^9.34.0",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"jest": "^29.7.0",
"prettier": "^3.6.2",
"jest": "^30.2.0",
"prettier": "^3.7.4",
"supertest": "^7.1.4",
"ts-jest": "^29.4.1",
"ts-jest": "^29.4.6",
"ts-loader": "^9.5.4",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.9.2",
"typescript-eslint": "^8.40.0"
"typescript-eslint": "^8.50.0"
},
"engines": {
"node": "22.x",
Expand Down
19 changes: 18 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { ConfigModule } from '@nestjs/config';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ClsModule } from 'nestjs-cls';
import { dataSourceOptions } from 'src/typeorm.config';
Expand Down Expand Up @@ -32,13 +34,22 @@ import { WebhooksModule } from './webhooks/webhooks.module';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
ThrottlerModule.forRoot([
{
ttl: 60000, // 60 seconds
limit: 100, // 100 requests per TTL window
},
]),
TypeOrmModule.forRoot(dataSourceOptions as TypeOrmModuleOptions),
ClsModule.forRoot({
global: true,
middleware: {
mount: true,
generateId: true,
idGenerator: (req: Request) => req.headers['X-Request-Id'] ?? uuidv4(),
idGenerator: (req: Request) => {
const requestId = req.headers['x-request-id'];
return (Array.isArray(requestId) ? requestId[0] : requestId) ?? uuidv4();
},
},
}),
LoggerModule,
Expand Down Expand Up @@ -66,5 +77,11 @@ import { WebhooksModule } from './webhooks/webhooks.module';
ResourceFeedbackModule,
TherapySessionModule,
],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class AppModule {}
8 changes: 5 additions & 3 deletions src/crisp/crisp.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ export interface NewCrispProfileBaseResponse {
data: CrispProfileBaseResponse;
}

// Response type from crisp-api getPeopleData - matches PeopleData type
export interface CrispProfileDataResponse {
error: boolean;
reason: string;
data: { data: CrispProfileCustomFields };
data?: CrispProfileCustomFields;
}

// Type for updatePeopleData params - crisp-api expects flat Record, not nested object
export type CrispPeopleDataUpdateParams = Record<string, string | number | boolean>;
2 changes: 1 addition & 1 deletion src/crisp/crisp.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ describe('CrispService', () => {
expect(mockWebsite.updatePeopleData).toHaveBeenCalledWith(
crispWebsiteId,
'[email protected]',
{ data: customFields },
customFields,
);
expect(response).toEqual(expectedResponse);
});
Expand Down
28 changes: 22 additions & 6 deletions src/crisp/crisp.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EventLoggerService } from 'src/event-logger/event-logger.service';
import { crispPluginId, crispPluginKey, crispWebsiteId } from 'src/utils/constants';
import { isCypressTestEmail } from 'src/utils/utils';
import {
CrispPeopleDataUpdateParams,
CrispProfileBase,
CrispProfileBaseResponse,
CrispProfileCustomFields,
Expand All @@ -21,6 +22,19 @@ export class CrispService {
CrispClient.authenticateTier('plugin', crispPluginId, crispPluginKey);
}

// Convert CrispProfileCustomFields to the format crisp-api expects (primitive values only)
private toCrispDataParams(
peopleData: CrispProfileCustomFields,
): CrispPeopleDataUpdateParams {
const data: CrispPeopleDataUpdateParams = {};
for (const [key, value] of Object.entries(peopleData)) {
if (value !== undefined && value !== null) {
data[key] = value;
}
}
return data;
}

private isProfileNotFoundError(error: unknown): boolean {
// Based on Crisp API docs, error format is: { reason: 'error', message: 'not_found', code: 404 }
const errorObj = error as Record<string, unknown>;
Expand Down Expand Up @@ -143,19 +157,21 @@ export class CrispService {
return null;
}

const params = this.toCrispDataParams(peopleData);

try {
const crispPeopleData = CrispClient.website.updatePeopleData(crispWebsiteId, email, {
data: peopleData,
});
const crispPeopleData = CrispClient.website.updatePeopleData(
crispWebsiteId,
email,
params,
);
return crispPeopleData;
} catch (error) {
// Only handle profile not found errors (404, not_found, or profile-related errors)
if (this.isProfileNotFoundError(error)) {
try {
await this.createCrispProfile({ email });
return await CrispClient.website.updatePeopleData(crispWebsiteId, email, {
data: peopleData,
});
return await CrispClient.website.updatePeopleData(crispWebsiteId, email, params);
} catch {
throw new Error(`Update crisp profile API call failed: ${error}`);
}
Expand Down
6 changes: 3 additions & 3 deletions src/user/dtos/admin-update-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ export class AdminUpdateUserDto {

@IsOptional()
@IsDate()
@ApiProperty({ type: 'date' })
@ApiProperty({ type: Date })
lastActiveAt: Date;

@SecureInput('email', { required: false, maxLength: 255 })
@ApiProperty({ type: 'email' })
@ApiProperty({ type: String, format: 'email' })
email: string;

@IsOptional()
@IsBoolean({})
@ApiProperty({ type: 'boolean' })
@ApiProperty({ type: Boolean })
isSuperAdmin: boolean;
}
4 changes: 2 additions & 2 deletions src/user/dtos/update-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ export class UpdateUserDto {

@IsOptional()
@IsDate()
@ApiProperty({ type: 'date' })
@ApiProperty({ type: Date })
lastActiveAt: Date;

@SecureInput('email', { required: false, maxLength: 255 })
@ApiProperty({ type: 'email' })
@ApiProperty({ type: String, format: 'email' })
email: string;
}
Loading
Loading