create-twenty-app 1.22.0-canary.6 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- "use strict";const zA=require("chalk"),r_=require("commander"),UA=require("fs-extra"),Rn=require("path"),jA=require("uuid"),LA=require("node:child_process"),FA=require("node:os"),i_=require("util"),o_=require("child_process"),ZA=require("inquirer"),BA=require("lodash.kebabcase"),rc=require("twenty-sdk/cli");require("lodash.camelcase");const Th=e=>e&&e.__esModule?e:{default:e};function a_(e){if(e&&e.__esModule)return e;const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const Xe=Th(zA),_t=a_(UA),zv=a_(Rn),ic=Th(ZA),WA=Th(BA),GA="create-twenty-app",qA="1.22.0-canary.6",Hc={name:GA,version:qA},HA="src",Uv=async({appName:e,appDisplayName:t,appDescription:r,appDirectory:i})=>{console.log(Xe.default.gray("Generating application project...")),await _t.copy(Rn.join(__dirname,"./constants/template"),i),await KA({appDirectory:i}),await JA({appDisplayName:t,appDescription:r,appDirectory:i}),await VA({appName:e,appDirectory:i})},KA=async({appDirectory:e})=>{const t=[{from:"gitignore",to:".gitignore"},{from:"github",to:".github"}];for(const{from:r,to:i}of t){const n=Rn.join(e,r);await _t.pathExists(n)&&await _t.rename(n,Rn.join(e,i))}},JA=async({appDisplayName:e,appDescription:t,appDirectory:r})=>{const i=Rn.join(r,HA,"constants","universal-identifiers.ts"),n=await _t.readFile(i,"utf-8");await _t.writeFile(i,n.replace("DISPLAY-NAME-TO-BE-GENERATED",e).replace("DESCRIPTION-TO-BE-GENERATED",t).replace(/UUID-TO-BE-GENERATED/g,()=>jA.v4()))},VA=async({appName:e,appDirectory:t})=>{const r=await _t.readJson(Rn.join(t,"package.json"));r.name=e,r.dependencies["twenty-sdk"]=Hc.version,r.dependencies["twenty-client-sdk"]=Hc.version,await _t.writeFile(Rn.join(t,"package.json"),JSON.stringify(r,null,2),"utf8")},yu="twentyhq",_u="twenty",u_="main",hl="packages/twenty-apps/examples",YA=`https://github.com/${yu}/${_u}/tree/${u_}/${hl}`,XA=async()=>{const e=await fetch(`https://api.github.com/repos/${yu}/${_u}/releases/latest`,{headers:{Accept:"application/vnd.github.v3+json"}});return e.ok?(await e.json()).tag_name:u_},s_=async(e,t)=>{const r=`https://api.github.com/repos/${yu}/${_u}/contents/${e}?ref=${t}`,i=await fetch(r,{headers:{Accept:"application/vnd.github.v3+json"}});if(!i.ok)return null;const n=await i.json();return Array.isArray(n)?n:null},QA=async e=>{const t=await s_(hl,e);return t?t.filter(r=>r.type==="dir").map(r=>r.name):[]},eN=async(e,t)=>{const r=`${hl}/${e}`;if(await s_(r,t)!==null)return;const n=await QA(t);throw new Error(`Example "${e}" not found.
2
+ "use strict";const zA=require("chalk"),r_=require("commander"),UA=require("fs-extra"),Rn=require("path"),jA=require("uuid"),LA=require("node:child_process"),FA=require("node:os"),i_=require("util"),o_=require("child_process"),ZA=require("inquirer"),BA=require("lodash.kebabcase"),rc=require("twenty-sdk/cli");require("lodash.camelcase");const Th=e=>e&&e.__esModule?e:{default:e};function a_(e){if(e&&e.__esModule)return e;const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const Xe=Th(zA),_t=a_(UA),zv=a_(Rn),ic=Th(ZA),WA=Th(BA),GA="create-twenty-app",qA="1.22.0",Hc={name:GA,version:qA},HA="src",Uv=async({appName:e,appDisplayName:t,appDescription:r,appDirectory:i})=>{console.log(Xe.default.gray("Generating application project...")),await _t.copy(Rn.join(__dirname,"./constants/template"),i),await KA({appDirectory:i}),await JA({appDisplayName:t,appDescription:r,appDirectory:i}),await VA({appName:e,appDirectory:i})},KA=async({appDirectory:e})=>{const t=[{from:"gitignore",to:".gitignore"},{from:"github",to:".github"}];for(const{from:r,to:i}of t){const n=Rn.join(e,r);await _t.pathExists(n)&&await _t.rename(n,Rn.join(e,i))}},JA=async({appDisplayName:e,appDescription:t,appDirectory:r})=>{const i=Rn.join(r,HA,"constants","universal-identifiers.ts"),n=await _t.readFile(i,"utf-8");await _t.writeFile(i,n.replace("DISPLAY-NAME-TO-BE-GENERATED",e).replace("DESCRIPTION-TO-BE-GENERATED",t).replace(/UUID-TO-BE-GENERATED/g,()=>jA.v4()))},VA=async({appName:e,appDirectory:t})=>{const r=await _t.readJson(Rn.join(t,"package.json"));r.name=e,r.dependencies["twenty-sdk"]=Hc.version,r.dependencies["twenty-client-sdk"]=Hc.version,await _t.writeFile(Rn.join(t,"package.json"),JSON.stringify(r,null,2),"utf8")},yu="twentyhq",_u="twenty",u_="main",hl="packages/twenty-apps/examples",YA=`https://github.com/${yu}/${_u}/tree/${u_}/${hl}`,XA=async()=>{const e=await fetch(`https://api.github.com/repos/${yu}/${_u}/releases/latest`,{headers:{Accept:"application/vnd.github.v3+json"}});return e.ok?(await e.json()).tag_name:u_},s_=async(e,t)=>{const r=`https://api.github.com/repos/${yu}/${_u}/contents/${e}?ref=${t}`,i=await fetch(r,{headers:{Accept:"application/vnd.github.v3+json"}});if(!i.ok)return null;const n=await i.json();return Array.isArray(n)?n:null},QA=async e=>{const t=await s_(hl,e);return t?t.filter(r=>r.type==="dir").map(r=>r.name):[]},eN=async(e,t)=>{const r=`${hl}/${e}`;if(await s_(r,t)!==null)return;const n=await QA(t);throw new Error(`Example "${e}" not found.
3
3
 
4
4
  `+(n.length>0?`Available examples:
5
5
  ${n.map(a=>` - ${a}`).join(`
package/dist/cli.mjs CHANGED
@@ -13,7 +13,7 @@ import rc from "inquirer";
13
13
  import jA from "lodash.kebabcase";
14
14
  import { serverStart as LA, detectLocalServer as FA, authLoginOAuth as ZA, ConfigService as BA } from "twenty-sdk/cli";
15
15
  import "lodash.camelcase";
16
- const WA = "create-twenty-app", GA = "1.22.0-canary.6", Hc = {
16
+ const WA = "create-twenty-app", GA = "1.22.0", Hc = {
17
17
  name: WA,
18
18
  version: GA
19
19
  }, HA = "src", Dv = async ({
@@ -7,9 +7,7 @@
7
7
  "npm": "please-use-yarn",
8
8
  "yarn": ">=4.0.2"
9
9
  },
10
- "keywords": [
11
- "twenty-app"
12
- ],
10
+ "keywords": [],
13
11
  "packageManager": "yarn@4.9.2",
14
12
  "scripts": {
15
13
  "twenty": "twenty",
@@ -0,0 +1,87 @@
1
+ import * as fs from 'fs';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+
5
+ import { appDevOnce, appUninstall } from 'twenty-sdk/cli';
6
+
7
+ const APP_PATH = process.cwd();
8
+ const CONFIG_DIR = path.join(os.homedir(), '.twenty');
9
+
10
+ function validateEnv(): { apiUrl: string; apiKey: string } {
11
+ const apiUrl = process.env.TWENTY_API_URL;
12
+ const apiKey = process.env.TWENTY_API_KEY;
13
+
14
+ if (!apiUrl || !apiKey) {
15
+ throw new Error(
16
+ 'TWENTY_API_URL and TWENTY_API_KEY must be set.\n' +
17
+ 'Start a local server: yarn twenty server start\n' +
18
+ 'Or set them in vitest env config.',
19
+ );
20
+ }
21
+
22
+ return { apiUrl, apiKey };
23
+ }
24
+
25
+ async function checkServer(apiUrl: string) {
26
+ let response: Response;
27
+
28
+ try {
29
+ response = await fetch(`${apiUrl}/healthz`);
30
+ } catch {
31
+ throw new Error(
32
+ `Twenty server is not reachable at ${apiUrl}. ` +
33
+ 'Make sure the server is running before executing integration tests.',
34
+ );
35
+ }
36
+
37
+ if (!response.ok) {
38
+ throw new Error(`Server at ${apiUrl} returned ${response.status}`);
39
+ }
40
+ }
41
+
42
+ function writeConfig(apiUrl: string, apiKey: string) {
43
+ const payload = JSON.stringify(
44
+ {
45
+ remotes: {
46
+ local: { apiUrl, apiKey, accessToken: apiKey },
47
+ },
48
+ defaultRemote: 'local',
49
+ },
50
+ null,
51
+ 2,
52
+ );
53
+
54
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
55
+ fs.writeFileSync(path.join(CONFIG_DIR, 'config.test.json'), payload);
56
+ }
57
+
58
+ export async function setup() {
59
+ const { apiUrl, apiKey } = validateEnv();
60
+
61
+ await checkServer(apiUrl);
62
+
63
+ writeConfig(apiUrl, apiKey);
64
+
65
+ await appUninstall({ appPath: APP_PATH }).catch(() => {});
66
+
67
+ const result = await appDevOnce({
68
+ appPath: APP_PATH,
69
+ onProgress: (message: string) => console.log(`[dev] ${message}`),
70
+ });
71
+
72
+ if (!result.success) {
73
+ throw new Error(
74
+ `Dev sync failed: ${result.error?.message ?? 'Unknown error'}`,
75
+ );
76
+ }
77
+ }
78
+
79
+ export async function teardown() {
80
+ const uninstallResult = await appUninstall({ appPath: APP_PATH });
81
+
82
+ if (!uninstallResult.success) {
83
+ console.warn(
84
+ `App uninstall failed: ${uninstallResult.error?.message ?? 'Unknown error'}`,
85
+ );
86
+ }
87
+ }
@@ -0,0 +1,46 @@
1
+ import { CoreApiClient } from 'twenty-client-sdk/core';
2
+ import { MetadataApiClient } from 'twenty-client-sdk/metadata';
3
+ import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
4
+ import { describe, expect, it } from 'vitest';
5
+
6
+ describe('App installation', () => {
7
+ it('should find the installed app in the applications list', async () => {
8
+ const client = new MetadataApiClient();
9
+
10
+ const result = await client.query({
11
+ findManyApplications: {
12
+ id: true,
13
+ name: true,
14
+ universalIdentifier: true,
15
+ },
16
+ });
17
+
18
+ const app = result.findManyApplications.find(
19
+ (a: { universalIdentifier: string }) =>
20
+ a.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER,
21
+ );
22
+
23
+ expect(app).toBeDefined();
24
+ });
25
+ });
26
+
27
+ describe('CoreApiClient', () => {
28
+ it('should support CRUD on standard objects', async () => {
29
+ const client = new CoreApiClient();
30
+
31
+ const created = await client.mutation({
32
+ createNote: {
33
+ __args: { data: { title: 'Integration test note' } },
34
+ id: true,
35
+ },
36
+ });
37
+ expect(created.createNote.id).toBeDefined();
38
+
39
+ await client.mutation({
40
+ destroyNote: {
41
+ __args: { id: created.createNote.id },
42
+ id: true,
43
+ },
44
+ });
45
+ });
46
+ });
@@ -1,6 +1,15 @@
1
1
  import tsconfigPaths from 'vite-tsconfig-paths';
2
2
  import { defineConfig } from 'vitest/config';
3
3
 
4
+ const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020';
5
+ const TWENTY_API_KEY =
6
+ process.env.TWENTY_API_KEY ??
7
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjQ4OTE0NDk2MDAsImp0aSI6IjIwMjAyMDIwLWY0MDEtNGQ4YS1hNzMxLTY0ZDAwN2MyN2JhZCJ9.bfQjfyN0NEtTCLE_xPyNcwonDzlSXFoP8kdCQTdnuDc';
8
+
9
+ // Make env vars available to globalSetup (test.env only applies to workers)
10
+ process.env.TWENTY_API_URL = TWENTY_API_URL;
11
+ process.env.TWENTY_API_KEY = TWENTY_API_KEY;
12
+
4
13
  export default defineConfig({
5
14
  plugins: [
6
15
  tsconfigPaths({
@@ -11,13 +20,12 @@ export default defineConfig({
11
20
  test: {
12
21
  testTimeout: 120_000,
13
22
  hookTimeout: 120_000,
23
+ fileParallelism: false,
14
24
  include: ['src/**/*.integration-test.ts'],
15
- setupFiles: ['src/__tests__/setup-test.ts'],
25
+ globalSetup: ['src/__tests__/global-setup.ts'],
16
26
  env: {
17
- TWENTY_API_URL: process.env.TWENTY_API_URL ?? 'http://localhost:2020',
18
- TWENTY_API_KEY:
19
- process.env.TWENTY_API_KEY ??
20
- 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjQ4OTE0NDk2MDAsImp0aSI6IjIwMjAyMDIwLWY0MDEtNGQ4YS1hNzMxLTY0ZDAwN2MyN2JhZCJ9.bfQjfyN0NEtTCLE_xPyNcwonDzlSXFoP8kdCQTdnuDc',
27
+ TWENTY_API_URL,
28
+ TWENTY_API_KEY,
21
29
  },
22
30
  },
23
31
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-twenty-app",
3
- "version": "1.22.0-canary.6",
3
+ "version": "1.22.0",
4
4
  "description": "Command-line interface to create Twenty application",
5
5
  "main": "dist/cli.cjs",
6
6
  "bin": "dist/cli.cjs",
@@ -36,7 +36,7 @@
36
36
  "lodash.camelcase": "^4.3.0",
37
37
  "lodash.kebabcase": "^4.1.1",
38
38
  "lodash.startcase": "^4.4.0",
39
- "twenty-sdk": "1.22.0-canary.6",
39
+ "twenty-sdk": "1.22.0",
40
40
  "uuid": "^13.0.0"
41
41
  },
42
42
  "devDependencies": {
@@ -7,9 +7,7 @@
7
7
  "npm": "please-use-yarn",
8
8
  "yarn": ">=4.0.2"
9
9
  },
10
- "keywords": [
11
- "twenty-app"
12
- ],
10
+ "keywords": [],
13
11
  "packageManager": "yarn@4.9.2",
14
12
  "scripts": {
15
13
  "twenty": "twenty",
@@ -1,70 +0,0 @@
1
- import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
2
- import { appBuild, appDeploy, appInstall, appUninstall } from 'twenty-sdk/cli';
3
- import { MetadataApiClient } from 'twenty-client-sdk/metadata';
4
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
5
-
6
- const APP_PATH = process.cwd();
7
-
8
- describe('App installation', () => {
9
- beforeAll(async () => {
10
- const buildResult = await appBuild({
11
- appPath: APP_PATH,
12
- tarball: true,
13
- onProgress: (message: string) => console.log(`[build] ${message}`),
14
- });
15
-
16
- if (!buildResult.success) {
17
- throw new Error(
18
- `Build failed: ${buildResult.error?.message ?? 'Unknown error'}`,
19
- );
20
- }
21
-
22
- const deployResult = await appDeploy({
23
- tarballPath: buildResult.data.tarballPath!,
24
- onProgress: (message: string) => console.log(`[deploy] ${message}`),
25
- });
26
-
27
- if (!deployResult.success) {
28
- throw new Error(
29
- `Deploy failed: ${deployResult.error?.message ?? 'Unknown error'}`,
30
- );
31
- }
32
-
33
- const installResult = await appInstall({ appPath: APP_PATH });
34
-
35
- if (!installResult.success) {
36
- throw new Error(
37
- `Install failed: ${installResult.error?.message ?? 'Unknown error'}`,
38
- );
39
- }
40
- });
41
-
42
- afterAll(async () => {
43
- const uninstallResult = await appUninstall({ appPath: APP_PATH });
44
-
45
- if (!uninstallResult.success) {
46
- console.warn(
47
- `App uninstall failed: ${uninstallResult.error?.message ?? 'Unknown error'}`,
48
- );
49
- }
50
- });
51
-
52
- it('should find the installed app in the applications list', async () => {
53
- const metadataClient = new MetadataApiClient();
54
-
55
- const result = await metadataClient.query({
56
- findManyApplications: {
57
- id: true,
58
- name: true,
59
- universalIdentifier: true,
60
- },
61
- });
62
-
63
- const installedApp = result.findManyApplications.find(
64
- (application: { universalIdentifier: string }) =>
65
- application.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER,
66
- );
67
-
68
- expect(installedApp).toBeDefined();
69
- });
70
- });
@@ -1,53 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as os from 'os';
3
- import * as path from 'path';
4
- import { beforeAll } from 'vitest';
5
-
6
- const CONFIG_DIR = path.join(os.homedir(), '.twenty');
7
- const CONFIG_PATH = path.join(CONFIG_DIR, 'config.test.json');
8
-
9
- beforeAll(async () => {
10
- const apiUrl = process.env.TWENTY_API_URL!;
11
- const token = process.env.TWENTY_API_KEY!;
12
-
13
- if (!apiUrl || !token) {
14
- throw new Error(
15
- 'TWENTY_API_URL and TWENTY_API_KEY must be set.\n' +
16
- 'Start a local server: yarn twenty server start\n' +
17
- 'Or set them in vitest env config.',
18
- );
19
- }
20
-
21
- let response: Response;
22
-
23
- try {
24
- response = await fetch(`${apiUrl}/healthz`);
25
- } catch {
26
- throw new Error(
27
- `Twenty server is not reachable at ${apiUrl}. ` +
28
- 'Make sure the server is running before executing integration tests.',
29
- );
30
- }
31
-
32
- if (!response.ok) {
33
- throw new Error(`Server at ${apiUrl} returned ${response.status}`);
34
- }
35
-
36
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
37
-
38
- fs.writeFileSync(
39
- CONFIG_PATH,
40
- JSON.stringify(
41
- {
42
- remotes: {
43
- local: { apiUrl, apiKey: token },
44
- },
45
- defaultRemote: 'local',
46
- },
47
- null,
48
- 2,
49
- ),
50
- );
51
-
52
- process.env.TWENTY_APP_ACCESS_TOKEN ??= token;
53
- });