579c59bd11
add auth:switch and auth:list commands
230 lines
5.1 KiB
TypeScript
230 lines
5.1 KiB
TypeScript
import * as fs from 'fs-extra';
|
|
import { join } from 'path';
|
|
import { v4 } from 'uuid';
|
|
|
|
const APP_FOLDER = 'src/app';
|
|
|
|
export const copyBaseApplicationProject = async ({
|
|
appName,
|
|
appDisplayName,
|
|
appDescription,
|
|
appDirectory,
|
|
}: {
|
|
appName: string;
|
|
appDisplayName: string;
|
|
appDescription: string;
|
|
appDirectory: string;
|
|
}) => {
|
|
await fs.copy(join(__dirname, './constants/base-application'), appDirectory);
|
|
|
|
await createPackageJson({ appName, appDirectory });
|
|
|
|
await createGitignore(appDirectory);
|
|
|
|
await createYarnLock(appDirectory);
|
|
|
|
const appFolderPath = join(appDirectory, APP_FOLDER);
|
|
|
|
await fs.ensureDir(appFolderPath);
|
|
|
|
await createDefaultServerlessFunctionRoleConfig({
|
|
displayName: appDisplayName,
|
|
appDirectory: appFolderPath,
|
|
});
|
|
|
|
await createDefaultFrontComponent({
|
|
appDirectory: appFolderPath,
|
|
});
|
|
|
|
await createApplicationConfig({
|
|
displayName: appDisplayName,
|
|
description: appDescription,
|
|
appDirectory: appFolderPath,
|
|
});
|
|
};
|
|
|
|
const createYarnLock = async (appDirectory: string) => {
|
|
const yarnLockContent = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
# yarn lockfile v1
|
|
`;
|
|
|
|
await fs.writeFile(join(appDirectory, 'yarn.lock'), yarnLockContent);
|
|
};
|
|
const createGitignore = async (appDirectory: string) => {
|
|
const gitignoreContent = `# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
|
|
# dependencies
|
|
/node_modules
|
|
/.pnp
|
|
.pnp.*
|
|
.yarn
|
|
|
|
# codegen
|
|
generated
|
|
|
|
# testing
|
|
/coverage
|
|
|
|
# dev
|
|
/dist/
|
|
|
|
# production
|
|
/build
|
|
|
|
# misc
|
|
.DS_Store
|
|
*.pem
|
|
|
|
# debug
|
|
npm-debug.log*
|
|
yarn-debug.log*
|
|
yarn-error.log*
|
|
.pnpm-debug.log*
|
|
|
|
# env files (can opt-in for committing if needed)
|
|
.env*
|
|
|
|
# typescript
|
|
*.tsbuildinfo
|
|
`;
|
|
|
|
await fs.writeFile(join(appDirectory, '.gitignore'), gitignoreContent);
|
|
};
|
|
|
|
const createDefaultServerlessFunctionRoleConfig = async ({
|
|
displayName,
|
|
appDirectory,
|
|
}: {
|
|
displayName: string;
|
|
appDirectory: string;
|
|
}) => {
|
|
const universalIdentifier = v4();
|
|
|
|
const content = `import { defineRole } from 'twenty-sdk';
|
|
|
|
export const DEFAULT_FUNCTION_ROLE_UNIVERSAL_IDENTIFIER =
|
|
'${universalIdentifier}';
|
|
|
|
export default defineRole({
|
|
universalIdentifier: DEFAULT_FUNCTION_ROLE_UNIVERSAL_IDENTIFIER,
|
|
label: '${displayName} default function role',
|
|
description: '${displayName} default function role',
|
|
canReadAllObjectRecords: true,
|
|
canUpdateAllObjectRecords: true,
|
|
canSoftDeleteAllObjectRecords: true,
|
|
canDestroyAllObjectRecords: false,
|
|
});
|
|
`;
|
|
|
|
await fs.writeFile(join(appDirectory, 'default-function.role.ts'), content);
|
|
};
|
|
|
|
const createDefaultFrontComponent = async ({
|
|
appDirectory,
|
|
}: {
|
|
appDirectory: string;
|
|
}) => {
|
|
const universalIdentifier = v4();
|
|
|
|
const content = `import { defineFrontComponent } from 'twenty-sdk';
|
|
|
|
export const HelloWorld = () => {
|
|
return (
|
|
<div style={{ padding: '20px', fontFamily: 'sans-serif' }}>
|
|
<h1>Hello, World!</h1>
|
|
<p>This is your first front component.</p>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default defineFrontComponent({
|
|
universalIdentifier: '${universalIdentifier}',
|
|
name: 'hello-world',
|
|
description: 'A sample front component',
|
|
component: HelloWorld,
|
|
});
|
|
`;
|
|
|
|
await fs.writeFile(
|
|
join(appDirectory, 'hello-world.front-component.tsx'),
|
|
content,
|
|
);
|
|
};
|
|
|
|
const createApplicationConfig = async ({
|
|
displayName,
|
|
description,
|
|
appDirectory,
|
|
}: {
|
|
displayName: string;
|
|
description?: string;
|
|
appDirectory: string;
|
|
}) => {
|
|
const content = `import { defineApp } from 'twenty-sdk';
|
|
import { DEFAULT_FUNCTION_ROLE_UNIVERSAL_IDENTIFIER } from './default-function.role';
|
|
|
|
export default defineApp({
|
|
universalIdentifier: '${v4()}',
|
|
displayName: '${displayName}',
|
|
description: '${description ?? ''}',
|
|
functionRoleUniversalIdentifier: DEFAULT_FUNCTION_ROLE_UNIVERSAL_IDENTIFIER,
|
|
});
|
|
`;
|
|
|
|
await fs.writeFile(join(appDirectory, 'application.config.ts'), content);
|
|
};
|
|
|
|
const createPackageJson = async ({
|
|
appName,
|
|
appDirectory,
|
|
}: {
|
|
appName: string;
|
|
appDirectory: string;
|
|
}) => {
|
|
const packageJson = {
|
|
name: appName,
|
|
version: '0.1.0',
|
|
license: 'MIT',
|
|
engines: {
|
|
node: '^24.5.0',
|
|
npm: 'please-use-yarn',
|
|
yarn: '>=4.0.2',
|
|
},
|
|
packageManager: 'yarn@4.9.2',
|
|
scripts: {
|
|
'auth:login': 'twenty auth:login',
|
|
'auth:logout': 'twenty auth:logout',
|
|
'auth:status': 'twenty auth:status',
|
|
'auth:switch': 'twenty auth:switch',
|
|
'auth:list': 'twenty auth:list',
|
|
'app:dev': 'twenty app:dev',
|
|
'app:sync': 'twenty app:sync',
|
|
'entity:add': 'twenty entity:add',
|
|
'app:generate': 'twenty app:generate',
|
|
'function:logs': 'twenty function:logs',
|
|
'function:execute': 'twenty function:execute',
|
|
'app:uninstall': 'twenty app:uninstall',
|
|
help: 'twenty help',
|
|
lint: 'eslint',
|
|
'lint:fix': 'eslint --fix',
|
|
},
|
|
dependencies: {
|
|
'twenty-sdk': '0.3.1',
|
|
},
|
|
devDependencies: {
|
|
typescript: '^5.9.3',
|
|
'@types/node': '^24.7.2',
|
|
'@types/react': '^19.0.2',
|
|
react: '^19.0.2',
|
|
eslint: '^9.32.0',
|
|
'typescript-eslint': '^8.50.0',
|
|
},
|
|
};
|
|
|
|
await fs.writeFile(
|
|
join(appDirectory, 'package.json'),
|
|
JSON.stringify(packageJson, null, 2),
|
|
'utf8',
|
|
);
|
|
};
|