Commit Graph
9 Commits
Author SHA1 Message Date
Paul RastoinandGitHub a735e3dfef Dirty fix twenty cli ci build order issue (#16024)
# Introduction
- fix twenty-apps hello world deps lockfile 
- improve error response format in application resolver
- fixed tests by adding applicationId back to serverless function
service v2

## New log format
We should have a tmp logs folder where we write the errors so the user
can see the whole of them such as what's done in yarn logs
```ts
    console.log
      ✓ Client generated successfully!

      at GenerateService.generateClient (src/services/generate.service.ts:58:13)

    console.log
      Generated files at: /Users/paulrastoin/ws/twenty/packages/twenty-apps/hello-world/generated

      at GenerateService.generateClient (src/services/generate.service.ts:59:13)

    console.error
       Serverless functions Sync failed: {
        message: 'Multiple validation errors occurred while creating serverless function',
        extensions: {
          code: 'METADATA_VALIDATION_FAILED',
          errors: {
            fieldMetadata: [],
            objectMetadata: [],
            view: [],
            viewField: [],
            viewGroup: [],
            index: [],
            serverlessFunction: [Array],
            cronTrigger: [],
            databaseEventTrigger: [],
            routeTrigger: [],
            viewFilter: []
          },
          summary: {
            invalidViewFilter: 0,
            invalidObjectMetadata: 0,
            invalidView: 0,
            invalidViewField: 0,
            invalidIndex: 0,
            invalidServerlessFunction: 0,
            invalidDatabaseEventTrigger: 0,
            invalidCronTrigger: 0,
            invalidRouteTrigger: 0,
            invalidFieldMetadata: 0,
            invalidViewGroup: 0,
            totalErrors: 0
          },
          message: 'Validation failed for 0 object(s) and 0 field(s)',
          userFriendlyMessage: 'Validation failed for 0 object(s) and 0 field(s)'
        }
      }

      63 |         JSON.stringify(serverlessSyncResult.error, null, 2),
      64 |       );
    > 65 |       console.error(
         |               ^
      66 |         chalk.red(' Serverless functions Sync failed:'),
      67 |         serverlessSyncResult.error,
      68 |       );

      at AppSyncCommand.synchronize (src/commands/app-sync.command.ts:65:15)
      at async AppSyncCommand.execute (src/commands/app-sync.command.ts:21:14)
      at async Object.<anonymous> (src/__tests__/e2e/applications-install-delete-reinstall.e2e-spec.ts:28:22)

```
2025-11-24 15:49:58 +00:00
martmullandGitHub aa5d30a911 Fix twenty cli (#15997)
As title

fixes "app add" and "app init" commands
adds tests
2025-11-21 19:21:30 +01:00
2a44bde848 Dynamic grql api wrapper on application sync (#15791)
# Introduction

Important note: for the moment testing this locally will require some
hack due to latest twenty-sdk not being published.
You will need to build twenty-cli and `cd packages/twenty-cli && yarn
link`
To finally sync the app in your app folder as `cd app-folder && twenty
app sync`

close https://github.com/twentyhq/core-team-issues/issues/1863

In this PR is introduced the generate sdk programmatic call to
[genql](https://genql.dev/) exposed in a `client` barrel of `twenty-sdk`
located in this package as there's high chances that will add a codegen
layer above it at some point ?

The cli calls this method after a sync application and writes a client
in a generated folder. It will make a graql introspection query on the
whole workspace. We should later improve that and only filter by current
applicationId and its dependencies ( when twenty-standard application is
introduced )

Fully typesafe ( input, output, filters etc ) auto-completed client

## Hello-world app serverless refactor

<img width="2480" height="1326" alt="image"
src="https://github.com/user-attachments/assets/b18ea372-b21d-4560-8fbc-1dc348427a95"
/>

---------

Co-authored-by: martmull <martmull@hotmail.fr>
2025-11-17 14:46:59 +01:00
martmullandGitHub 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',
   }
  ]
}

```
2025-10-29 16:51:43 +00:00
martmullandGitHub 7723fa70a4 Move schemas to constant folder (#15207)
- move schemas to constants
- increase npm package version
2025-10-20 15:41:53 +02:00
Paul RastoinandGitHub e91b0a4b15 [CLI-E2E-CI] Fix dependency graph (#15167)
# Introduction

Fixed the build dependency leading to twenty-server start failing before
building,
Removed redundant steps
Make everything run on test db
2025-10-17 13:17:48 +02:00
Paul RastoinandGitHub 7c661f47fd e2e test environment fortwenty-cli (#15123)
# Introduction
Defining very first basis of the twenty-cli e2e testing env.
Dynamically generating tests cases based on a list of applications names
that will be matched to stored twenty-apps and run install delete and
reinstall with their configuration on the same instance

We could use a glob pattern with a specific e2e configuration in every
apps but right now overkill

## Notes
- We should define typescript path aliasing to ease import devxp
- parse the config using a zod object

## Some vision on test granularity
Right now we only check that the server sent back success or failure on
below operation. In the future the synchronize will return a report of
what has been installed per entity exactly. We will be able to snapshot
everything in order to detect regressions

We should also be testing the cli directly for init and other stuff in
the end, we could get some inspiration from what's done in preconstruct
e2e tests with an on heap virtual file system

## Conclusion
Any suggestions are more than welcomed !
close https://github.com/twentyhq/core-team-issues/issues/1721
2025-10-16 12:43:43 +00:00
martmullandGitHub 0368d2a094 1574 extensibility twenty cli use workspace migration v2 to synchronize serverless function triggers (#14830)
twenty-cli serverless triggers follow up. Fixes:
- eventName don't support wildcard
- universalIdentifier not used to create or update trigger : update does
not work properly (does deletion then creation)
- add a base project in twenty-cli that is copied when creating a new
app
2025-10-02 14:06:56 +02:00
Félix MalfaitandGitHub 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
2025-09-10 15:12:38 +02:00