2023-11-06 22:15:02 +00:00
|
|
|
import { Module } from '@nestjs/common';
|
2025-07-23 12:57:16 +00:00
|
|
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
2023-11-06 22:15:02 +00:00
|
|
|
|
2025-06-23 19:05:01 +00:00
|
|
|
import { CronRegisterAllCommand } from 'src/database/commands/cron-register-all.command';
|
2025-09-08 14:46:31 +00:00
|
|
|
import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command';
|
2026-01-06 14:13:40 +00:00
|
|
|
import { ListOrphanedWorkspaceEntitiesCommand } from 'src/database/commands/list-and-delete-orphaned-workspace-entities.command';
|
2024-07-09 15:48:10 +00:00
|
|
|
import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question';
|
2025-02-28 18:51:32 +00:00
|
|
|
import { UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/upgrade-version-command.module';
|
2024-07-09 15:48:10 +00:00
|
|
|
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
2025-07-09 15:03:54 +00:00
|
|
|
import { ApiKeyModule } from 'src/engine/core-modules/api-key/api-key.module';
|
2026-02-23 18:56:44 +00:00
|
|
|
import { GenerateApiKeyCommand } from 'src/engine/core-modules/api-key/commands/generate-api-key.command';
|
2026-03-06 07:45:08 +00:00
|
|
|
import { ApplicationUpgradeModule } from 'src/engine/core-modules/application/application-upgrade/application-upgrade.module';
|
feat: add npm and tarball app distribution with upgrade mechanism (#18358)
## Summary
- **npm + tarball app distribution**: Apps can be installed from the npm
registry (public or private) or uploaded as `.tar.gz` tarballs, with
`AppRegistrationSourceType` tracking the origin
- **Upgrade mechanism**: `AppUpgradeService` checks for newer versions,
supports rollback for npm-sourced apps, and a cron job runs every 6
hours to update `latestAvailableVersion` on registrations
- **Security hardening**: Tarball extraction uses path traversal
protection, and `enableScripts: false` in `.yarnrc.yml` disables all
lifecycle scripts during `yarn install` to prevent RCE
- **Frontend**: "Install from npm" and "Upload tarball" modals, upgrade
button on app detail page, blue "Update" badge on installed apps table
when a newer version is available
- **Marketplace catalog sync**: Hourly cron job syncs a hardcoded
catalog index into `ApplicationRegistration` entities
- **Integration tests**: Coverage for install, upgrade, tarball upload,
and catalog sync flows
## Backend changes
| Area | Files |
|------|-------|
| Entity & migration | `ApplicationRegistrationEntity` (sourceType,
sourcePackage, latestAvailableVersion), `ApplicationEntity`
(applicationRegistrationId), migration |
| Services | `AppPackageResolverService`, `ApplicationInstallService`,
`AppUpgradeService`, `MarketplaceCatalogSyncService` |
| Cron jobs | `MarketplaceCatalogSyncCronJob` (hourly),
`AppVersionCheckCronJob` (every 6h) |
| REST endpoint | `AppRegistrationUploadController` — tarball upload
with secure extraction |
| Resolver | `MarketplaceResolver` — simplified `installMarketplaceApp`
(removed redundant `sourcePackage` arg) |
| Security | `.yarnrc.yml` — `enableScripts: false` to block postinstall
RCE |
## Frontend changes
| Area | Files |
|------|-------|
| Modals | `SettingsInstallNpmAppModal`, `SettingsUploadTarballModal`,
`SettingsAppModalLayout` |
| Hooks | `useUploadAppTarball`, `useInstallMarketplaceApp` (cleaned up)
|
| Upgrade UI | `SettingsApplicationVersionContainer`,
`SettingsApplicationDetailAboutTab` |
| Badge | `SettingsApplicationTableRow` — blue "Update" tag,
`SettingsApplicationsInstalledTab` — fetches registrations for version
comparison |
| Styling | Migrated to Linaria (matching main) |
## Test plan
- [ ] Install an app from npm via the "Install from npm" modal
- [ ] Upload a `.tar.gz` tarball via the "Upload tarball" modal
- [ ] Verify upgrade badge appears when `latestAvailableVersion >
version`
- [ ] Verify upgrade flow from app detail page
- [ ] Run integration tests: `app-distribution.integration-spec.ts`,
`marketplace-catalog-sync.integration-spec.ts`
- [ ] Verify `enableScripts: false` blocks postinstall scripts during
yarn install
Made with [Cursor](https://cursor.com)
2026-03-05 09:34:08 +00:00
|
|
|
import { MarketplaceModule } from 'src/engine/core-modules/application/application-marketplace/marketplace.module';
|
2026-02-04 12:30:55 +00:00
|
|
|
import { EventLogCleanupModule } from 'src/engine/core-modules/event-logs/cleanup/event-log-cleanup.module';
|
2025-07-23 12:57:16 +00:00
|
|
|
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
2025-07-15 06:57:10 +00:00
|
|
|
import { FileModule } from 'src/engine/core-modules/file/file.module';
|
2025-09-30 09:14:18 +00:00
|
|
|
import { PublicDomainModule } from 'src/engine/core-modules/public-domain/public-domain.module';
|
2025-10-22 07:55:20 +00:00
|
|
|
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
2025-09-30 09:14:18 +00:00
|
|
|
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
2024-07-09 15:48:10 +00:00
|
|
|
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
2024-08-05 16:19:19 +00:00
|
|
|
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
|
2024-07-09 15:48:10 +00:00
|
|
|
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
Fix user deletion flows (#15614)
**Before**
- any user with workpace_members permission was able to remove a user
from their workspace. This triggered the deletion of workspaceMember +
of userWorkspace, but did not delete the user (even if they had no
workspace left) nor the roleTarget (acts as junction between role and
userWorkspace) which was left with a userWorkspaceId pointing to
nothing. This is because roleTarget points to userWorkspaceId but the
foreign key constraint was not implemented
- any user could delete their own account. This triggered the deletion
of all their workspaceMembers, but not of their userWorkspace nor their
user nor the roleTarget --> we have orphaned userWorkspace, not
technically but product wise - a userWorkspace without a workspaceMember
does not make sense
So the problems are
- we have some roleTargets pointing to non-existing userWorkspaceId
(which caused https://github.com/twentyhq/twenty/issues/14608 )
- we have userWorkspaces that should not exist and that have no
workspaceMember counterpart
- it is not possible for a user to leave a workspace by themselves, they
can only leave all workspaces at once, except if they are being removed
from the workspace by another user
**Now**
- if a user has multiple workspaces, they are given the possibility to
leave one workspace while remaining in the others (we show two buttons:
Leave workspace and Delete account buttons). if a user has just one
workspace, they only see Delete account
- when a user leaves a workspace, we delete their workspaceMember,
userWorkspace and roleTarget. If they don't belong to any other
workspace we also soft-delete their user
- soft-deleted users get hard deleted after 30 days thanks to a cron
- we have two commands to clean the orphans roleTarget and userWorkspace
(TODO: query db to see how many must be run)
**Next**
- once the commands have been run, we can implement and introduce the
foreign key constraint on roleTarget
Fixes https://github.com/twentyhq/twenty/issues/14608
2025-11-06 18:29:12 +00:00
|
|
|
import { TrashCleanupModule } from 'src/engine/trash-cleanup/trash-cleanup.module';
|
2025-05-07 08:42:51 +00:00
|
|
|
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
Deprecate old relations completely (#12482)
# What
Fully deprecate old relations because we have one bug tied to it and it
make the codebase complex
# How I've made this PR:
1. remove metadata datasource (we only keep 'core') => this was causing
extra complexity in the refactor + flaky reset
2. merge dev and demo datasets => as I needed to update the tests which
is very painful, I don't want to do it twice
3. remove all code tied to RELATION_METADATA /
relation-metadata.resolver, or anything tied to the old relation system
4. Remove ONE_TO_ONE and MANY_TO_MANY that are not supported
5. fix impacts on the different areas : see functional testing below
# Functional testing
## Functional testing from the front-end:
1. Database Reset ✅
2. Sign In ✅
3. Workspace sign-up ✅
5. Browsing table / kanban / show ✅
6. Assigning a record in a one to many / in a many to one ✅
7. Deleting a record involved in a relation ✅ => broken but not tied to
this PR
8. "Add new" from relation picker ✅ => broken but not tied to this PR
9. Creating a Task / Note, Updating a Task / Note relations, Deleting a
Task / Note (from table, show page, right drawer) ✅ => broken but not
tied to this PR
10. creating a relation from settings (custom / standard x oneToMany /
manyToOne) ✅
11. updating a relation from settings should not be possible ✅
12. deleting a relation from settings (custom / standard x oneToMany /
manyToOne) ✅
13. Make sure timeline activity still work (relation were involved
there), espacially with Task / Note => to be double checked ✅ => Cannot
convert undefined or null to object
14. Workspace deletion / User deletion ✅
15. CSV Import should keep working ✅
16. Permissions: I have tested without permissions V2 as it's still hard
to test v2 work and it's not in prod yet ✅
17. Workflows global test ✅
## From the API:
1. Review open-api documentation (REST) ✅
2. Make sure REST Api are still able to fetch relations ==> won't do, we
have a coupling Get/Update/Create there, this requires refactoring
3. Make sure REST Api is still able to update / remove relation => won't
do same
## Automated tests
1. lint + typescript ✅
2. front unit tests: ✅
3. server unit tests 2 ✅
4. front stories: ✅
5. server integration: ✅
6. chromatic check : expected 0
7. e2e check : expected no more that current failures
## Remove // Todos
1. All are captured by functional tests above, nothing additional to do
## (Un)related regressions
1. Table loading state is not working anymore, we see the empty state
before table content
2. Filtering by Creator Tim Ap return empty results
3. Not possible to add Tasks / Notes / Files from show page
# Result
## New seeds that can be easily extended
<img width="1920" alt="image"
src="https://github.com/user-attachments/assets/d290d130-2a5f-44e6-b419-7e42a89eec4b"
/>
## -5k lines of code
## No more 'metadata' dataSource (we only have 'core)
## No more relationMetadata (I haven't drop the table yet it's not
referenced in the code anymore)
## We are ready to fix the 6 months lag between current API results and
our mocked tests
## No more bug on relation creation / deletion
---------
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-06-10 14:45:27 +00:00
|
|
|
import { DevSeederModule } from 'src/engine/workspace-manager/dev-seeder/dev-seeder.module';
|
2025-09-08 14:46:31 +00:00
|
|
|
import { WorkspaceCleanerModule } from 'src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module';
|
2024-07-09 15:48:10 +00:00
|
|
|
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
2026-01-08 15:45:12 +00:00
|
|
|
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
2025-06-23 19:05:01 +00:00
|
|
|
import { CalendarEventImportManagerModule } from 'src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module';
|
|
|
|
|
import { MessagingImportManagerModule } from 'src/modules/messaging/message-import-manager/messaging-import-manager.module';
|
2025-08-12 13:54:58 +00:00
|
|
|
import { WorkflowRunQueueModule } from 'src/modules/workflow/workflow-runner/workflow-run-queue/workflow-run-queue.module';
|
2025-06-23 19:05:01 +00:00
|
|
|
import { AutomatedTriggerModule } from 'src/modules/workflow/workflow-trigger/automated-trigger/automated-trigger.module';
|
2023-11-06 22:15:02 +00:00
|
|
|
|
|
|
|
|
@Module({
|
|
|
|
|
imports: [
|
2025-02-28 18:51:32 +00:00
|
|
|
UpgradeVersionCommandModule,
|
2025-10-22 07:55:20 +00:00
|
|
|
TypeOrmModule.forFeature([WorkspaceEntity]),
|
2025-06-23 19:05:01 +00:00
|
|
|
// Cron command dependencies
|
|
|
|
|
MessagingImportManagerModule,
|
|
|
|
|
CalendarEventImportManagerModule,
|
|
|
|
|
AutomatedTriggerModule,
|
2025-07-15 06:57:10 +00:00
|
|
|
FileModule,
|
2025-09-11 10:24:57 +00:00
|
|
|
WorkspaceModule,
|
2025-08-12 13:54:58 +00:00
|
|
|
WorkflowRunQueueModule,
|
2025-07-09 15:03:54 +00:00
|
|
|
// Data seeding dependencies
|
2025-02-28 18:51:32 +00:00
|
|
|
TypeORMModule,
|
|
|
|
|
FieldMetadataModule,
|
|
|
|
|
ObjectMetadataModule,
|
Deprecate old relations completely (#12482)
# What
Fully deprecate old relations because we have one bug tied to it and it
make the codebase complex
# How I've made this PR:
1. remove metadata datasource (we only keep 'core') => this was causing
extra complexity in the refactor + flaky reset
2. merge dev and demo datasets => as I needed to update the tests which
is very painful, I don't want to do it twice
3. remove all code tied to RELATION_METADATA /
relation-metadata.resolver, or anything tied to the old relation system
4. Remove ONE_TO_ONE and MANY_TO_MANY that are not supported
5. fix impacts on the different areas : see functional testing below
# Functional testing
## Functional testing from the front-end:
1. Database Reset ✅
2. Sign In ✅
3. Workspace sign-up ✅
5. Browsing table / kanban / show ✅
6. Assigning a record in a one to many / in a many to one ✅
7. Deleting a record involved in a relation ✅ => broken but not tied to
this PR
8. "Add new" from relation picker ✅ => broken but not tied to this PR
9. Creating a Task / Note, Updating a Task / Note relations, Deleting a
Task / Note (from table, show page, right drawer) ✅ => broken but not
tied to this PR
10. creating a relation from settings (custom / standard x oneToMany /
manyToOne) ✅
11. updating a relation from settings should not be possible ✅
12. deleting a relation from settings (custom / standard x oneToMany /
manyToOne) ✅
13. Make sure timeline activity still work (relation were involved
there), espacially with Task / Note => to be double checked ✅ => Cannot
convert undefined or null to object
14. Workspace deletion / User deletion ✅
15. CSV Import should keep working ✅
16. Permissions: I have tested without permissions V2 as it's still hard
to test v2 work and it's not in prod yet ✅
17. Workflows global test ✅
## From the API:
1. Review open-api documentation (REST) ✅
2. Make sure REST Api are still able to fetch relations ==> won't do, we
have a coupling Get/Update/Create there, this requires refactoring
3. Make sure REST Api is still able to update / remove relation => won't
do same
## Automated tests
1. lint + typescript ✅
2. front unit tests: ✅
3. server unit tests 2 ✅
4. front stories: ✅
5. server integration: ✅
6. chromatic check : expected 0
7. e2e check : expected no more that current failures
## Remove // Todos
1. All are captured by functional tests above, nothing additional to do
## (Un)related regressions
1. Table loading state is not working anymore, we see the empty state
before table content
2. Filtering by Creator Tim Ap return empty results
3. Not possible to add Tasks / Notes / Files from show page
# Result
## New seeds that can be easily extended
<img width="1920" alt="image"
src="https://github.com/user-attachments/assets/d290d130-2a5f-44e6-b419-7e42a89eec4b"
/>
## -5k lines of code
## No more 'metadata' dataSource (we only have 'core)
## No more relationMetadata (I haven't drop the table yet it's not
referenced in the code anymore)
## We are ready to fix the 6 months lag between current API results and
our mocked tests
## No more bug on relation creation / deletion
---------
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-06-10 14:45:27 +00:00
|
|
|
DevSeederModule,
|
2023-11-17 10:26:33 +00:00
|
|
|
WorkspaceManagerModule,
|
2023-11-10 14:33:25 +00:00
|
|
|
DataSourceModule,
|
2025-05-07 08:42:51 +00:00
|
|
|
WorkspaceCacheStorageModule,
|
2025-07-09 15:03:54 +00:00
|
|
|
ApiKeyModule,
|
2025-07-23 12:57:16 +00:00
|
|
|
FeatureFlagModule,
|
2025-09-08 14:46:31 +00:00
|
|
|
WorkspaceCleanerModule,
|
2026-01-08 15:45:12 +00:00
|
|
|
WorkspaceMigrationModule,
|
2025-10-14 16:49:40 +00:00
|
|
|
TrashCleanupModule,
|
2025-09-15 13:14:11 +00:00
|
|
|
PublicDomainModule,
|
2026-02-04 12:30:55 +00:00
|
|
|
EventLogCleanupModule,
|
feat: add npm and tarball app distribution with upgrade mechanism (#18358)
## Summary
- **npm + tarball app distribution**: Apps can be installed from the npm
registry (public or private) or uploaded as `.tar.gz` tarballs, with
`AppRegistrationSourceType` tracking the origin
- **Upgrade mechanism**: `AppUpgradeService` checks for newer versions,
supports rollback for npm-sourced apps, and a cron job runs every 6
hours to update `latestAvailableVersion` on registrations
- **Security hardening**: Tarball extraction uses path traversal
protection, and `enableScripts: false` in `.yarnrc.yml` disables all
lifecycle scripts during `yarn install` to prevent RCE
- **Frontend**: "Install from npm" and "Upload tarball" modals, upgrade
button on app detail page, blue "Update" badge on installed apps table
when a newer version is available
- **Marketplace catalog sync**: Hourly cron job syncs a hardcoded
catalog index into `ApplicationRegistration` entities
- **Integration tests**: Coverage for install, upgrade, tarball upload,
and catalog sync flows
## Backend changes
| Area | Files |
|------|-------|
| Entity & migration | `ApplicationRegistrationEntity` (sourceType,
sourcePackage, latestAvailableVersion), `ApplicationEntity`
(applicationRegistrationId), migration |
| Services | `AppPackageResolverService`, `ApplicationInstallService`,
`AppUpgradeService`, `MarketplaceCatalogSyncService` |
| Cron jobs | `MarketplaceCatalogSyncCronJob` (hourly),
`AppVersionCheckCronJob` (every 6h) |
| REST endpoint | `AppRegistrationUploadController` — tarball upload
with secure extraction |
| Resolver | `MarketplaceResolver` — simplified `installMarketplaceApp`
(removed redundant `sourcePackage` arg) |
| Security | `.yarnrc.yml` — `enableScripts: false` to block postinstall
RCE |
## Frontend changes
| Area | Files |
|------|-------|
| Modals | `SettingsInstallNpmAppModal`, `SettingsUploadTarballModal`,
`SettingsAppModalLayout` |
| Hooks | `useUploadAppTarball`, `useInstallMarketplaceApp` (cleaned up)
|
| Upgrade UI | `SettingsApplicationVersionContainer`,
`SettingsApplicationDetailAboutTab` |
| Badge | `SettingsApplicationTableRow` — blue "Update" tag,
`SettingsApplicationsInstalledTab` — fetches registrations for version
comparison |
| Styling | Migrated to Linaria (matching main) |
## Test plan
- [ ] Install an app from npm via the "Install from npm" modal
- [ ] Upload a `.tar.gz` tarball via the "Upload tarball" modal
- [ ] Verify upgrade badge appears when `latestAvailableVersion >
version`
- [ ] Verify upgrade flow from app detail page
- [ ] Run integration tests: `app-distribution.integration-spec.ts`,
`marketplace-catalog-sync.integration-spec.ts`
- [ ] Verify `enableScripts: false` blocks postinstall scripts during
yarn install
Made with [Cursor](https://cursor.com)
2026-03-05 09:34:08 +00:00
|
|
|
MarketplaceModule,
|
2026-03-06 07:45:08 +00:00
|
|
|
ApplicationUpgradeModule,
|
2023-12-02 17:37:45 +00:00
|
|
|
],
|
2025-06-23 19:05:01 +00:00
|
|
|
providers: [
|
|
|
|
|
DataSeedWorkspaceCommand,
|
|
|
|
|
ConfirmationQuestion,
|
|
|
|
|
CronRegisterAllCommand,
|
2026-01-06 12:36:53 +00:00
|
|
|
ListOrphanedWorkspaceEntitiesCommand,
|
2026-02-23 18:56:44 +00:00
|
|
|
GenerateApiKeyCommand,
|
2025-06-23 19:05:01 +00:00
|
|
|
],
|
2023-11-06 22:15:02 +00:00
|
|
|
})
|
|
|
|
|
export class DatabaseCommandModule {}
|