23cae2040a
App manifests could point the logo and screenshots at either external
URLs or public folder paths, and that was handled inconsistently across
install, sync and the marketplace.
This makes assets always bundled files:
- Manifests now use `logo` and `galleryImages` (a `string[]` of public
folder paths) instead of `logoUrl` and `screenshots`. The old fields
still work but are deprecated. Gallery order comes from the array index.
Normalization (deprecated-field migration, and warning about + ignoring
external URLs) happens in `defineApplication`, so the warnings surface
at define time.
- Logo is stored as a File record (`logoFileId`).
- The registration gallery is configured via a `settings` jsonb column
on `applicationRegistration` (`{ galleryImages: string[] }`) — populated
from the manifest, read by the marketplace detail (falling back to the
legacy `screenshots` column, then the manifest). No dedicated gallery
table.
- The marketplace detail DTO and front now use `galleryImages`.
Verified against a local Postgres: the fast instance commands run with
no pending-migration diff, the schema is correct, and the server boots.
Typecheck, lint, codegen and the application unit tests pass.
Not included yet: rehosting assets into storage for npm catalog and
tarball registrations, versioned cache busting on the serving route, and
a backfill for existing installs.
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22564?utm_source=github"
rel="nofollow noreferrer noopener" target="_blank">``<img alt="Review
in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg">``</a>
68 lines
3.0 KiB
Plaintext
68 lines
3.0 KiB
Plaintext
---
|
|
title: Public Assets
|
|
description: Ship static files — images, icons, fonts — alongside your app via the public/ folder.
|
|
icon: "folder-open"
|
|
---
|
|
|
|
The `public/` folder at the root of your app holds static files — images, icons, fonts, or any other assets your app needs at runtime. These files are automatically included in builds, synced during dev mode, and uploaded to the server.
|
|
|
|
Files placed in `public/` are:
|
|
|
|
- **Publicly accessible** — once synced to the server, assets are served at a public URL. No authentication is needed to access them.
|
|
- **Available in front components** — use asset URLs to display images, icons, or any media inside your React components.
|
|
- **Available in logic functions** — reference asset URLs in emails, API responses, or any server-side logic.
|
|
- **Used for marketplace metadata** — the `logo` and `galleryImages` fields in `defineApplication()` reference files from this folder (e.g., `public/logo.png`). These are displayed in the marketplace when your app is published. External absolute URLs are ignored for these fields — bundle the images in `public/` instead.
|
|
- **Auto-synced in dev mode** — when you add, update, or delete a file in `public/`, it is synced to the server automatically. No restart needed.
|
|
- **Included in builds** — `yarn twenty dev:build` bundles all public assets into the distribution output.
|
|
|
|
## Accessing public assets with `getPublicAssetUrl`
|
|
|
|
Use the `getPublicAssetUrl` helper from `twenty-sdk` to get the full URL of a file in your `public/` directory. It works in both **logic functions** and **front components**.
|
|
|
|
**In a logic function:**
|
|
|
|
```ts src/logic-functions/send-invoice.ts
|
|
import { defineLogicFunction } from 'twenty-sdk/define';
|
|
import { getPublicAssetUrl } from 'twenty-sdk/utils';
|
|
|
|
const handler = async (): Promise<any> => {
|
|
const logoUrl = getPublicAssetUrl('logo.png');
|
|
const invoiceUrl = getPublicAssetUrl('templates/invoice.png');
|
|
|
|
// Fetch the file content (no auth required — public endpoint)
|
|
const response = await fetch(invoiceUrl);
|
|
const buffer = await response.arrayBuffer();
|
|
|
|
return { logoUrl, size: buffer.byteLength };
|
|
};
|
|
|
|
export default defineLogicFunction({
|
|
universalIdentifier: 'a1b2c3d4-...',
|
|
name: 'send-invoice',
|
|
description: 'Sends an invoice with the app logo',
|
|
timeoutSeconds: 10,
|
|
handler,
|
|
});
|
|
```
|
|
|
|
**In a front component:**
|
|
|
|
```tsx src/front-components/company-card.tsx
|
|
import { defineFrontComponent } from 'twenty-sdk/define';
|
|
import { getPublicAssetUrl } from 'twenty-sdk/utils';
|
|
|
|
const CompanyCard = () => {
|
|
const logoUrl = getPublicAssetUrl('logo.png');
|
|
|
|
return <img src={logoUrl} alt="App logo" />;
|
|
};
|
|
|
|
export default defineFrontComponent({
|
|
universalIdentifier: '...',
|
|
name: 'company-card',
|
|
component: CompanyCard,
|
|
});
|
|
```
|
|
|
|
The `path` argument is relative to your app's `public/` folder. Both `getPublicAssetUrl('logo.png')` and `getPublicAssetUrl('public/logo.png')` resolve to the same URL — the `public/` prefix is stripped automatically if present.
|