• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inclusion-numerique / coop-mediation-numerique / 4c3f2b63-ebf1-404a-997e-d0d9c5d67600

01 Apr 2026 04:09PM UTC coverage: 7.472% (-3.2%) from 10.684%
4c3f2b63-ebf1-404a-997e-d0d9c5d67600

Pull #464

circleci

web-flow
chore(deps): bump next from 15.5.9 to 15.5.14

Bumps [next](https://github.com/vercel/next.js) from 15.5.9 to 15.5.14.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.5.9...v15.5.14)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 15.5.14
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #464: chore(deps): bump next from 15.5.9 to 15.5.14

500 of 10542 branches covered (4.74%)

Branch coverage included in aggregate %.

1500 of 16224 relevant lines covered (9.25%)

36.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/apps/web/src/api-client/apiClient.ts
1
import { prismaClient } from '@app/web/prismaClient'
2
import { generateRandomSecret } from '@app/web/security/generateRandomSecret'
3
import { hashSecret, verifySecret } from '@app/web/security/hashSecret'
4
import { ApiClient, ApiClientScope } from '@prisma/client'
5

6
export type CreateApiClientInput = {
7
  id?: string
8
  name: string
9
  scopes: ApiClientScope[]
10
  validUntil?: Date
11
  validFrom?: Date
12
}
13

14
export const createApiClient = async ({
×
15
  id,
16
  name,
17
  scopes,
18
  validFrom,
19
  validUntil,
20
}: CreateApiClientInput): Promise<
21
  ApiClient & {
22
    secret: string
23
  }
24
> => {
25
  const secret = generateRandomSecret()
×
26
  const secretHash = hashSecret(secret)
×
27

28
  const apiClient = await prismaClient.apiClient.create({
×
29
    data: {
30
      id,
31
      name,
32
      secretHash, // Store the hashed secret in the database
33
      validFrom: validFrom ?? new Date(),
×
34
      validUntil,
35
      scopes,
36
    },
37
  })
38

39
  return {
×
40
    ...apiClient,
41
    secret,
42
    secretHash,
43
  }
44
}
45

46
export type CreateApiClientOutput = Awaited<ReturnType<typeof createApiClient>>
47

48
export const rotateApiClientSecret = async ({
×
49
  clientId,
50
}: {
51
  clientId: string
52
}) => {
53
  const secret = generateRandomSecret()
×
54
  const secretHash = hashSecret(secret)
×
55

56
  await prismaClient.apiClient.update({
×
57
    where: { id: clientId },
58
    data: {
59
      secretHash, // Store the hashed secret in the database
60
      updated: new Date(),
61
    },
62
  })
63

64
  return {
×
65
    clientId,
66
    secret,
67
    secretHash,
68
  }
69
}
70

71
export const changeApiClientScopes = async ({
×
72
  clientId,
73
  scopes,
74
}: {
75
  clientId: string
76
  scopes: ApiClientScope[]
77
}) => {
78
  const apiClient = await prismaClient.apiClient.findUnique({
×
79
    where: { id: clientId },
80
  })
81

82
  if (!apiClient) {
×
83
    throw new Error('Api client not found')
×
84
  }
85

86
  await prismaClient.apiClient.update({
×
87
    where: { id: clientId },
88
    data: {
89
      scopes,
90
      updated: new Date(),
91
    },
92
  })
93
}
94

95
export const authenticateApiCient = async (
×
96
  clientId: string,
97
  clientSecret: string,
98
): Promise<ApiClient | null> => {
99
  // Ensure that clientId is a uuid v4 using regex
100
  if (!/^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/.test(clientId)) return null
×
101

102
  const apiClient = await prismaClient.apiClient.findUnique({
×
103
    where: { id: clientId },
104
  })
105

106
  if (!apiClient) return null
×
107

108
  const isValid = verifySecret(clientSecret, apiClient.secretHash)
×
109

110
  if (!isValid) return null
×
111

112
  const now = new Date()
×
113

114
  if (apiClient.validFrom > now) return null
×
115

116
  if (!!apiClient.validUntil && apiClient.validUntil < now) {
×
117
    return null
×
118
  }
119

120
  return apiClient
×
121
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc