diff --git a/packages/twenty-front/src/modules/front-components/utils/__tests__/getFrontComponentUrl.test.ts b/packages/twenty-front/src/modules/front-components/utils/__tests__/getFrontComponentUrl.test.ts new file mode 100644 index 0000000000..53867c6e4b --- /dev/null +++ b/packages/twenty-front/src/modules/front-components/utils/__tests__/getFrontComponentUrl.test.ts @@ -0,0 +1,21 @@ +import { REST_API_BASE_URL } from '@/apollo/constant/rest-api-base-url'; +import { getFrontComponentUrl } from '@/front-components/utils/getFrontComponentUrl'; + +describe('getFrontComponentUrl', () => { + it('builds a checksum-fingerprinted path URL when a checksum is provided', () => { + expect( + getFrontComponentUrl({ + frontComponentId: 'front-component-id', + checksum: 'abc123', + }), + ).toBe( + `${REST_API_BASE_URL}/front-components/front-component-id/abc123.js`, + ); + }); + + it('falls back to the bare id URL when no checksum is provided', () => { + expect( + getFrontComponentUrl({ frontComponentId: 'front-component-id' }), + ).toBe(`${REST_API_BASE_URL}/front-components/front-component-id`); + }); +}); diff --git a/packages/twenty-front/src/modules/front-components/utils/getFrontComponentUrl.ts b/packages/twenty-front/src/modules/front-components/utils/getFrontComponentUrl.ts index a5afcfe5a2..891d9c59fd 100644 --- a/packages/twenty-front/src/modules/front-components/utils/getFrontComponentUrl.ts +++ b/packages/twenty-front/src/modules/front-components/utils/getFrontComponentUrl.ts @@ -9,6 +9,6 @@ export const getFrontComponentUrl = ({ checksum?: string; }): string => { return isDefined(checksum) - ? `${REST_API_BASE_URL}/front-components/${frontComponentId}?checksum=${checksum}` + ? `${REST_API_BASE_URL}/front-components/${frontComponentId}/${checksum}.js` : `${REST_API_BASE_URL}/front-components/${frontComponentId}`; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/front-component/controllers/front-component.controller.ts b/packages/twenty-server/src/engine/metadata-modules/front-component/controllers/front-component.controller.ts index 410493cac7..430ef15c29 100644 --- a/packages/twenty-server/src/engine/metadata-modules/front-component/controllers/front-component.controller.ts +++ b/packages/twenty-server/src/engine/metadata-modules/front-component/controllers/front-component.controller.ts @@ -46,7 +46,7 @@ export class FrontComponentController { constructor(private readonly frontComponentService: FrontComponentService) {} - @Get(':frontComponentId') + @Get([':frontComponentId', ':frontComponentId/:cacheKey']) @UseGuards(NoPermissionGuard) async getBuiltJs( @Res() res: Response, diff --git a/packages/twenty-server/test/integration/rest/suites/front-component-built-js.integration-spec.ts b/packages/twenty-server/test/integration/rest/suites/front-component-built-js.integration-spec.ts index 1d759b7443..c3d389cf04 100644 --- a/packages/twenty-server/test/integration/rest/suites/front-component-built-js.integration-spec.ts +++ b/packages/twenty-server/test/integration/rest/suites/front-component-built-js.integration-spec.ts @@ -55,6 +55,20 @@ describe('Front component built JS endpoint', () => { }); }); + it('should serve the built JS from the checksum-fingerprinted path with an immutable cache header', async () => { + await makeRestAPIRequest({ + method: 'get', + path: `/front-components/${frontComponentId}/test-checksum-123.js`, + bearer: APPLE_JANE_ADMIN_ACCESS_TOKEN, + }) + .expect(200) + .expect('Content-Type', /application\/javascript/) + .expect('Cache-Control', 'private, max-age=86400, immutable') + .expect((res) => { + expect(res.text).toBe('dummy built component content'); + }); + }); + it('should return 404 for a non-existent front component ID', async () => { const nonExistentId = '00000000-0000-0000-0000-000000000000';