e09b67158ec9fae9efcb3c4926c19081fdb0967d
20
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e09b67158e |
[HACKTOBERFEST] LINKEDIN EXTENSION (#15521)
# Twenty Browser Extension A Chrome browser extension for capturing LinkedIn profiles (people and companies) directly into Twenty CRM. This is a basic **v0** focused mostly on establishing a architectural foundation. ## Overview This extension integrates with LinkedIn to extract profile information and create records in Twenty CRM. It uses **WXT** as the framework - initially tried Plasmo, but found WXT to be significantly better due to its extensibility and closer alignment with the Chrome extension APIs, providing more control and flexibility. ## Architecture ### Package Structure The extension consists of two main packages: 1. **`twenty-browser-extension`** - The main extension package (WXT + React) 2. **`twenty-apps/browser-extension`** - Serverless functions for API interactions ### Extension Components #### Entrypoints - **Background Script** (`src/entrypoints/background/index.ts`) - Handles extension messaging protocol - Manages API calls to serverless functions - Coordinates communication between content scripts and popup - **Content Scripts** - **`add-person.content`** - Injects UI button on LinkedIn person profiles - **`add-company.content`** - Injects UI button on LinkedIn company profiles - Both scripts use WXT's `createIntegratedUi` for seamless DOM injection - Extract profile data from LinkedIn DOM - **Popup** (`src/entrypoints/popup/`) - React-based popup UI - Displays extracted profile information - Provides buttons to save person/company to Twenty #### Messaging System Uses `@webext-core/messaging` for type-safe communication between extension components: ```typescript // Defined in src/utils/messaging.ts - getPersonviaRelay() - Relays extraction from content script - getCompanyviaRelay() - Relays extraction from content script - extractPerson() - Extracts person data from LinkedIn DOM - extractCompany() - Extracts company data from LinkedIn DOM - createPerson() - Creates person record via serverless function - createCompany() - Creates company record via serverless function - openPopup() - Opens extension popup ``` #### Serverless Functions Located in `packages/twenty-apps/browser-extension/serverlessFunctions/`: - **`/s/create/person`** - Creates a new person record in Twenty - **`/s/create/company`** - Creates a new company record in Twenty - **`/s/get/person`** - Retrieves existing person record (placeholder) - **`/s/get/company`** - Retrieves existing company record (placeholder) ## Development Guide ### Prerequisites - Twenty CLI installed globally: `npm install -g twenty-cli` - API key from Twenty: https://twenty.com/settings/api-webhooks ### Setup ``` 1. **Configure environment variables:** - Set `TWENTY_API_URL` in the serverless function configuration - Set `TWENTY_API_KEY` (marked as secret) in the serverless function configuration - For local development, create a `.env` file or configure via `wxt.config.ts` ### Development Commands ```bash # Start development server with hot reload npx nx run dev twenty-browser-extension # Build for production npx nx run build twenty-browser-extension # Package extension for distribution npx nx run package twenty-browser-extension ``` ### Development Workflow 1. **Start the dev server:** ```bash npx nx run dev twenty-browser-extension ``` This starts WXT in development mode with hot module reloading. 2. **Load extension in Chrome:** - Navigate to `chrome://extensions/` - Enable "Developer mode" - Click "Load unpacked" - Select `packages/twenty-browser-extension/dist/chrome-mv3-dev/` 3. **Test on LinkedIn:** - Navigate to a LinkedIn person profile: `https://www.linkedin.com/in/...` - Navigate to a LinkedIn company profile: `https://www.linkedin.com/company/...` - The "Add to Twenty" button should appear in the profile header - Click the button to open the popup and save to Twenty ### Project Structure ``` packages/twenty-browser-extension/ ├── src/ │ ├── common/ │ │ └── constants/ # LinkedIn URL patterns │ ├── entrypoints/ │ │ ├── background/ # Background service worker │ │ ├── popup/ # Extension popup UI │ │ ├── add-person.content/ # Content script for person profiles │ │ └── add-company.content/ # Content script for company profiles │ ├── ui/ # Shared UI components and theme │ └── utils/ # Messaging utilities ├── public/ # Static assets (icons) ├── wxt.config.ts # WXT configuration └── project.json # Nx project configuration ``` ## Current Status (v0) This is a foundational version focused on architecture. Current features: ✅ Inject UI buttons into LinkedIn profiles ✅ Extract person and company data from LinkedIn ✅ Display extracted data in popup ✅ Create person records in Twenty ✅ Create company records in Twenty ## Planned Features - [ ] Provide a way to have API key and custom remote URLs. - [ ] Detect if record already exists and prevent duplicates - [ ] Open existing Twenty record when clicked (instead of creating duplicate) - [ ] Sidepanel Overlay UI for rich profile viewing/editing - [ ] Enhanced data extraction (email, phone, etc.) - [ ] Better error handling # Demo https://github.com/user-attachments/assets/0bbed724-a429-4af0-a0f1-fdad6997685e https://github.com/user-attachments/assets/85d2301d-19ee-43ba-b7f9-13ed3915f676 |
||
|
|
89c8d89330 |
Revert "Revert "[hacktoberfest] feat: add fireflies"" (#15595)
Reverts twentyhq/twenty#15589 Add back without the breaking change |
||
|
|
281070423f |
Revert "[hacktoberfest] feat: add fireflies" (#15589)
Reverts twentyhq/twenty#15527 due to tsconfig base update |
||
|
|
ad80a50354 |
feat: add Webmetic Visitor Intelligence (#15551)
# Webmetic Visitor Intelligence Automatically sync B2B website visitor data into Twenty CRM. Identify anonymous companies visiting your website and track their engagement without forms or manual entry. Every hour, Webmetic enriches your CRM with actionable sales intelligence about who's researching your product before they ever fill out a contact form. ## Features - 🔄 **Hourly Automatic Sync**: Fetches visitor data every hour via cron trigger - 🏢 **Company Enrichment**: Creates and updates company records with visitor intelligence - 📊 **Website Lead Tracking**: Records individual visits with detailed engagement metrics - 📈 **Engagement Scoring**: Webmetic's proprietary scoring algorithm (0-100) identifies warm leads - 🎯 **Sales Intelligence**: See which companies are actively researching your product - 🌍 **Geographic Data**: Captures visitor city and country information - 🔗 **UTM Parameter Tracking**: Full campaign attribution with utm_source, utm_medium, utm_campaign, utm_term, and utm_content - 📄 **Page Journey Mapping**: Records complete navigation paths and scroll depth - ⚡ **Smart Deduplication**: Prevents duplicate records using session-based identification - 🔐 **Production-Ready**: Built with rate limiting, error handling, and idempotent operations ## Requirements - `twenty-cli` — `npm install -g twenty-cli` - A Twenty API key (create one at `https://twenty.com/settings/api-webhooks` and name it **"Webmetic"**) - A Webmetic account with API access. Sign up at [webmetic.de](https://webmetic.de) - Node 18+ (for local development) ## Metadata prerequisites The app automatically creates the `websiteLead` custom object with all required fields on first run. No manual field provisioning is needed. **Created automatically:** - `websiteLead` object with 14 custom fields (TEXT, NUMBER, DATE_TIME types) - Company relation field (Many-to-One from websiteLead to Company) - All fields are idempotent — safe to re-run without errors ## Quick start ### 1. Deploy the app ```bash twenty auth login cd packages/twenty-apps/webmetic twenty app sync ``` ### 2. Configure environment variables - **First, create a Twenty API key**: - Go to **Settings → API & Webhooks → API Keys** - Click **+ Create API Key** - Name it **"Webmetic"** - Copy the generated key - **Then configure the app**: - Open **Settings → Apps → Webmetic Visitor Intelligence → Configuration** - Provide values for the required keys: - `TWENTY_API_KEY` (required secret; paste the API key you just created) - `TWENTY_API_URL` (optional; defaults to `http://localhost:3000` for local dev, set to your production URL) - `WEBMETIC_API_KEY` (required secret; get from [app.webmetic.de/?menu=api_details](https://app.webmetic.de/?menu=api_details)) - `WEBMETIC_DOMAIN` (required; your website domain to track, e.g., `example.com`) - Save the configuration ### 3. Test the function - On the app page, select **Test your function** - Click **Run** - You should see a success summary showing companies and leads created - Check **Settings → Data Model → Website Leads** to verify the custom object was created - Navigate to **Website Leads** from the sidebar to view synced visitor data ### 4. Automatic hourly sync begins The cron trigger (`0 * * * *`) runs every hour on the hour, continuously syncing new visitor data. ## How it works ### Data flow ``` Webmetic API ─[hourly]→ sync-visitor-data ─[create/update]→ Twenty CRM │ ├─→ Company records (with enrichment data) └─→ Website Lead records (linked to companies) ``` ### Sync process 1. **Cron Trigger**: Every hour at :00 (e.g., 1:00, 2:00, 3:00) 2. **Schema Validation**: Ensures `websiteLead` object and all fields exist (creates if missing) 3. **Fetch Visitors**: Queries Webmetic API `/company-sessions` endpoint for last hour 4. **Process Companies**: For each visitor's company: - Searches for existing company by domain - Creates new company or updates existing with latest data from Webmetic - Extracts employee count from ranges (e.g., "11-50" → 50) 5. **Create Website Leads**: For each session: - Checks for duplicate (by name: "Company - Date") - Creates lead record with engagement metrics - Links to company via relation field 6. **Rate Limiting**: 800ms delay between API calls (75 requests/minute max) ### Data captured **Company enrichment (from Webmetic):** - Name, domain, address (street, city, postcode, country) - Employee count (parsed from ranges) - LinkedIn URL (if available) - Tagline/short description **Website Lead tracking:** - Visit date and session duration - Page views count and pages visited (full navigation path) - Traffic source (Direct, or utm_source/utm_medium combination) - UTM campaign parameters (campaign, term, content) - Visitor location (city, country) - Engagement score (Webmetic's 0-100 scoring) - Average scroll depth percentage - Total user interaction events (clicks, etc.) ## Configuration reference | Variable | Required | Description | |----------|----------|-------------| | `TWENTY_API_KEY` | ✅ Yes | Your Twenty API key for authentication | | `TWENTY_API_URL` | ❌ No | Base URL of your Twenty instance (defaults to `http://localhost:3000`) | | `WEBMETIC_API_KEY` | ✅ Yes | Your Webmetic API key from [app.webmetic.de/?menu=api_details](https://app.webmetic.de/?menu=api_details) | | `WEBMETIC_DOMAIN` | ✅ Yes | Website domain to track (e.g., `example.com` without protocol) | ## API integration This app uses multiple Twenty CRM APIs: **REST API** (data operations): - `GET /rest/metadata/objects` — Fetch object metadata with fields - `GET /rest/companies` — Find existing companies by domain - `POST /rest/companies` — Create new companies - `PATCH /rest/companies/:id` — Update company data - `POST /rest/websiteLeads` — Create website lead records **GraphQL Metadata API** (schema management): - `createOneObject` mutation — Creates custom objects (if needed) - `createOneField` mutation — Creates custom fields and relations ## Website Lead object structure The app creates a custom `websiteLead` object with the following fields: | Field | Type | Description | |-------|------|-------------| | `name` | TEXT | Lead identifier (Company Name - Date) | | `company` | RELATION | Many-to-One relation to Company object | | `visitDate` | DATE_TIME | When the visit occurred | | `pageViews` | NUMBER | Number of pages viewed during session | | `sessionDuration` | NUMBER | Visit length in seconds | | `trafficSource` | TEXT | Where visitor came from (utm_source/utm_medium or Direct) | | `pagesVisited` | TEXT | List of page URLs visited (→ separated, max 1000 chars) | | `utmCampaign` | TEXT | UTM campaign parameter | | `utmTerm` | TEXT | UTM term parameter (keywords for paid search) | | `utmContent` | TEXT | UTM content parameter (for A/B testing) | | `visitorCity` | TEXT | Geographic city of visitor | | `visitorCountry` | TEXT | Geographic country of visitor | | `visitCount` | NUMBER | Total number of visits from this company | | `engagementScore` | NUMBER | Webmetic engagement score (0-100) | | `averageScrollDepth` | NUMBER | Average scroll percentage (0-100) | | `totalUserEvents` | NUMBER | Total count of user interactions (clicks, etc.) | ## Troubleshooting **Issue**: No data syncing after setup - **Solution**: Run "Test your function" to manually trigger a sync and check logs. Verify your `WEBMETIC_API_KEY` and `WEBMETIC_DOMAIN` are correct. **Issue**: "Duplicate Domain Name" error - **Solution**: This occurs if you previously deleted a company. Twenty maintains unique constraints on soft-deleted records. Either restore the company from trash or contact support. **Issue**: Missing fields on websiteLead object - **Solution**: The sync function recreates missing fields automatically. Run "Test your function" once to repair the schema. **Issue**: Empty linkedinLink on companies - **Solution**: Webmetic doesn't have LinkedIn data for that specific company. The mapping is working correctly; data availability depends on Webmetic's enrichment coverage. **Issue**: Employee count not matching Webmetic - **Solution**: Webmetic returns ranges (e.g., "11-50"). The app uses the maximum value (50) to better represent company size. **Issue**: Test shows "No new visitors in the last hour" - **Solution**: Normal if you have no traffic in the last 60 minutes. Wait for actual traffic or manually adjust the time range in code for testing. ## Rate limiting and performance - **Webmetic API**: No pagination used; fetches all visitors from last hour - **Twenty API**: 800ms delay between requests (75 requests/minute) - **Processing**: Handles 14+ companies with full enrichment in under 30 seconds - **Cron schedule**: `0 * * * *` (every hour on the hour) - **Duplicate prevention**: Checks existing leads by name before creating ## Development ### Local testing ```bash cd packages/twenty-apps/webmetic yarn install # Set up .env file cp .env.example .env # Edit .env with your credentials # Sync to local Twenty instance npx twenty-cli app sync # Watch for changes npx twenty-cli app dev ``` ### Manual trigger Use the Twenty UI test panel or trigger via API: ```bash curl -X POST http://localhost:3000/functions/sync-visitor-data \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Architecture notes - **100% programmatic schema**: Fields created via GraphQL Metadata API, not manifests - **Idempotent operations**: Safe to re-run without duplicates or errors - **Smart domain matching**: Normalizes domains (strips www, protocols) for matching - **Error resilience**: Individual company failures don't stop the entire sync - **Detailed logging**: Returns full execution log in response for debugging ## Contributing Built with 🍺 and ❤️ in Munich by [Team Webmetic](https://webmetic.de) for Twenty CRM Hacktoberfest 2025. For issues or questions: - Webmetic API: [webmetic.de](https://webmetic.de) - Twenty CRM: [twenty.com/developers](https://twenty.com/developers) ## License MIT |
||
|
|
995f5b3b3f | [hacktoberfest] feat: add fireflies (#15527) | ||
|
|
6065fa61c7 |
Stripe synchronizer extension (#15515)
Challenge 7 from "Call for projects" list |
||
|
|
ff1a87080a |
Mailchimp synchronizer extension (#15512)
Challenge 10 from "Call for projects" list |
||
|
|
e4dbe87fa1 |
Last email interaction extension (#15511)
Challenge 4 from "Call for projects" list |
||
|
|
1957f839ff |
[HACKTOBERFEST] [FEATURE] Create activity summary application (#15510)
## Background This is team Comfortably Summed's submission for Twenty's Hacktoberfest. We built an activity summary application that can periodically send messages to the following platforms: Slack; Discord; and WhatsApp. ### Features - 🧑💻 **People & Company Tracking**: Summarizes newly created people and companies - 🎯 **Opportunity Monitoring**: Reports on new opportunities created, broken down by stage - ✅ **Task Analytics**: - Tracks task creation - Calculates on-time completion rates - Identifies team members with the most overdue tasks (the "slackers") - 🔔 **Multi-Platform Notifications**: Send reports to Slack, Discord, and/or WhatsApp - ⏰ **Configurable Time Range**: Look back any number of days ### Summary of Changes - Adds a new Twenty app called Activity Summary - Contains a single index.ts file which utilises exported functions from opportunity-creation-summariser.ts, people-creation-summariser.ts, task-creation-summariser.ts, and senders.ts - Implementation of sending a message to Slack, Discord, and WhatsApp can be found in senders.ts - Retrieval and summarising of Opportunity creation can be found in opportunity-creation-summariser.ts - Retrieval and summarising of People creation can be found in people-creation-summariser.ts - Retrieval and summarising of Task creation can be found in task-creation-summariser.ts ## Screenshots ### Message to our Slack channel <details> <summary>Screenshot</summary> <img width="326" height="242" alt="Screenshot 2025-11-01 at 22 05 30" src="https://github.com/user-attachments/assets/57c5d50b-959d-4c3f-bd7d-00f42bf545b2" /> </details> ### Message to our Discord server's channel <details> <summary>Screenshot</summary> <img width="472" height="386" alt="Screenshot 2025-11-01 at 22 06 44" src="https://github.com/user-attachments/assets/f4a38d7f-e82d-47b0-a4b3-7bcf063fa575" /> </details> ### Message to our WhatsApp number <details> <summary>Screenshot</summary> <img width="972" height="548" alt="IMG_2024" src="https://github.com/user-attachments/assets/5533fc4d-a3ee-4e11-a9e7-9cc6a96316fc" /> </details> ### App-level configuration <details> <summary>Screenshot</summary> <img width="442" height="385" alt="Screenshot 2025-11-01 at 22 02 14" src="https://github.com/user-attachments/assets/c9948f57-f22c-42a0-972f-3348f480aa30" /> </details> ### Serverless functions <details> <summary>Screenshot</summary> <img width="413" height="378" alt="Screenshot 2025-11-01 at 22 03 48" src="https://github.com/user-attachments/assets/d297967b-52ce-4690-bb04-a16d89729d94" /> </details> ### Cron configuration Default value in place due to Cron having a non-editable text input. <details> <summary>Screenshot</summary> <img width="395" height="386" alt="Screenshot 2025-11-01 at 22 08 03" src="https://github.com/user-attachments/assets/a95a708c-7136-4512-99c3-a6723adc0da5" /> </details> ## Testing Sync the application to your Twenty instance and ensure the following variables have values: - `TWENTY_API_KEY` - Your Twenty CRM API key - `DAYS_AGO` - Number of days to look back for the report Choose any of the supported platforms and you shall see a summary being sent! |
||
|
|
7f3af243c7 |
[Hacktoberfest] AI-Powered Meeting Transcript Analysis Extension for Twenty CRM (#15507)
# 🧠 AI-Powered Meeting Transcript to CRM Data Integration ## **Overview** This feature automatically transforms meeting transcripts into structured CRM data using AI. When unstructured meeting notes are received via a **webhook**, the system processes them and creates organized **notes, tasks, and assignments** directly in **Twenty CRM**. --- ## **Key Features** - **🤖 AI-Powered Analysis:** Extracts **summaries, action items, assignees, and due dates** from natural language transcripts. - **📋 Smart Task Consolidation:** Merges related sub-tasks into unified deliverables *(e.g., `"draft" + "review" + "present"` → one consolidated task).* - **👥 Intelligent Assignment:** Uses **GraphQL member lookup** to match extracted assignee names to workspace member IDs with flexible string matching. - **🔗 Automatic Linking:** Links generated **notes and tasks** to relevant contacts using `noteTargets` and `taskTargets`. - **🗓️ Date Parsing:** Converts **relative date expressions** (e.g., “next Monday”, “end of week”) into **ISO-formatted dates** for accurate scheduling. --- ## **Technical Stack** | Component | Description | |------------|-------------| | **AI Provider** | Groq (via OpenAI SDK) using the `GPT-OSS-20B` model | | **APIs** | Twenty CRM REST API + GraphQL (for member resolution) | | **Runtime** | Webhook-triggered **serverless function** written in **TypeScript** | --- ## **Example Input** ```json { "transcript": "During the Project Phoenix Kick-off on November 1st, 2025, we discussed securing the Series B funding. ACTION: Dylan Field is designated to finalize the investor deck layout and needs to present it next Monday, November 4th. Irfan Hussain will review the deck before the presentation by Monday morning. COMMITMENT: Dario Amodei confirmed he would personally review the security protocols for the AI model before the end of this week, by Friday November 7th. Iqra Khan will coordinate the security review process and ensure completion by the Friday deadline.", "meetingTitle": "Project Phoenix Kick-off", "meetingDate": "2025-11-01", "participants": [ "Brian Chesky", "Dario Amodei", "Iqra Khan", "Irfan Hussain", "Dylan Field" ], "token": "e6d9d54e51953fd5a451cca933c63e7f8783b001f0c45be95be9d09ee06c6cda", "relatedPersonId": "6c4b0e98-b69e-42a4-ba0c-fd2eeafca642" } ``` --- ## **Example Output** ```json { "success": true, "noteId": "9cc3b4fc-ae37-4b3e-a343-a4c69cf6b1e8", "taskIds": [ "0f408062-0dcc-49f0-9866-1ea05392661d", "2b3739bf-0653-4101-9419-6a44ea5135cd" ], "summary": { "noteCreated": true, "tasksCreated": 2, "actionItemsProcessed": 2, "commitmentsProcessed": 0 }, "executionLogs": [ "✅ Validation passed", "📝 RelatedPersonId: 6c4b0e98-b69e-42a4-ba0c-fd2eeafca642", "🤖 Starting transcript analysis...", "✅ Analysis complete: 2 action items, 0 commitments", "📄 Creating note in Twenty CRM...", "✅ Note created: 9cc3b4fc-ae37-4b3e-a343-a4c69cf6b1e8", "📋 Creating tasks from action items...", "✅ Action item tasks created: 2", "📋 Creating tasks from commitments...", "✅ Commitment tasks created: 0" ] } ``` --- Variable Name | Description -- | -- GROQ_API_KEY | API key for authenticating requests to the Groq AI service. TWENTY_API_KEY | Authentication token used to access the Twenty CRM API. TWENTY_API_URL | Base URL for the Twenty CRM REST API. WEBHOOK_SECRET | Secret key used to validate incoming webhook requests for security. NODE_ENV | Defines the runtime environment (development, production, etc.). LOG_LEVEL | Controls verbosity of logs (info, debug, error). --- ## **Attachments** <img width="649" height="863" alt="swappy-20251103-035128" src="https://github.com/user-attachments/assets/2f0390af-9538-4fe2-bba8-f38e558935ad" /> --- https://github.com/user-attachments/assets/88620035-67ed-4150-b0be-46131083e2c5 --- Co-authored-by: iqra77818 <iqra77818@gmail.com> |
||
|
|
0cdc61c211 |
[HACKTOBERFEST] feat: Add AI meeting transcript integration with Twenty CRM (#15498)
This PR introduces an end-to-end workflow to automatically process meeting transcripts and create structured notes and tasks in Twenty CRM. It leverages OpenAI to extract summaries, key points, action items, and participant commitments from transcripts. Key features include: 1. AI-powered transcript analysis: Uses OpenAI GPT‑4o-mini to extract a concise summary, key discussion points, action items, and commitments. 2. Automated note creation: Generates a rich Markdown note in Twenty CRM with summary and key points. 3. Task automation: Automatically creates tasks in Twenty CRM from extracted action items and commitments, linking them to the meeting note. 4. Custom field support: Supports optional metadata from transcript payloads, which can be included in note/task content or mapped to custom fields in Twenty CRM if supported. 5. Webhook-ready: Designed to process Granola-style (or similar) webhook payloads, making it easy to integrate with any AI meeting tool. Sumbission for Hacktoberfest Team Name : One for All |
||
|
|
7ec56433c7 |
[HACKTOBERFEST] Add rollup engine app with UI-driven configuration (#15482)
## Summary
- add packages/twenty-apps/rollup-engine: a parameterised rollup engine
that ships a default Opportunity → Company
aggregation.
- declare runtime config in package.json (TWENTY_API_KEY, optional
TWENTY_API_BASE_URL, and ROLLUP_ENGINE_CONFIG) so
app configuration lives entirely in Settings → Apps → [App] →
Configuration.
- document the workflow in README.md: deploy via twenty app sync,
populate env vars in the UI, use the Test panel with
a ready JSON payload, and reference troubleshooting tips.
- adjust the function entry point to a named async export and add
fallback logic for blank base URLs, matching the
UI’s env behaviour.
- prune legacy templates and examples so
config/templates/opportunity-to-company.json is the single copy/paste
starting point.
## UI / UX impact
After syncing the app:
- the Configuration screen shows the three env keys with helpful
descriptions (API key, optional base URL, JSON
override),
- the built-in Test your function panel works immediately
- and the default JSON config is available from
config/templates/opportunity-to-company.json for users who need to
customise rollups.
## Testing
- Out-of-the-box deploy to the hosted workspace (Opportunity update) ✓
- “Test your function” with the default config ✓
- Override example: point debugOpportunityCount at a scratch field via
ROLLUP_ENGINE_CONFIG ✓
- Optional: local smoke test (yarn install && yarn smoke) still passes
|
||
|
|
a6cc80eedd |
1751 extensibility twenty sdk v2 use twenty sdk to define a serverless function trigger (#15347)
This PR adds 2 columns handlerPath and handlerName in serverlessFunction
to locate the entrypoint of a serverless in a codebase
It adds the following decorators in twenty-sdk:
- ServerlessFunction
- DatabaseEventTrigger
- RouteTrigger
- CronTrigger
- ApplicationVariable
It still supports deprecated entity.manifest.jsonc
Overall code needs to be cleaned a little bit, but it should work
properly so you can try to test if the DEVX fits your needs
See updates in hello-world application
```typescript
import axios from 'axios';
import {
DatabaseEventTrigger,
ServerlessFunction,
RouteTrigger,
CronTrigger,
ApplicationVariable,
} from 'twenty-sdk';
@ApplicationVariable({
universalIdentifier: 'dedc53eb-9c12-4fe2-ba86-4a2add19d305',
key: 'TWENTY_API_KEY',
description: 'Twenty API Key',
isSecret: true,
})
@DatabaseEventTrigger({
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
eventName: 'person.created',
})
@RouteTrigger({
universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6',
path: '/post-card/create',
httpMethod: 'GET',
isAuthRequired: false,
})
@CronTrigger({
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
pattern: '0 0 1 1 *', // Every year 1st of January
})
@ServerlessFunction({
universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
})
class CreateNewPostCard {
main = async (params: { recipient: string }): Promise<string> => {
const { recipient } = params;
const options = {
method: 'POST',
url: 'http://localhost:3000/rest/postCards',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.TWENTY_API_KEY}`,
},
data: { name: recipient ?? 'Unknown' },
};
try {
const { data } = await axios.request(options);
console.log(`New post card to "${recipient}" created`);
return data;
} catch (error) {
console.error(error);
throw error;
}
};
}
export const createNewPostCardHandler = new CreateNewPostCard().main;
```
### [edit] V2
After the v1 proposal, I see that using a class method to define the
serverless function handler is pretty confusing. Lets leave
serverlessFunction configuration decorators on the class, but move the
handler like before. Here is the v2 hello-world serverless function:
```typescript
import axios from 'axios';
import {
DatabaseEventTrigger,
ServerlessFunction,
RouteTrigger,
CronTrigger,
ApplicationVariable,
} from 'twenty-sdk';
@ApplicationVariable({
universalIdentifier: 'dedc53eb-9c12-4fe2-ba86-4a2add19d305',
key: 'TWENTY_API_KEY',
description: 'Twenty API Key',
isSecret: true,
})
@DatabaseEventTrigger({
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
eventName: 'person.created',
})
@RouteTrigger({
universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6',
path: '/post-card/create',
httpMethod: 'GET',
isAuthRequired: false,
})
@CronTrigger({
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
pattern: '0 0 1 1 *', // Every year 1st of January
})
@ServerlessFunction({
universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
})
export class ServerlessFunctionDefinition {}
export const main = async (params: { recipient: string }): Promise<string> => {
const { recipient } = params;
const options = {
method: 'POST',
url: 'http://localhost:3000/rest/postCards',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.TWENTY_API_KEY}`,
},
data: { name: recipient ?? 'Unknown' },
};
try {
const { data } = await axios.request(options);
console.log(`New post card to "${recipient}" created`);
return data;
} catch (error) {
console.error(error);
throw error;
}
};
```
### [edit] V3
After the v2 proposal, we don't really like decorators on empty classes.
We decided to go with a Vercel approach with a config constant
```typescript
import axios from 'axios';
import { ServerlessFunctionConfig } from 'twenty-sdk';
export const main = async (params: { recipient: string }): Promise<string> => {
const { recipient } = params;
const options = {
method: 'POST',
url: 'http://localhost:3000/rest/postCards',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.TWENTY_API_KEY}`,
},
data: { name: recipient ?? 'Unknown' },
};
try {
const { data } = await axios.request(options);
console.log(`New post card to "${recipient}" created`);
return data;
} catch (error) {
console.error(error);
throw error;
}
};
export const config: ServerlessFunctionConfig = {
universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
routeTriggers: [
{
universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6',
path: '/post-card/create',
httpMethod: 'GET',
isAuthRequired: false,
}
],
cronTriggers: [
{
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
pattern: '0 0 1 1 *', // Every year 1st of January
}
],
databaseEventTriggers: [
{
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
eventName: 'person.created',
}
]
}
```
|
||
|
|
033c28a3d5 |
1750 extensibility twenty sdk v2 use twenty sdk to define an object (#15230)
We maintain jsonc object definition but will deprecate them pretty soon ## Before <img width="1512" height="575" alt="image" src="https://github.com/user-attachments/assets/d2fa6ca4-c456-4aa9-a1e3-845b61839718" /> ## After <img width="1260" height="555" alt="image" src="https://github.com/user-attachments/assets/ba72f4cf-d443-4967-913c-029bc71f3f48" /> |
||
|
|
5186e73ce1 |
Add .env.example in hello-world app (#15211)
as title |
||
|
|
d2e7f2a910 |
1635 extensibilitytwenty cli app vars (#15143)
- Update twenty-cli to support application env variable definition - Update twenty-server to create a new `core.applicationVariable` entity to store env variables and provide env var when executing serverless function - Update twenty-front to support application environment variable value setting <img width="1044" height="660" alt="image" src="https://github.com/user-attachments/assets/24c3d323-5370-4a80-8174-fc4653cc3c22" /> <img width="1178" height="662" alt="image" src="https://github.com/user-attachments/assets/c124f423-8ed8-4246-ae5b-a9bd6672c7dc" /> <img width="1163" height="823" alt="image" src="https://github.com/user-attachments/assets/fb7425a3-facc-4895-a5eb-8a8e278e0951" /> <img width="1087" height="696" alt="image" src="https://github.com/user-attachments/assets/113da8a2-5590-433c-b1b3-5ed3137f24ca" /> <img width="1512" height="715" alt="image" src="https://github.com/user-attachments/assets/1d2110b7-301d-4f21-a45c-ddd54d6e3391" /> <img width="1287" height="581" alt="image" src="https://github.com/user-attachments/assets/353b16c6-0527-444c-87d6-51447a96cbc7" /> |
||
|
|
f6240fabd0 |
Fix hello world application (#14880)
Updates of the hello-world application - remove the old hello-world application - adds an object "postCard" - adds a serverlessFunction `create-new-post-card` that calls the twenty api to create a new postCard record - add a route trigger /post-card/create?recipient=John |
||
|
|
5105b4284e |
Remove twenty-app.jsonc (#14662)
As title, use package.json instead of twenty-app.jsonc |
||
|
|
e8121919bd |
Remove twenty-apps irrelevant stuff (#14649)
As title twenty-apps is the public repository for public twenty applications. One small hello-world application is registered here, will be useful for development |
||
|
|
30a2164980 |
First Application POC (#14382)
Quick proof of concept for twenty-apps + twenty-cli, with local development / hot reload Let's discuss it! https://github.com/user-attachments/assets/c6789936-cd5f-4110-a265-863a6ac1af2d |