Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0238d8bd53 |
+9
-12
@@ -71,10 +71,10 @@ npx nx build twenty-server
|
||||
# Database management
|
||||
npx nx database:reset twenty-server # Reset database
|
||||
npx nx run twenty-server:database:init:prod # Initialize database
|
||||
npx nx run twenty-server:database:migrate:prod # Run instance commands (fast only)
|
||||
npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
|
||||
# Generate an instance command (fast or slow)
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow>
|
||||
# Generate migration
|
||||
npx nx run twenty-server:database:migrate:generate
|
||||
```
|
||||
|
||||
### Database Inspection (Postgres MCP)
|
||||
@@ -158,17 +158,14 @@ packages/
|
||||
- **Redis** for caching and session management
|
||||
- **BullMQ** for background job processing
|
||||
|
||||
### Database & Upgrade Commands
|
||||
### Database & Migrations
|
||||
- **PostgreSQL** as primary database
|
||||
- **Redis** for caching and sessions
|
||||
- **ClickHouse** for analytics (when enabled)
|
||||
- When changing entity files, generate an **instance command** (`database:migrate:generate --name <name> --type <fast|slow>`)
|
||||
- **Fast** instance commands handle schema changes; **slow** ones add a `runDataMigration` step for data backfills
|
||||
- **Workspace commands** iterate over all active/suspended workspaces for per-workspace upgrades
|
||||
- Commands use `@RegisteredInstanceCommand` and `@RegisteredWorkspaceCommand` decorators for automatic discovery
|
||||
- Include both `up` and `down` logic in instance commands
|
||||
- Never delete or rewrite committed instance command `up`/`down` logic
|
||||
- See `packages/twenty-server/docs/UPGRADE_COMMANDS.md` for full documentation
|
||||
- Always generate migrations when changing entity files
|
||||
- Migration names must be kebab-case (e.g. `add-agent-turn-evaluation`)
|
||||
- Include both `up` and `down` logic in migrations
|
||||
- Never delete or rewrite committed migrations
|
||||
|
||||
### Utility Helpers
|
||||
Use existing helpers from `twenty-shared` instead of manual type guards:
|
||||
@@ -181,7 +178,7 @@ IMPORTANT: Use Context7 for code generation, setup or configuration steps, or li
|
||||
### Before Making Changes
|
||||
1. Always run linting (`lint:diff-with-main`) and type checking after code changes
|
||||
2. Test changes with relevant test suites (prefer single-file test runs)
|
||||
3. Ensure instance commands are generated for entity changes (`database:migrate:generate`)
|
||||
3. Ensure database migrations are generated for entity changes
|
||||
4. Check that GraphQL schema changes are backward compatible
|
||||
5. Run `graphql:generate` after any GraphQL schema changes
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ This directory contains Twenty's development guidelines and best practices in th
|
||||
### Core Guidelines
|
||||
- **architecture.mdc** - Project overview, technology stack, and infrastructure setup (Always Applied)
|
||||
- **nx-rules.mdc** - Nx workspace guidelines and best practices (Auto-attached to Nx files)
|
||||
- **server-migrations.mdc** - Upgrade command guidelines (instance commands and workspace commands) for `twenty-server` (Auto-attached to server entities and upgrade command files)
|
||||
- **server-migrations.mdc** - Backend migration and TypeORM guidelines for `twenty-server` (Auto-attached to server entities and migration files)
|
||||
- **creating-syncable-entity.mdc** - Comprehensive guide for creating new syncable entities (with universalIdentifier and applicationId) in the workspace migration system (Agent-requested for metadata-modules and workspace-migration files)
|
||||
|
||||
### Code Quality
|
||||
@@ -81,8 +81,10 @@ npx nx run twenty-server:typecheck # Type checking
|
||||
npx nx run twenty-server:test # Run unit tests
|
||||
npx nx run twenty-server:test:integration:with-db-reset # Run integration tests
|
||||
|
||||
# Upgrade commands (instance + workspace)
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow>
|
||||
# Migrations
|
||||
npx nx run twenty-server:database:migrate:generate
|
||||
|
||||
# Workspace
|
||||
```
|
||||
|
||||
## Usage Guidelines
|
||||
|
||||
@@ -55,8 +55,7 @@ If feature descriptions are not provided or need enhancement, research the codeb
|
||||
- Services: Look for `*.service.ts` files
|
||||
|
||||
**For Database/ORM Changes:**
|
||||
- Instance commands (fast/slow): `packages/twenty-server/src/database/commands/upgrade-version-command/`
|
||||
- Legacy TypeORM migrations: `packages/twenty-server/src/database/typeorm/`
|
||||
- Migrations: `packages/twenty-server/src/database/typeorm/`
|
||||
- Entities: `packages/twenty-server/src/entities/`
|
||||
|
||||
### Research Commands
|
||||
|
||||
@@ -22,7 +22,7 @@ This main guide provides a high-level overview and navigation hub.
|
||||
|
||||
A syncable entity is a metadata entity that:
|
||||
- Has a **`universalIdentifier`**: A unique identifier used for syncing entities across workspaces/applications
|
||||
- Has an **`applicationId`**: Links the entity to an application (Standard or Custom applications)
|
||||
- Has an **`applicationId`**: Links the entity to an application (Twenty Standard or Custom applications)
|
||||
- Participates in the **workspace migration system**: Can be created, updated, and deleted through the migration pipeline
|
||||
- Is **cached as a flat entity**: Denormalized representation for efficient validation and change detection
|
||||
|
||||
|
||||
@@ -1,46 +1,27 @@
|
||||
---
|
||||
description: Guidelines for generating and managing upgrade commands (instance commands and workspace commands) in twenty-server
|
||||
description: Guidelines for generating and managing TypeORM migrations in twenty-server
|
||||
globs: [
|
||||
"packages/twenty-server/src/**/*.entity.ts",
|
||||
"packages/twenty-server/src/database/commands/upgrade-version-command/**/*.ts"
|
||||
"packages/twenty-server/src/database/typeorm/**/*.ts"
|
||||
]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
## Upgrade Commands (twenty-server)
|
||||
## Server Migrations (twenty-server)
|
||||
|
||||
The upgrade system uses two types of commands instead of raw TypeORM migrations:
|
||||
- **Instance commands** — schema and data migrations that run once at the instance level.
|
||||
- **Workspace commands** — commands that iterate over all active/suspended workspaces.
|
||||
|
||||
See `packages/twenty-server/docs/UPGRADE_COMMANDS.md` for full documentation.
|
||||
|
||||
### Instance Commands
|
||||
|
||||
- **When changing a `*.entity.ts` file**, generate an instance command:
|
||||
- **When changing an entity, always generate a migration**
|
||||
- If you modify a `*.entity.ts` file in `packages/twenty-server/src`, you **must** generate a corresponding TypeORM migration instead of manually editing the database schema.
|
||||
- Use the Nx command from the project root:
|
||||
|
||||
```bash
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow>
|
||||
npx nx run twenty-server:database:migrate:generate
|
||||
```
|
||||
|
||||
- **Fast commands** (`--type fast`, default) are for schema-only changes that must run immediately. They implement `FastInstanceCommand` with `up`/`down` methods and use the `@RegisteredInstanceCommand` decorator.
|
||||
- **Prefer generated migrations over manual edits**
|
||||
- Let TypeORM infer schema changes from the updated entities; only adjust the generated migration file manually if absolutely necessary (for example, for data backfills or complex constraints).
|
||||
- Keep schema changes (DDL) in these generated migrations and avoid mixing in heavy data migrations unless there is a strong reason and clear comments.
|
||||
|
||||
- **Slow commands** (`--type slow`) add a `runDataMigration` method for potentially long-running data backfills that execute before `up`. They only run when `--include-slow` is passed. Use the decorator with `{ type: 'slow' }`.
|
||||
|
||||
- The generator auto-registers the command in `instance-commands.constant.ts` — do not edit that file manually.
|
||||
|
||||
- **Keep commands consistent and reversible**: include both `up` and `down` logic. Do not delete or rewrite existing, committed commands unless on a pre-release branch.
|
||||
|
||||
### Workspace Commands
|
||||
|
||||
- Use the `@RegisteredWorkspaceCommand` decorator alongside nest-commander's `@Command` decorator.
|
||||
- Extend `ActiveOrSuspendedWorkspaceCommandRunner` and implement `runOnWorkspace`.
|
||||
- The base class provides `--dry-run`, `--verbose`, and workspace filter options automatically.
|
||||
|
||||
### Execution Order
|
||||
|
||||
Within a given version, commands run in this order (timestamp-sorted within each group):
|
||||
1. Instance fast commands
|
||||
2. Instance slow commands (only with `--include-slow`)
|
||||
3. Workspace commands
|
||||
- **Keep migrations consistent and reversible**
|
||||
- Ensure the generated migration includes both `up` and `down` logic that correctly applies and reverts the entity change when possible.
|
||||
- Do not delete or rewrite existing, committed migrations unless you are explicitly working on a pre-release branch where history rewrites are allowed by team conventions.
|
||||
|
||||
|
||||
@@ -8,10 +8,6 @@ inputs:
|
||||
api-key:
|
||||
description: API key or access token for the target instance
|
||||
required: true
|
||||
app-path:
|
||||
description: Path to the app directory (relative to repo root). Defaults to repo root.
|
||||
required: false
|
||||
default: '.'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
@@ -23,13 +19,11 @@ runs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '${{ inputs.app-path }}/.nvmrc'
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: '${{ inputs.app-path }}/yarn.lock'
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.app-path }}
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Configure remote
|
||||
@@ -49,5 +43,4 @@ runs:
|
||||
|
||||
- name: Deploy
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.app-path }}
|
||||
run: yarn twenty deploy --remote target
|
||||
|
||||
@@ -8,10 +8,6 @@ inputs:
|
||||
api-key:
|
||||
description: API key or access token for the target workspace
|
||||
required: true
|
||||
app-path:
|
||||
description: Path to the app directory (relative to repo root). Defaults to repo root.
|
||||
required: false
|
||||
default: '.'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
@@ -23,13 +19,11 @@ runs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '${{ inputs.app-path }}/.nvmrc'
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: '${{ inputs.app-path }}/yarn.lock'
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.app-path }}
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Configure remote
|
||||
@@ -49,5 +43,4 @@ runs:
|
||||
|
||||
- name: Install
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.app-path }}
|
||||
run: yarn twenty install --remote target
|
||||
|
||||
@@ -15,8 +15,8 @@ outputs:
|
||||
description: 'URL where the Twenty test server can be reached'
|
||||
value: http://localhost:2021
|
||||
api-key:
|
||||
description: 'API key (type: API_KEY) for the seeded Twenty dev workspace'
|
||||
value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjQ4OTE0NDk2MDAsImp0aSI6IjIwMjAyMDIwLWY0MDEtNGQ4YS1hNzMxLTY0ZDAwN2MyN2JhZCJ9.bfQjfyN0NEtTCLE_xPyNcwonDzlSXFoP8kdCQTdnuDc
|
||||
description: 'API key for the Twenty test instance'
|
||||
value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ1c2VySWQiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtOWUzYi00NmQ0LWE1NTYtODhiOWRkYzJiMDM1IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjQ5MDQ4ODE3MDR9.9S4wc0MOr5iczsomlFxZdOHD1IRDS4dnRSwNVNpctF4
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
|
||||
@@ -19,7 +19,6 @@ jobs:
|
||||
files: |
|
||||
packages/twenty-sdk/**
|
||||
packages/twenty-server/**
|
||||
.github/workflows/ci-sdk.yaml
|
||||
!packages/twenty-sdk/package.json
|
||||
sdk-test:
|
||||
needs: changed-files-check
|
||||
@@ -70,6 +69,7 @@ jobs:
|
||||
ports:
|
||||
- 6379:6379
|
||||
env:
|
||||
NODE_ENV: test
|
||||
TWENTY_API_URL: http://localhost:3000
|
||||
TWENTY_API_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik
|
||||
steps:
|
||||
@@ -79,26 +79,16 @@ jobs:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Build SDK
|
||||
- name: Build
|
||||
run: npx nx build twenty-sdk
|
||||
- name: Setup server environment
|
||||
run: npx nx reset:env:e2e-testing-server twenty-server
|
||||
- name: Create databases
|
||||
- name: Server / Create Test DB
|
||||
run: |
|
||||
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";'
|
||||
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
|
||||
- name: Setup database
|
||||
run: npx nx run twenty-server:database:reset
|
||||
- name: Start server
|
||||
run: nohup npx nx start:ci twenty-server > /tmp/twenty-server.log 2>&1 &
|
||||
- name: Wait for server to be ready
|
||||
run: npx wait-on http://localhost:3000/healthz --timeout 120000 --interval 1000
|
||||
- name: SDK / Run e2e Tests
|
||||
run: NODE_ENV=test npx vitest run --config ./vitest.e2e.config.ts
|
||||
working-directory: packages/twenty-sdk
|
||||
- name: Server / Dump logs on failure
|
||||
if: failure()
|
||||
run: tail -100 /tmp/twenty-server.log || echo "No server log file found"
|
||||
uses: ./.github/actions/nx-affected
|
||||
with:
|
||||
tag: scope:sdk
|
||||
tasks: test:e2e
|
||||
ci-sdk-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 5
|
||||
|
||||
@@ -144,18 +144,15 @@ jobs:
|
||||
exit 1
|
||||
- name: Server / Check for Pending Migrations
|
||||
run: |
|
||||
npx nx database:migrate:generate twenty-server -- --name pending-migration-check || true
|
||||
CORE_MIGRATION_OUTPUT=$(npx nx database:migrate:generate twenty-server -- --name core-migration-check || true)
|
||||
|
||||
if ! git diff --quiet; then
|
||||
CORE_MIGRATION_FILE=$(ls packages/twenty-server/src/database/typeorm/core/migrations/common/*core-migration-check.ts 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$CORE_MIGRATION_FILE" ]; then
|
||||
echo "::error::Unexpected migration files were generated. Please run 'npx nx database:migrate:generate twenty-server -- --name <migration-name>' and commit the result."
|
||||
echo ""
|
||||
echo "The following migration changes were detected:"
|
||||
echo "==================================================="
|
||||
git diff
|
||||
echo "==================================================="
|
||||
echo ""
|
||||
echo "$CORE_MIGRATION_OUTPUT"
|
||||
|
||||
git checkout -- .
|
||||
rm -f packages/twenty-server/src/database/typeorm/core/migrations/common/*core-migration-check.ts
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -69,14 +69,13 @@ jobs:
|
||||
|
||||
- name: Server / Start
|
||||
run: |
|
||||
npx nx run twenty-server:start:ci &
|
||||
npx nx start twenty-server &
|
||||
echo "Waiting for server to be ready..."
|
||||
timeout 60 bash -c 'until curl -sf http://localhost:3000/healthz; do sleep 2; done'
|
||||
timeout 60 bash -c 'until curl -s http://localhost:3000/health; do sleep 2; done'
|
||||
|
||||
- name: Start worker
|
||||
working-directory: packages/twenty-server
|
||||
run: |
|
||||
NODE_ENV=development node dist/queue-worker/queue-worker.js &
|
||||
npx nx run twenty-server:worker &
|
||||
echo "Worker started"
|
||||
|
||||
- name: Zapier / Build
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
.DS_Store
|
||||
/.idea
|
||||
.claude/settings.json
|
||||
.cursor/debug-*.log
|
||||
**/**/node_modules/
|
||||
.cache
|
||||
|
||||
@@ -54,4 +53,3 @@ mcp.json
|
||||
TRANSLATION_QA_REPORT.md
|
||||
.playwright-mcp/
|
||||
.playwright-cli/
|
||||
output/playwright/
|
||||
|
||||
@@ -71,10 +71,10 @@ npx nx build twenty-server
|
||||
# Database management
|
||||
npx nx database:reset twenty-server # Reset database
|
||||
npx nx run twenty-server:database:init:prod # Initialize database
|
||||
npx nx run twenty-server:database:migrate:prod # Run instance commands (fast only)
|
||||
npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
|
||||
# Generate an instance command (fast or slow)
|
||||
npx nx run twenty-server:database:migrate:generate --name <name> --type <fast|slow>
|
||||
# Generate migration
|
||||
npx nx run twenty-server:database:migrate:generate
|
||||
```
|
||||
|
||||
### Database Inspection (Postgres MCP)
|
||||
@@ -158,17 +158,14 @@ packages/
|
||||
- **Redis** for caching and session management
|
||||
- **BullMQ** for background job processing
|
||||
|
||||
### Database & Upgrade Commands
|
||||
### Database & Migrations
|
||||
- **PostgreSQL** as primary database
|
||||
- **Redis** for caching and sessions
|
||||
- **ClickHouse** for analytics (when enabled)
|
||||
- When changing entity files, generate an **instance command** (`database:migrate:generate --name <name> --type <fast|slow>`)
|
||||
- **Fast** instance commands handle schema changes; **slow** ones add a `runDataMigration` step for data backfills
|
||||
- **Workspace commands** iterate over all active/suspended workspaces for per-workspace upgrades
|
||||
- Commands use `@RegisteredInstanceCommand` and `@RegisteredWorkspaceCommand` decorators for automatic discovery
|
||||
- Include both `up` and `down` logic in instance commands
|
||||
- Never delete or rewrite committed instance command `up`/`down` logic
|
||||
- See `packages/twenty-server/docs/UPGRADE_COMMANDS.md` for full documentation
|
||||
- Always generate migrations when changing entity files
|
||||
- Migration names must be kebab-case (e.g. `add-agent-turn-evaluation`)
|
||||
- Include both `up` and `down` logic in migrations
|
||||
- Never delete or rewrite committed migrations
|
||||
|
||||
### Utility Helpers
|
||||
Use existing helpers from `twenty-shared` instead of manual type guards:
|
||||
@@ -181,7 +178,7 @@ IMPORTANT: Use Context7 for code generation, setup or configuration steps, or li
|
||||
### Before Making Changes
|
||||
1. Always run linting (`lint:diff-with-main`) and type checking after code changes
|
||||
2. Test changes with relevant test suites (prefer single-file test runs)
|
||||
3. Ensure instance commands are generated for entity changes (`database:migrate:generate`)
|
||||
3. Ensure database migrations are generated for entity changes
|
||||
4. Check that GraphQL schema changes are backward compatible
|
||||
5. Run `graphql:generate` after any GraphQL schema changes
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-twenty-app",
|
||||
"version": "1.23.0-canary.1",
|
||||
"version": "0.9.0",
|
||||
"description": "Command-line interface to create Twenty application",
|
||||
"main": "dist/cli.cjs",
|
||||
"bin": "dist/cli.cjs",
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"npm": "please-use-yarn",
|
||||
"yarn": ">=4.0.2"
|
||||
},
|
||||
"keywords": [],
|
||||
"keywords": [
|
||||
"twenty-app"
|
||||
],
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"scripts": {
|
||||
"twenty": "twenty",
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { appBuild, appDeploy, appInstall, appUninstall } from 'twenty-sdk/cli';
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||
|
||||
const APP_PATH = process.cwd();
|
||||
|
||||
describe('App installation', () => {
|
||||
beforeAll(async () => {
|
||||
const buildResult = await appBuild({
|
||||
appPath: APP_PATH,
|
||||
tarball: true,
|
||||
onProgress: (message: string) => console.log(`[build] ${message}`),
|
||||
});
|
||||
|
||||
if (!buildResult.success) {
|
||||
throw new Error(
|
||||
`Build failed: ${buildResult.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
|
||||
const deployResult = await appDeploy({
|
||||
tarballPath: buildResult.data.tarballPath!,
|
||||
onProgress: (message: string) => console.log(`[deploy] ${message}`),
|
||||
});
|
||||
|
||||
if (!deployResult.success) {
|
||||
throw new Error(
|
||||
`Deploy failed: ${deployResult.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
|
||||
const installResult = await appInstall({ appPath: APP_PATH });
|
||||
|
||||
if (!installResult.success) {
|
||||
throw new Error(
|
||||
`Install failed: ${installResult.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
const uninstallResult = await appUninstall({ appPath: APP_PATH });
|
||||
|
||||
if (!uninstallResult.success) {
|
||||
console.warn(
|
||||
`App uninstall failed: ${uninstallResult.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should find the installed app in the applications list', async () => {
|
||||
const metadataClient = new MetadataApiClient();
|
||||
|
||||
const result = await metadataClient.query({
|
||||
findManyApplications: {
|
||||
id: true,
|
||||
name: true,
|
||||
universalIdentifier: true,
|
||||
},
|
||||
});
|
||||
|
||||
const installedApp = result.findManyApplications.find(
|
||||
(application: { universalIdentifier: string }) =>
|
||||
application.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
);
|
||||
|
||||
expect(installedApp).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,87 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
import { appDevOnce, appUninstall } from 'twenty-sdk/cli';
|
||||
|
||||
const APP_PATH = process.cwd();
|
||||
const CONFIG_DIR = path.join(os.homedir(), '.twenty');
|
||||
|
||||
function validateEnv(): { apiUrl: string; apiKey: string } {
|
||||
const apiUrl = process.env.TWENTY_API_URL;
|
||||
const apiKey = process.env.TWENTY_API_KEY;
|
||||
|
||||
if (!apiUrl || !apiKey) {
|
||||
throw new Error(
|
||||
'TWENTY_API_URL and TWENTY_API_KEY must be set.\n' +
|
||||
'Start a local server: yarn twenty server start\n' +
|
||||
'Or set them in vitest env config.',
|
||||
);
|
||||
}
|
||||
|
||||
return { apiUrl, apiKey };
|
||||
}
|
||||
|
||||
async function checkServer(apiUrl: string) {
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await fetch(`${apiUrl}/healthz`);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Twenty server is not reachable at ${apiUrl}. ` +
|
||||
'Make sure the server is running before executing integration tests.',
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server at ${apiUrl} returned ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
function writeConfig(apiUrl: string, apiKey: string) {
|
||||
const payload = JSON.stringify(
|
||||
{
|
||||
remotes: {
|
||||
local: { apiUrl, apiKey, accessToken: apiKey },
|
||||
},
|
||||
defaultRemote: 'local',
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
fs.writeFileSync(path.join(CONFIG_DIR, 'config.test.json'), payload);
|
||||
}
|
||||
|
||||
export async function setup() {
|
||||
const { apiUrl, apiKey } = validateEnv();
|
||||
|
||||
await checkServer(apiUrl);
|
||||
|
||||
writeConfig(apiUrl, apiKey);
|
||||
|
||||
await appUninstall({ appPath: APP_PATH }).catch(() => {});
|
||||
|
||||
const result = await appDevOnce({
|
||||
appPath: APP_PATH,
|
||||
onProgress: (message: string) => console.log(`[dev] ${message}`),
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(
|
||||
`Dev sync failed: ${result.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function teardown() {
|
||||
const uninstallResult = await appUninstall({ appPath: APP_PATH });
|
||||
|
||||
if (!uninstallResult.success) {
|
||||
console.warn(
|
||||
`App uninstall failed: ${uninstallResult.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('App installation', () => {
|
||||
it('should find the installed app in the applications list', async () => {
|
||||
const client = new MetadataApiClient();
|
||||
|
||||
const result = await client.query({
|
||||
findManyApplications: {
|
||||
id: true,
|
||||
name: true,
|
||||
universalIdentifier: true,
|
||||
},
|
||||
});
|
||||
|
||||
const app = result.findManyApplications.find(
|
||||
(a: { universalIdentifier: string }) =>
|
||||
a.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
);
|
||||
|
||||
expect(app).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('CoreApiClient', () => {
|
||||
it('should support CRUD on standard objects', async () => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
const created = await client.mutation({
|
||||
createNote: {
|
||||
__args: { data: { title: 'Integration test note' } },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
expect(created.createNote.id).toBeDefined();
|
||||
|
||||
await client.mutation({
|
||||
destroyNote: {
|
||||
__args: { id: created.createNote.id },
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
|
||||
import {
|
||||
APP_DESCRIPTION,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineRole } from 'twenty-sdk/define';
|
||||
import { defineRole } from 'twenty-sdk';
|
||||
|
||||
import {
|
||||
APP_DISPLAY_NAME,
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020';
|
||||
const TWENTY_API_KEY =
|
||||
process.env.TWENTY_API_KEY ??
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjQ4OTE0NDk2MDAsImp0aSI6IjIwMjAyMDIwLWY0MDEtNGQ4YS1hNzMxLTY0ZDAwN2MyN2JhZCJ9.bfQjfyN0NEtTCLE_xPyNcwonDzlSXFoP8kdCQTdnuDc';
|
||||
|
||||
// Make env vars available to globalSetup (test.env only applies to workers)
|
||||
process.env.TWENTY_API_URL = TWENTY_API_URL;
|
||||
process.env.TWENTY_API_KEY = TWENTY_API_KEY;
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
tsconfigPaths({
|
||||
@@ -20,12 +11,14 @@ export default defineConfig({
|
||||
test: {
|
||||
testTimeout: 120_000,
|
||||
hookTimeout: 120_000,
|
||||
fileParallelism: false,
|
||||
include: ['src/**/*.integration-test.ts'],
|
||||
globalSetup: ['src/__tests__/global-setup.ts'],
|
||||
setupFiles: ['src/__tests__/setup-test.ts'],
|
||||
env: {
|
||||
TWENTY_API_URL,
|
||||
TWENTY_API_KEY,
|
||||
TWENTY_API_URL: process.env.TWENTY_API_URL ?? 'http://localhost:2020',
|
||||
TWENTY_API_KEY:
|
||||
process.env.TWENTY_API_KEY ??
|
||||
// Tim Apple (admin) access token for twenty-app-dev
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ1c2VySWQiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtOWUzYi00NmQ0LWE1NTYtODhiOWRkYzJiMDM1IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjQ5MDQ4ODE3MDR9.9S4wc0MOr5iczsomlFxZdOHD1IRDS4dnRSwNVNpctF4',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: 'ac1d2ed1-8835-4bd4-9043-28b46fdda465',
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: 'da15cfc6-3657-457d-8757-4ba11b5bb6e1',
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: '505532f5-1fc5-4a58-8074-ba9b48650dbc',
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: 'be15e062-b065-48b4-979c-65b9a50e0cb1',
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: 'c90ae72d-4ddf-4f22-882f-eef98c91e40e',
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import styled from '@emotion/styled';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { OAuthApplicationVariables } from 'src/logic-functions/get-oauth-application-variables';
|
||||
import { VERIFY_PAGE_PATH } from 'src/logic-functions/get-verify-page';
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineLogicFunction, RoutePayload } from "twenty-sdk/define";
|
||||
import { defineLogicFunction, RoutePayload } from "twenty-sdk";
|
||||
import { MetadataApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
export const OAUTH_TOKEN_PAIRS_PATH = '/oauth/token-pairs';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
|
||||
export type OAuthApplicationVariables = {
|
||||
apolloClientId: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineLogicFunction } from "twenty-sdk/define";
|
||||
import { defineLogicFunction } from "twenty-sdk";
|
||||
|
||||
export const VERIFY_PAGE_PATH = '/oauth/verify';
|
||||
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { defineLogicFunction, type DatabaseEventPayload, type ObjectRecordUpdateEvent } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineLogicFunction,
|
||||
type DatabaseEventPayload,
|
||||
type ObjectRecordUpdateEvent,
|
||||
} from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-sdk/clients';
|
||||
|
||||
type CompanyRecord = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { definePostInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk/define';
|
||||
import { definePostInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk';
|
||||
|
||||
const handler = async (payload: InstallLogicFunctionPayload): Promise<void> => {
|
||||
console.log('Post install logic function executed successfully!', payload.previousVersion);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { definePreInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk/define';
|
||||
import { definePreInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk';
|
||||
|
||||
const handler = async (payload: InstallLogicFunctionPayload): Promise<void> => {
|
||||
console.log('Pre install logic function executed successfully!', payload.previousVersion);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineRole } from 'twenty-sdk/define';
|
||||
import { defineRole } from 'twenty-sdk';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'b8faae3f-e174-43fa-ab94-715712ae26cb';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type ApplicationConfig } from 'twenty-sdk/define';
|
||||
import { type ApplicationConfig } from 'twenty-sdk';
|
||||
|
||||
const config: ApplicationConfig = {
|
||||
universalIdentifier: 'a4df0c0f-c65e-44e5-8436-24814182d4ac',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Object } from 'twenty-sdk/define';
|
||||
import { Object } from 'twenty-sdk';
|
||||
|
||||
@Object({
|
||||
universalIdentifier: 'd1831348-b4a4-4426-9c0b-0af19e7a9c27',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type FunctionConfig } from 'twenty-sdk/define';
|
||||
import { type FunctionConfig } from 'twenty-sdk';
|
||||
import type { ProcessResult } from './types';
|
||||
import { WebhookHandler } from './webhook-handler';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: '718ed9ab-53fc-49c8-8deb-0cff78ecf0d2',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: '9378751e-c23b-4e84-887d-2905cb8359b4',
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: '2f195c4c-1db1-4bbe-80b6-25c2f63168b0',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: 'fa342e26-9742-4db8-85b4-4d78ba18482f',
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
export default defineField({
|
||||
universalIdentifier: 'bec14de7-6683-4784-91ba-62d83b5f30f7',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { calculateStatus } from '../shared/calculate-status';
|
||||
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { DatabaseEventPayload, defineLogicFunction, ObjectRecordCreateEvent } from 'twenty-sdk/define';
|
||||
import {
|
||||
DatabaseEventPayload,
|
||||
defineLogicFunction,
|
||||
ObjectRecordCreateEvent,
|
||||
} from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { calculateStatus } from '../shared/calculate-status';
|
||||
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { DatabaseEventPayload, defineLogicFunction, ObjectRecordCreateEvent } from 'twenty-sdk/define';
|
||||
import {
|
||||
DatabaseEventPayload,
|
||||
defineLogicFunction,
|
||||
ObjectRecordCreateEvent,
|
||||
} from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { calculateStatus } from '../shared/calculate-status';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type ApplicationConfig } from 'twenty-sdk/define';
|
||||
import { type ApplicationConfig } from 'twenty-sdk';
|
||||
|
||||
const config: ApplicationConfig = {
|
||||
universalIdentifier: '1eadac4e-db9f-4cce-b20b-de75f41e34dc',
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import axios from 'axios';
|
||||
import { type DatabaseEventPayload, type FunctionConfig, type ObjectRecordCreateEvent, type ObjectRecordUpdateEvent } from 'twenty-sdk/define';
|
||||
import {
|
||||
type DatabaseEventPayload,
|
||||
type FunctionConfig,
|
||||
type ObjectRecordCreateEvent,
|
||||
type ObjectRecordUpdateEvent,
|
||||
} from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../generated';
|
||||
|
||||
const MAILCHIMP_API_URL: string =
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type ApplicationConfig } from 'twenty-sdk/define';
|
||||
import { type ApplicationConfig } from 'twenty-sdk';
|
||||
|
||||
const config: ApplicationConfig = {
|
||||
universalIdentifier: '0ed2bcb8-64ab-4ca1-b875-eeabf41b5f95',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import { type FunctionConfig } from 'twenty-sdk/define';
|
||||
import { type FunctionConfig } from 'twenty-sdk';
|
||||
import {
|
||||
type stripeCustomer,
|
||||
type stripeEvent,
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-client-sdk": "0.9.0",
|
||||
"twenty-sdk": "0.9.0"
|
||||
"twenty-client-sdk": "0.8.0-canary.5",
|
||||
"twenty-sdk": "0.8.0-canary.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.7.2",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineAgent } from 'twenty-sdk/define';
|
||||
import { defineAgent } from 'twenty-sdk';
|
||||
|
||||
export const EXAMPLE_AGENT_UNIVERSAL_IDENTIFIER =
|
||||
'110bebc2-f116-46b6-a35d-61e91c3c0a43';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/roles/default-role';
|
||||
|
||||
export const APPLICATION_UNIVERSAL_IDENTIFIER =
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineField, FieldType } from 'twenty-sdk/define';
|
||||
import { defineField, FieldType } from 'twenty-sdk';
|
||||
import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER } from 'src/objects/example-object';
|
||||
|
||||
export default defineField({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
|
||||
export const HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER =
|
||||
'7a758f23-5e7d-497d-98c9-7ca8d6c085b0';
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
|
||||
const handler = async (): Promise<{ message: string }> => {
|
||||
const client = new CoreApiClient();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
|
||||
const handler = async (): Promise<{ message: string }> => {
|
||||
return { message: 'Hello, World!' };
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { definePostInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk/define';
|
||||
import {
|
||||
definePostInstallLogicFunction,
|
||||
type InstallLogicFunctionPayload,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
const handler = async (payload: InstallLogicFunctionPayload): Promise<void> => {
|
||||
console.log(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { definePreInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk/define';
|
||||
import { definePreInstallLogicFunction, type InstallLogicFunctionPayload } from 'twenty-sdk';
|
||||
|
||||
const handler = async (payload: InstallLogicFunctionPayload): Promise<void> => {
|
||||
console.log('Pre install logic function executed successfully!', payload.previousVersion);
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineNavigationMenuItem } from 'twenty-sdk/define';
|
||||
import { defineNavigationMenuItem } from 'twenty-sdk';
|
||||
import { NavigationMenuItemType } from 'twenty-shared/types';
|
||||
import { EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER } from 'src/views/example-view';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineObject, FieldType } from 'twenty-sdk/define';
|
||||
import { defineObject, FieldType } from 'twenty-sdk';
|
||||
|
||||
export const EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER =
|
||||
'47fd9bd9-392b-4d9f-9091-9a91b1edf519';
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER } from 'src/objects/example-object';
|
||||
import { HELLO_WORLD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from 'src/front-components/hello-world';
|
||||
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk/define';
|
||||
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk';
|
||||
|
||||
export default definePageLayout({
|
||||
universalIdentifier: '203aeb94-6701-46d6-9af1-be2bbcc9e134',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineRole } from 'twenty-sdk/define';
|
||||
import { defineRole } from 'twenty-sdk';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'c38f4d11-760c-4d5c-89ed-e569c28b7b70';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineSkill } from 'twenty-sdk/define';
|
||||
import { defineSkill } from 'twenty-sdk';
|
||||
|
||||
export const EXAMPLE_SKILL_UNIVERSAL_IDENTIFIER =
|
||||
'90cf9144-4811-4653-93a2-9a6780fe6aac';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineView, ViewKey } from 'twenty-sdk/define';
|
||||
import { defineView, ViewKey } from 'twenty-sdk';
|
||||
import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER, NAME_FIELD_UNIVERSAL_IDENTIFIER } from 'src/objects/example-object';
|
||||
|
||||
export const EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER = '965e3776-b966-4be8-83f7-6cd3bce5e1bd';
|
||||
|
||||
@@ -17,7 +17,8 @@ export default defineConfig({
|
||||
TWENTY_API_URL: process.env.TWENTY_API_URL ?? 'http://localhost:2020',
|
||||
TWENTY_API_KEY:
|
||||
process.env.TWENTY_API_KEY ??
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjQ4OTE0NDk2MDAsImp0aSI6IjIwMjAyMDIwLWY0MDEtNGQ4YS1hNzMxLTY0ZDAwN2MyN2JhZCJ9.bfQjfyN0NEtTCLE_xPyNcwonDzlSXFoP8kdCQTdnuDc',
|
||||
// Tim Apple (admin) access token for twenty-app-dev
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ1c2VySWQiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtOWUzYi00NmQ0LWE1NTYtODhiOWRkYzJiMDM1IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjQ5MDQ4ODE3MDR9.9S4wc0MOr5iczsomlFxZdOHD1IRDS4dnRSwNVNpctF4',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,8 +19,8 @@
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-client-sdk": "0.9.0",
|
||||
"twenty-sdk": "0.9.0"
|
||||
"twenty-client-sdk": "0.8.0-canary.8",
|
||||
"twenty-sdk": "0.8.0-canary.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.7.2",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application.config';
|
||||
import { appBuild, appDeploy, appInstall, appUninstall } from 'twenty-sdk/cli';
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application.config';
|
||||
|
||||
const APP_PATH = process.cwd();
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
import { appDevOnce, appUninstall } from 'twenty-sdk/cli';
|
||||
|
||||
const APP_PATH = process.cwd();
|
||||
const CONFIG_DIR = path.join(os.homedir(), '.twenty');
|
||||
|
||||
function validateEnv(): { apiUrl: string; apiKey: string } {
|
||||
const apiUrl = process.env.TWENTY_API_URL;
|
||||
const apiKey = process.env.TWENTY_API_KEY;
|
||||
|
||||
if (!apiUrl || !apiKey) {
|
||||
throw new Error(
|
||||
'TWENTY_API_URL and TWENTY_API_KEY must be set.\n' +
|
||||
'Start a local server: yarn twenty server start\n' +
|
||||
'Or set them in vitest env config.',
|
||||
);
|
||||
}
|
||||
|
||||
return { apiUrl, apiKey };
|
||||
}
|
||||
|
||||
async function checkServer(apiUrl: string) {
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await fetch(`${apiUrl}/healthz`);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Twenty server is not reachable at ${apiUrl}. ` +
|
||||
'Make sure the server is running before executing integration tests.',
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server at ${apiUrl} returned ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
function writeConfig(apiUrl: string, apiKey: string) {
|
||||
const payload = JSON.stringify(
|
||||
{
|
||||
remotes: {
|
||||
local: { apiUrl, apiKey, accessToken: apiKey },
|
||||
},
|
||||
defaultRemote: 'local',
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
fs.writeFileSync(path.join(CONFIG_DIR, 'config.test.json'), payload);
|
||||
}
|
||||
|
||||
export async function setup() {
|
||||
const { apiUrl, apiKey } = validateEnv();
|
||||
|
||||
await checkServer(apiUrl);
|
||||
|
||||
writeConfig(apiUrl, apiKey);
|
||||
|
||||
await appUninstall({ appPath: APP_PATH }).catch(() => {});
|
||||
|
||||
const result = await appDevOnce({
|
||||
appPath: APP_PATH,
|
||||
onProgress: (message: string) => console.log(`[dev] ${message}`),
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(
|
||||
`Dev sync failed: ${result.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function teardown() {
|
||||
const uninstallResult = await appUninstall({ appPath: APP_PATH });
|
||||
|
||||
if (!uninstallResult.success) {
|
||||
console.warn(
|
||||
`App uninstall failed: ${uninstallResult.error?.message ?? 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application.config';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('App installation', () => {
|
||||
it('should find the installed app in the applications list', async () => {
|
||||
const client = new MetadataApiClient();
|
||||
|
||||
const result = await client.query({
|
||||
findManyApplications: {
|
||||
id: true,
|
||||
name: true,
|
||||
universalIdentifier: true,
|
||||
},
|
||||
});
|
||||
|
||||
const app = result.findManyApplications.find(
|
||||
(a: { universalIdentifier: string }) =>
|
||||
a.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
);
|
||||
|
||||
expect(app).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('PostCard object', () => {
|
||||
it('should exist with expected fields and relations', async () => {
|
||||
const client = new MetadataApiClient();
|
||||
|
||||
const { objects } = await client.query({
|
||||
objects: {
|
||||
__args: {
|
||||
filter: { isCustom: { is: true } },
|
||||
paging: { first: 50 },
|
||||
},
|
||||
edges: {
|
||||
node: {
|
||||
nameSingular: true,
|
||||
fields: {
|
||||
__args: { paging: { first: 500 } },
|
||||
edges: { node: { name: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const obj = objects.edges
|
||||
.map((e: { node: { nameSingular: string } }) => e.node)
|
||||
.find((n: { nameSingular: string }) => n.nameSingular === 'postCard');
|
||||
expect(obj).toBeDefined();
|
||||
|
||||
const names = obj!.fields.edges.map(
|
||||
(e: { node: { name: string } }) => e.node.name,
|
||||
);
|
||||
expect(names).toContain('name');
|
||||
expect(names).toContain('content');
|
||||
expect(names).toContain('status');
|
||||
expect(names).toContain('deliveredAt');
|
||||
expect(names).toContain('recipient');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { beforeAll } from 'vitest';
|
||||
|
||||
const CONFIG_DIR = path.join(os.homedir(), '.twenty');
|
||||
const CONFIG_PATH = path.join(CONFIG_DIR, 'config.test.json');
|
||||
|
||||
beforeAll(async () => {
|
||||
const apiUrl = process.env.TWENTY_API_URL!;
|
||||
const token = process.env.TWENTY_API_KEY!;
|
||||
|
||||
if (!apiUrl || !token) {
|
||||
throw new Error(
|
||||
'TWENTY_API_URL and TWENTY_API_KEY must be set.\n' +
|
||||
'Start a local server: yarn twenty server start\n' +
|
||||
'Or set them in vitest env config.',
|
||||
);
|
||||
}
|
||||
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await fetch(`${apiUrl}/healthz`);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Twenty server is not reachable at ${apiUrl}. ` +
|
||||
'Make sure the server is running before executing integration tests.',
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server at ${apiUrl} returned ${response.status}`);
|
||||
}
|
||||
|
||||
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
CONFIG_PATH,
|
||||
JSON.stringify(
|
||||
{
|
||||
remotes: {
|
||||
local: { apiUrl, apiKey: token },
|
||||
},
|
||||
defaultRemote: 'local',
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
process.env.TWENTY_APP_ACCESS_TOKEN ??= token;
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineAgent } from 'twenty-sdk/define';
|
||||
import { defineAgent } from 'twenty-sdk';
|
||||
|
||||
export default defineAgent({
|
||||
universalIdentifier: 'b8d4f2a3-9c5e-4f7b-a012-3e4d5c6b7a8f',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from './roles/default-function.role';
|
||||
|
||||
export const APPLICATION_UNIVERSAL_IDENTIFIER =
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { useRecordId } from 'twenty-sdk/front-component';
|
||||
import { defineFrontComponent, useRecordId } from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
|
||||
+7
-2
@@ -1,6 +1,11 @@
|
||||
import { useEffect } from 'react';
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { useRecordId, updateProgress, enqueueSnackbar, unmountFrontComponent } from 'twenty-sdk/front-component';
|
||||
import {
|
||||
defineFrontComponent,
|
||||
useRecordId,
|
||||
updateProgress,
|
||||
enqueueSnackbar,
|
||||
unmountFrontComponent,
|
||||
} from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
|
||||
|
||||
+7
-2
@@ -1,6 +1,11 @@
|
||||
import { useEffect } from 'react';
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { useRecordId, updateProgress, enqueueSnackbar, unmountFrontComponent } from 'twenty-sdk/front-component';
|
||||
import {
|
||||
defineFrontComponent,
|
||||
useRecordId,
|
||||
updateProgress,
|
||||
enqueueSnackbar,
|
||||
unmountFrontComponent,
|
||||
} from 'twenty-sdk';
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
import { defineField, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
|
||||
// Field on existing company object
|
||||
export default defineField({
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { defineField, FieldType, RelationType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
RelationType,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
|
||||
import {
|
||||
POST_CARDS_ON_PERSON_ID,
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { defineField, FieldType, RelationType, OnDeleteAction, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';
|
||||
import {
|
||||
defineField,
|
||||
FieldType,
|
||||
RelationType,
|
||||
OnDeleteAction,
|
||||
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-sdk';
|
||||
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
|
||||
|
||||
export const RECIPIENT_ON_POST_CARD_ID = 'c44f158e-2747-42c6-9295-75b8cbae7039';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CoreApiClient } from 'twenty-client-sdk/core';
|
||||
import { definePostInstallLogicFunction } from 'twenty-sdk/define';
|
||||
import { definePostInstallLogicFunction } from 'twenty-sdk';
|
||||
|
||||
const SEED_POST_CARDS = [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { definePreInstallLogicFunction } from 'twenty-sdk/define';
|
||||
import { definePreInstallLogicFunction } from 'twenty-sdk';
|
||||
|
||||
const handler = async (params: any) => {
|
||||
console.log(
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineNavigationMenuItem } from 'twenty-sdk/define';
|
||||
import { defineNavigationMenuItem } from 'twenty-sdk';
|
||||
import { NavigationMenuItemType } from 'twenty-shared/types';
|
||||
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineObject, FieldType } from 'twenty-sdk/define';
|
||||
import { defineObject, FieldType } from 'twenty-sdk';
|
||||
|
||||
enum PostCardStatus {
|
||||
DRAFT = 'DRAFT',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk/define';
|
||||
import { definePageLayout, PageLayoutTabLayoutMode } from 'twenty-sdk';
|
||||
import { POST_CARD_UNIVERSAL_IDENTIFIER } from 'src/objects/post-card.object';
|
||||
import { CARD_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from 'src/components/card.front-component';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PermissionFlag, defineRole } from 'twenty-sdk/define';
|
||||
import { PermissionFlag, defineRole } from 'twenty-sdk';
|
||||
import {
|
||||
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
POST_CARD_UNIVERSAL_IDENTIFIER,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineSkill } from 'twenty-sdk/define';
|
||||
import { defineSkill } from 'twenty-sdk';
|
||||
|
||||
export default defineSkill({
|
||||
universalIdentifier: 'a7c3e1f2-8b4d-4e6a-9f01-2d3c4b5a6e7f',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineView } from 'twenty-sdk/define';
|
||||
import { defineView } from 'twenty-sdk';
|
||||
import {
|
||||
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
NAME_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020';
|
||||
const TWENTY_API_KEY =
|
||||
process.env.TWENTY_API_KEY ??
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjQ4OTE0NDk2MDAsImp0aSI6IjIwMjAyMDIwLWY0MDEtNGQ4YS1hNzMxLTY0ZDAwN2MyN2JhZCJ9.bfQjfyN0NEtTCLE_xPyNcwonDzlSXFoP8kdCQTdnuDc';
|
||||
|
||||
// Make env vars available to globalSetup (test.env only applies to workers)
|
||||
process.env.TWENTY_API_URL = TWENTY_API_URL;
|
||||
process.env.TWENTY_API_KEY = TWENTY_API_KEY;
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
tsconfigPaths({
|
||||
@@ -20,12 +11,14 @@ export default defineConfig({
|
||||
test: {
|
||||
testTimeout: 120_000,
|
||||
hookTimeout: 120_000,
|
||||
fileParallelism: false,
|
||||
include: ['src/**/*.integration-test.ts'],
|
||||
globalSetup: ['src/__tests__/global-setup.ts'],
|
||||
setupFiles: ['src/__tests__/setup-test.ts'],
|
||||
env: {
|
||||
TWENTY_API_URL,
|
||||
TWENTY_API_KEY,
|
||||
TWENTY_API_URL: process.env.TWENTY_API_URL ?? 'http://localhost:2020',
|
||||
TWENTY_API_KEY:
|
||||
process.env.TWENTY_API_KEY ??
|
||||
// Tim Apple (admin) access token for twenty-app-dev
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ1c2VySWQiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtOWUzYi00NmQ0LWE1NTYtODhiOWRkYzJiMDM1IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjQ5MDQ4ODE3MDR9.9S4wc0MOr5iczsomlFxZdOHD1IRDS4dnRSwNVNpctF4',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -3317,8 +3317,8 @@ __metadata:
|
||||
oxlint: "npm:^0.16.0"
|
||||
react: "npm:^19.0.0"
|
||||
react-dom: "npm:^19.0.0"
|
||||
twenty-client-sdk: "npm:0.9.0"
|
||||
twenty-sdk: "npm:0.9.0"
|
||||
twenty-client-sdk: "npm:0.8.0-canary.8"
|
||||
twenty-sdk: "npm:0.8.0-canary.8"
|
||||
typescript: "npm:^5.9.3"
|
||||
vite-tsconfig-paths: "npm:^4.2.1"
|
||||
vitest: "npm:^3.1.1"
|
||||
@@ -4059,21 +4059,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"twenty-client-sdk@npm:0.9.0":
|
||||
version: 0.9.0
|
||||
resolution: "twenty-client-sdk@npm:0.9.0"
|
||||
"twenty-client-sdk@npm:0.8.0-canary.8":
|
||||
version: 0.8.0-canary.8
|
||||
resolution: "twenty-client-sdk@npm:0.8.0-canary.8"
|
||||
dependencies:
|
||||
"@genql/cli": "npm:^3.0.3"
|
||||
"@genql/runtime": "npm:^2.10.0"
|
||||
esbuild: "npm:^0.25.0"
|
||||
graphql: "npm:^16.8.1"
|
||||
checksum: 10c0/4b42a6622a9852fc3eca50c1131b116c5602af006ee5f1d3b4f1e97721bbc8ef5c2f3b60d9dee3ca9ca8c3c7ad4b292a7b55007b779b4c042997dbc29940ba54
|
||||
checksum: 10c0/acb5bf952a9729811235a3474ccb4db82630c53a2caed03176bfb4f442576ee2ef7e625886f63714e2534f7ec83b03d83e4c0b1170a0eb816c531acfc2c98010
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"twenty-sdk@npm:0.9.0":
|
||||
version: 0.9.0
|
||||
resolution: "twenty-sdk@npm:0.9.0"
|
||||
"twenty-sdk@npm:0.8.0-canary.8":
|
||||
version: 0.8.0-canary.8
|
||||
resolution: "twenty-sdk@npm:0.8.0-canary.8"
|
||||
dependencies:
|
||||
"@genql/cli": "npm:^3.0.3"
|
||||
"@genql/runtime": "npm:^2.10.0"
|
||||
@@ -4093,7 +4093,7 @@ __metadata:
|
||||
react: "npm:^19.0.0"
|
||||
react-dom: "npm:^19.0.0"
|
||||
tinyglobby: "npm:^0.2.15"
|
||||
twenty-client-sdk: "npm:0.9.0"
|
||||
twenty-client-sdk: "npm:0.8.0-canary.8"
|
||||
typescript: "npm:^5.9.2"
|
||||
uuid: "npm:^13.0.0"
|
||||
vite: "npm:^7.0.0"
|
||||
@@ -4101,7 +4101,7 @@ __metadata:
|
||||
zod: "npm:^4.1.11"
|
||||
bin:
|
||||
twenty: dist/cli.cjs
|
||||
checksum: 10c0/27f93e5edac3265f819abacc853598435718020258a95d55518562e086e42daabae784964b42005d8e4ff30d1d6f13a12a38c656e18c60bad98da3f579a8e1c3
|
||||
checksum: 10c0/a22cf071f41c19d769e68a995912a0bda0f087bd9a295534bf9e545544f6dfc84f284a477f9011fc135f2a44de9372b977a66de06454e760822119e76921ea69
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from './my.role';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineRole } from 'twenty-sdk/define';
|
||||
import { defineRole } from 'twenty-sdk';
|
||||
|
||||
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
|
||||
'9f992b6c-17e9-4381-bab5-b6150b574304';
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-sdk": "latest",
|
||||
"twenty-client-sdk": "latest"
|
||||
"twenty-sdk": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3",
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import { defineLogicFunction } from 'twenty-sdk';
|
||||
|
||||
export const ADD_NUMBERS_UNIVERSAL_IDENTIFIER =
|
||||
'f9e5589c-e951-4d99-85db-0a305ab53502';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: 'invalid-app-0000-0000-0000-000000000001',
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-sdk": "latest",
|
||||
"twenty-client-sdk": "latest"
|
||||
"twenty-sdk": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineObject, FieldType } from 'twenty-sdk/define';
|
||||
import { defineObject, FieldType } from 'twenty-sdk';
|
||||
|
||||
const DUPLICATE_ID = 'duplicate-id-0000-0000-000000000001';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineObject, FieldType } from 'twenty-sdk/define';
|
||||
import { defineObject, FieldType } from 'twenty-sdk';
|
||||
|
||||
const DUPLICATE_ID = 'duplicate-id-0000-0000-000000000001';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
import { defineApplication } from 'twenty-sdk';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000001',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineFrontComponent } from 'twenty-sdk/define';
|
||||
import { defineFrontComponent } from 'twenty-sdk';
|
||||
|
||||
export const MyComponent = () => {
|
||||
return (
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user