Serve gh release over the GitHub compatibility layer4951bed10 hours ago142 lines · 5.7 KB | 1 | import type { IncomingMessage } from 'node:http'; |
| 2 | |
| 3 | import type { Database |
| 4 | import { Module } |
| 5 | import { ConfigModule, ConfigService |
| 6 | import { AuthModule } |
| 7 | import type { Request |
| 8 | |
| 9 | import { AppController } |
| 10 | import { AvatarsModule } |
| 11 | import { DATABASE, DatabaseModule |
| 12 | import { GitModule } |
| 13 | import { GithubModule } |
| 14 | import { createAuth } |
| 15 | import { githubOAuthConfig } |
| 16 | import { |
| 17 | emailVerificationEnabled, |
| 18 | MailModule, |
| 19 | mailConfigured, |
| 20 | } from './mail/mail.module.js'; |
| 21 | import { MailService } |
| 22 | import { AttachmentsModule } |
| 23 | import { BranchesModule } |
| 24 | import { CollaboratorsModule } |
| 25 | import { EmailsModule } |
| 26 | import { GpgKeysModule } |
| 27 | import { ImportsModule } |
| 28 | import { IssuesModule } |
| 29 | import { NotificationsModule } |
| 30 | import { OauthAppsModule } |
| 31 | import { OrganizationsModule } |
| 32 | import { PullRequestsModule } |
| 33 | import { ReleasesModule } |
| 34 | import { RepositoriesModule } |
| 35 | import { SshKeysModule } |
| 36 | import { UserModule } |
| 37 | import { WebhooksModule } |
| 38 | import { S3Module } |
| 39 | import { AvatarStorageService } |
| 40 | import { AppStatsService } |
| 41 | |
| 42 | /** Body parsing for `type`, except on GitHub's asset uploads, which stream raw bytes of any type to object storage. */ |
| 43 | const parses = ( |
| 44 | const request = |
| 45 | return ( |
| 46 | !request.originalUrl.startsWith |
| 47 | Boolean(request.is |
| 48 | ); |
| 49 | }; |
| 50 | |
| 51 | @Module({ |
| 52 | imports: [ |
| 53 | S3Module, |
| 54 | ConfigModule.forRoot({ |
| 55 | isGlobal: true, |
| 56 | // `.env` interpolates values (e.g. BETTER_AUTH_URL=http://localhost:${API_PORT}), which dotenv does not expand on its own. |
| 57 | expandVariables: true, |
| 58 | envFilePath: ['.env.local', |
| 59 | }), |
| 60 | DatabaseModule, |
| 61 | MailModule, |
| 62 | AuthModule.forRootAsync({ |
| 63 | imports: [DatabaseModule, |
| 64 | inject: [DATABASE, |
| 65 | useFactory: ( |
| 66 | db: Database |
| 67 | config: ConfigService |
| 68 | mail: MailService |
| 69 | avatars: AvatarStorageService |
| 70 | ) => ({ |
| 71 | // Importer batches carry whole issue bodies, which GitHub allows up to 64K characters each. |
| 72 | bodyParser: { |
| 73 | json: { limit: ' |
| 74 | urlencoded: { type: parses |
| 75 | }, |
| 76 | auth: createAuth(db |
| 77 | secret: config.getOrThrow |
| 78 | baseURL: config.getOrThrow |
| 79 | trustedOrigins: config |
| 80 | .get<string>( |
| 81 | .split(',') |
| 82 | .map((origin) |
| 83 | .filter(Boolean), |
| 84 | cookieDomain: config.get |
| 85 | webAppUrl: config.get |
| 86 | github: githubOAuthConfig(config |
| 87 | sendChangeEmail: mailConfigured(config |
| 88 | ? ({ email, |
| 89 | mail.sendChangeEmailEmail(email |
| 90 | name, |
| 91 | newEmail, |
| 92 | approveUrl: url, |
| 93 | }) |
| 94 | : undefined, |
| 95 | onOrganizationDeleted: async ( |
| 96 | await Promise.all |
| 97 | [organizationId, ...oauthClientIds |
| 98 | avatars.remove(id |
| 99 | ), |
| 100 | ); |
| 101 | }, |
| 102 | sendOrganizationInvitation: mailConfigured(config |
| 103 | ? ({ email, |
| 104 | mail.sendOrganizationInvitationEmail(email |
| 105 | ...context, |
| 106 | acceptUrl: url, |
| 107 | }) |
| 108 | : undefined, |
| 109 | sendResetPassword: mailConfigured(config |
| 110 | ? ({ email, |
| 111 | mail.sendResetPasswordEmail(email |
| 112 | : undefined, |
| 113 | sendVerificationEmail: emailVerificationEnabled(config |
| 114 | ? ({ email, |
| 115 | mail.sendVerificationEmail(email |
| 116 | : undefined, |
| 117 | }), |
| 118 | }), |
| 119 | }), |
| 120 | RepositoriesModule, |
| 121 | OrganizationsModule, |
| 122 | PullRequestsModule, |
| 123 | IssuesModule, |
| 124 | ImportsModule, |
| 125 | ReleasesModule, |
| 126 | AttachmentsModule, |
| 127 | BranchesModule, |
| 128 | NotificationsModule, |
| 129 | CollaboratorsModule, |
| 130 | WebhooksModule, |
| 131 | EmailsModule, |
| 132 | GpgKeysModule, |
| 133 | SshKeysModule, |
| 134 | GitModule, |
| 135 | UserModule, |
| 136 | GithubModule, |
| 137 | OauthAppsModule, |
| 138 | ], |
| 139 | controllers: [AppController], |
| 140 | providers: [AppStatsService], |
| 141 | }) |
| 142 | export class AppModule |
}
from
'
@ghost/db
'
;
from
'
@nestjs/common
'
;
}
from
'
@nestjs/config
'
;
from
'
@thallesp/nestjs-better-auth
'
;
}
from
'
express
'
;
from
'
./app.controller.js
'
;
from
'
./avatars/avatars.module.js
'
;
}
from
'
./database/database.module.js
'
;
from
'
./git/git.module.js
'
;
from
'
./github/github.module.js
'
;
from
'
./lib/auth.js
'
;
from
'
./lib/imports/importer.js
'
;
from
'
./mail/mail.service.js
'
;
from
'
./resources/attachments/attachments.module.js
'
;
from
'
./resources/branches/branches.module.js
'
;
from
'
./resources/collaborators/collaborators.module.js
'
;
from
'
./resources/emails/emails.module.js
'
;
from
'
./resources/gpg-keys/gpg-keys.module.js
'
;
from
'
./resources/imports/imports.module.js
'
;
from
'
./resources/issues/issues.module.js
'
;
from
'
./resources/notifications/notifications.module.js
'
;
from
'
./resources/oauth-apps/oauth-apps.module.js
'
;
from
'
./resources/organizations/organizations.module.js
'
;
from
'
./resources/pull-requests/pull-requests.module.js
'
;
from
'
./resources/releases/releases.module.js
'
;
from
'
./resources/repositories/repositories.module.js
'
;
from
'
./resources/ssh-keys/ssh-keys.module.js
'
;
from
'
./resources/user/user.module.js
'
;
from
'
./resources/webhooks/webhooks.module.js
'
;
from
'
./s3/s3.module.js
'
;
from
'
./services/avatars/avatar-storage.service.js
'
;
from
'
./services/stats/app-stats.service.js
'
;
type
:
string
)
=>
(
req
:
IncomingMessage
)
=>
{
req
as
Request
;
(
'
/api/uploads/
'
)
&&
(
type
))
'
.env
'
,
'
../../.env
'
]
,
MailModule
,
AvatarsModule
]
,
ConfigService
,
MailService
,
AvatarStorageService
]
,
,
,
,
,
2mb
'
,
type
:
parses
(
'
application/json
'
)
}
,
(
'
application/x-www-form-urlencoded
'
)
}
,
,
{
<
string
>
(
'
BETTER_AUTH_SECRET
'
)
,
<
string
>
(
'
BETTER_AUTH_URL
'
)
,
'
AUTH_TRUSTED_ORIGINS
'
,
'
http://localhost:3000
'
)
=>
origin
.
trim
())
<
string
>
(
'
AUTH_COOKIE_DOMAIN
'
)
,
<
string
>
(
'
WEB_APP_URL
'
,
'
http://localhost:3000
'
)
,
)
??
undefined
,
)
name
,
newEmail
,
url
}
)
=>
,
{
organizationId
,
oauthClientIds
)
=>
{
(
]
.
map
(
(
id
)
=>
)
,
)
url
,
...
context
}
)
=>
,
{
)
name
,
url
}
)
=>
,
{
name
,
resetUrl
:
url
}
)
)
name
,
url
}
)
=>
,
{
name
,
verifyUrl
:
url
}
)
{}