e289f3056e
- moves applicationRoleId to application entity - add new `APPLICATION` FieldActorSource and `APPLICATION` JwtTokenTypeEnum value - create a new token with applicationId when executing a function - when applicationId is in token, check for application.defaultRole permissions -use twenty-shared types in `twenty-sdk/application` - create a new import from generate called "Twenty" that you can use directly without having to set TWENTY_API_KEY AND TWENTY_API_URL (keep metadata or core parameter only) - provide to serverless unique one time BEARER TOKEN to run it Result <img width="977" height="566" alt="image" src="https://github.com/user-attachments/assets/e78428a0-5b13-4975-aa13-58ee3b32450c" /> <img width="910" height="596" alt="image" src="https://github.com/user-attachments/assets/6ec72bf5-7655-4093-a45e-ad269595a324" /> <img width="741" height="568" alt="image" src="https://github.com/user-attachments/assets/7683944c-fd79-4417-8fb2-8e4815cc112f" />
117 lines
2.9 KiB
TypeScript
117 lines
2.9 KiB
TypeScript
import { generate } from '@genql/cli';
|
|
import chalk from 'chalk';
|
|
import { join, resolve } from 'path';
|
|
import { ApiService } from '@/cli/services/api.service';
|
|
import { ConfigService } from '@/cli/services/config.service';
|
|
import * as fs from 'fs-extra';
|
|
import {
|
|
DEFAULT_API_URL_NAME,
|
|
DEFAULT_API_KEY_NAME,
|
|
} from 'twenty-shared/application';
|
|
|
|
export const GENERATED_FOLDER_NAME = 'generated';
|
|
|
|
export class GenerateService {
|
|
private configService: ConfigService;
|
|
private apiService: ApiService;
|
|
|
|
constructor() {
|
|
this.configService = new ConfigService();
|
|
this.apiService = new ApiService();
|
|
}
|
|
|
|
async generateClient(appPath: string): Promise<void> {
|
|
const outputPath = join(appPath, GENERATED_FOLDER_NAME);
|
|
|
|
console.log(chalk.blue('📦 Generating Twenty client...'));
|
|
console.log(chalk.gray(`📁 Output Path: ${outputPath}`));
|
|
console.log('');
|
|
const config = await this.configService.getConfig();
|
|
|
|
const url = config.apiUrl;
|
|
const token = config.apiKey;
|
|
|
|
if (!url || !token) {
|
|
console.log(
|
|
chalk.yellow(
|
|
'⚠️ Skipping Client generation: API URL or token not configured',
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
console.log(chalk.gray(`API URL: ${url}`));
|
|
console.log(chalk.gray(`Output: ${outputPath}`));
|
|
|
|
const getSchemaResponse = await this.apiService.getSchema();
|
|
|
|
if (!getSchemaResponse.success) {
|
|
return;
|
|
}
|
|
|
|
const { data: schema } = getSchemaResponse;
|
|
|
|
const output = resolve(outputPath);
|
|
|
|
await generate({
|
|
schema,
|
|
output,
|
|
scalarTypes: {
|
|
DateTime: 'string',
|
|
JSON: 'Record<string, unknown>',
|
|
UUID: 'string',
|
|
},
|
|
});
|
|
|
|
await this.injectTwentyClient(output);
|
|
|
|
console.log(chalk.green('✓ Client generated successfully!'));
|
|
console.log(chalk.gray(`Generated files at: ${outputPath}`));
|
|
}
|
|
|
|
private async injectTwentyClient(output: string) {
|
|
const twentyClientContent = `
|
|
|
|
// ----------------------------------------------------
|
|
// ✨ Custom Twenty client (auto-injected)
|
|
// ----------------------------------------------------
|
|
|
|
const defaultOptions: ClientOptions = {
|
|
url: \`\${process.env.${DEFAULT_API_URL_NAME}}/graphql\`,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Authorization: \`Bearer \${process.env.${DEFAULT_API_KEY_NAME}}\`,
|
|
},
|
|
}
|
|
|
|
export default class Twenty {
|
|
private client: Client;
|
|
|
|
constructor(options?: ClientOptions) {
|
|
const merged: ClientOptions = {
|
|
...defaultOptions,
|
|
...options,
|
|
headers: {
|
|
...defaultOptions.headers,
|
|
...(options?.headers ?? {}),
|
|
},
|
|
};
|
|
|
|
this.client = createClient(merged);
|
|
}
|
|
|
|
query<R extends QueryGenqlSelection>(request: R & { __name?: string }) {
|
|
return this.client.query(request);
|
|
}
|
|
|
|
mutation<R extends MutationGenqlSelection>(request: R & { __name?: string }) {
|
|
return this.client.mutation(request);
|
|
}
|
|
}
|
|
|
|
`;
|
|
|
|
await fs.appendFile(join(output, 'index.ts'), twentyClientContent);
|
|
}
|
|
}
|