Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 99 additions & 24 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ This is a **generator repository** that creates n8n community nodes from Apify A
## Quick Commands

```bash
npm run create-actor-app # Generate a new node from an Actor ID
npm run build # Compile TypeScript + copy icons
npm run dev # Run n8n locally with hot reload
npm test # Run tests (none exist yet)
npm run lint # Check code quality
npm run init-actor-app # Initialize a new Actor app from scratch
npm run add-actor-resource # Add a new resource to existing Actor (WIP)
npm run add-actor-operation # Add a new operation to existing resource (WIP)
npm run build # Compile TypeScript + copy icons
npm run dev # Run n8n locally with hot reload
npm test # Run tests (none exist yet)
npm run lint # Check code quality
```

---
Expand All @@ -36,10 +38,16 @@ These files serve as the blueprint for all generated nodes:
- Uses placeholders like `$$ACTOR_ID`, `$$CLASS_NAME` that get replaced

### Resources
- **`resources/`** - Contains operation definitions and routing logic
- **`resources/resources.ts`** - Router file that handles operation selection
- **`resources/properties/operation*.ts`** - Individual operation files with their properties and execute functions
- Gets **completely regenerated** during setup based on operation count
- **`resources/`** - Contains resource and operation definitions with routing logic
- **`resources/router.ts`** - Main router that merges all resources and delegates to resource-specific routers
- **`resources/resource_one/`** - Individual resource folder (supports multiple resources)
- **Note**: `resource_one` is a **dynamically generated name** based on user input during script execution
- **`resource.ts`** - Resource-level file that merges operations and routes to operation handlers
- **`operations/`** - Folder containing operation files
- **`operation_one.ts`** - Individual operation with properties and execute function (name generated from user input)
- **`operation_two.ts`** - Individual operation with properties and execute function (name generated from user input)
- Gets **completely regenerated** during setup based on resource and operation count
- **All folder/file names with underscores** (e.g., `resource_one`, `operation_one`) are **custom-named by the generator script** based on user input

### Helpers
- **`helpers/executeActor.ts`** - Actor build and execution utilities
Expand Down Expand Up @@ -68,9 +76,40 @@ These files serve as the blueprint for all generated nodes:

Location: `scripts/`

### Main Flow
### Script Structure

The scripts are organized into three command folders:

```
scripts/
├── cli.ts # Main router that handles command routing
├── utils.ts # Shared utilities and user input functions
├── types.ts # Shared TypeScript types
├── init-actor-app/ # Initialize new Actor app
│ ├── setupProject.ts # Main orchestrator
│ ├── actorConfig.ts # Placeholder generation
│ ├── actorSchemaConverter.ts # Schema conversion
│ ├── createActorApp.ts # Actor metadata fetching
│ ├── generateOperations.ts # Operations structure generation
│ └── refactorProject.ts # File renaming
├── add-actor-resource/ # Add new resource (WIP)
│ └── index.ts
└── add-actor-operation/ # Add new operation (WIP)
└── index.ts
```

**IMPORTANT**: All user input functions MUST be in `utils.ts`. This includes:
- `askForInput()` - Generic input prompt
- `askForActorId()` - Ask for Actor ID
- `askForOperationCount()` - Ask for operation count with validation
- `packageNameCheck()` - Validate and check npm package availability

Never create readline/input prompts in individual script files. Always use or extend the functions in `utils.ts`.

### Main Flow: init-actor-app

**`setupProject.ts`** - Orchestrates the entire generation process:
1. Prompts user for Actor ID and operation count
1. Prompts user for Actor ID and operation count (via `utils.ts` functions)
2. Calls `setConfig()` to create placeholder values
3. Calls `generateOperationsStructure()` to create resources/operations structure
4. Calls `refactorProject()` to rename files/folders
Expand All @@ -85,10 +124,13 @@ Location: `scripts/`
- `$$X_PLATFORM_APP_HEADER_ID` → `instagram-scraper-app`

**`generateOperations.ts`** - Generates resources/operations structure:
- Creates `resources/` directory with operation files
- Generates `resources/resources.ts` router file
- Creates individual operation files in `resources/properties/`
- Each operation has its own properties and execute function
- Creates `resources/` directory with resource folders
- Generates `resources/router.ts` main router file
- Creates individual resource folders with **custom names based on user input** (e.g., `resource_one/` where `resource_one` is dynamically generated)
- Each resource has its own `resource.ts` file that merges operations
- Creates `operations/` subfolder within each resource
- Each operation file is **dynamically named** based on user input (e.g., `operation_one.ts`)
- Each operation file defines its own operation name constant and contains properties and execute function

**`actorSchemaConverter.ts`** - Converts Apify schema → n8n properties:

Expand Down Expand Up @@ -117,11 +159,13 @@ Location: `scripts/`
## Generation Flow

```
User runs: npm run create-actor-app
User runs: npm run init-actor-app
Prompt for Actor ID (e.g., "apify/instagram-scraper")
cli.ts routes to 'init' command
Prompt for operation count (1-10, default 2)
Prompt for Actor ID (e.g., "apify/instagram-scraper") via askForActorId()
Prompt for operation count (1-10, default 1) via askForOperationCount()
Fetch Actor metadata via ApifyClient
Expand Down Expand Up @@ -151,6 +195,26 @@ export class ApifyActorName implements INodeType {
}
```

### Resource and Operation Structure
The new multi-resource architecture supports multiple resources per node:

```
resources/
├── router.ts # Main router - merges all resources
└── resource_one/ # Dynamically named based on user input
├── resource.ts # Resource router - merges operations
└── operations/
├── operation_one.ts # Dynamically named - Defines OPERATION_1_NAME constant
└── operation_two.ts # Dynamically named - Defines OPERATION_2_NAME constant
```

**Key Design Principles:**
- **Dynamic naming**: All folder/file names with underscores (e.g., `resource_one`, `operation_one`) are **generated by the script based on user input** during node generation
- **Single RESOURCE_NAME variable**: Each resource defines one `RESOURCE_NAME` constant used throughout that resource
- **Operation names in operation files**: Each operation file exports its own `OPERATION_X_NAME` constant
- **Resource-level routing**: Each `resource.ts` imports operation names and routes to the correct operation handler
- **Top-level routing**: `router.ts` re-exports constants and delegates to resource-specific routers

### Apify Actor Execution Flow
1. `getDefaultBuild()` → GET `/v2/acts/{actorId}/builds/default`
2. `getDefaultInputsFromBuild()` → Extract prefill values
Expand Down Expand Up @@ -188,15 +252,23 @@ Search for `SNIPPET` in generated code to find these:
| File | Purpose |
|------|---------|
| `nodes/ApifyActorTemplate/ApifyActorTemplate.node.ts` | Main node template |
| `nodes/ApifyActorTemplate/resources/router.ts` | Main router merging all resources |
| `nodes/ApifyActorTemplate/resources/resource_one/resource.ts` | Resource router merging operations (folder/file dynamically named) |
| `nodes/ApifyActorTemplate/resources/resource_one/operations/operation_one.ts` | Individual operation file (dynamically named) |
| `nodes/ApifyActorTemplate/helpers/executeActor.ts` | Actor execution logic |
| `nodes/ApifyActorTemplate/helpers/genericFunctions.ts` | API utilities |
| `scripts/setupProject.ts` | Main orchestrator |
| `scripts/actorSchemaConverter.ts` | Schema conversion |
| `scripts/actorConfig.ts` | Placeholder generation |
| `scripts/refactorProject.ts` | File renaming |
| `scripts/cli.ts` | Main router for all commands |
| `scripts/utils.ts` | Shared utilities & user input functions |
| `scripts/types.ts` | Shared TypeScript types |
| `scripts/init-actor-app/setupProject.ts` | Main orchestrator for init command |
| `scripts/init-actor-app/actorSchemaConverter.ts` | Schema conversion |
| `scripts/init-actor-app/actorConfig.ts` | Placeholder generation |
| `scripts/init-actor-app/refactorProject.ts` | File renaming |
| `credentials/ApifyApi.credentials.ts` | API key auth |
| `package.json` | Dependencies & n8n node registration |

**Note**: Files/folders with underscore naming (e.g., `resource_one`, `operation_one`) are dynamically generated based on user input during script execution.

---

## Common Tasks
Expand Down Expand Up @@ -227,8 +299,11 @@ Edit `nodes/ApifyActorTemplate/helpers/genericFunctions.ts` → add headers in `
### What Gets Regenerated vs. Copied

**Regenerated (not direct copies):**
- `ApifyActorTemplate.properties.ts` - Completely rebuilt from Actor's input schema
- `properties.json` - Generated from converted schema
- `resources/router.ts` - Main router merging all resources
- `resources/resource_*/resource.ts` - Resource routers merging operations (folders/files dynamically named)
- `resources/resource_*/operations/*.ts` - Individual operation files with properties (dynamically named)
- Generated completely from Actor's input schema and operation count
- **Note**: The `*` in paths represents dynamically generated names based on user input (e.g., `resource_one`, `operation_one`)

**Copied & modified (placeholders replaced):**
- `ApifyActorTemplate.node.ts` - Class names and constants updated
Expand Down
Empty file removed index.js
Empty file.
4 changes: 0 additions & 4 deletions nodes/ApifyActorTemplate/ApifyActorTemplate.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ export const X_PLATFORM_APP_HEADER_ID = '$$X_PLATFORM_APP_HEADER_ID' as string;
export const DISPLAY_NAME = '$$DISPLAY_NAME' as string;
export const DESCRIPTION = '$$DESCRIPTION' as string;

// SNIPPET 6: Resource and Operation name constants (edit in resources/router.ts)
// These are imported from resources/router.ts - modify them there
export { RESOURCE_NAME, OPERATION_1_NAME, OPERATION_2_NAME } from './resources/router';

export class ApifyActorTemplate implements INodeType {
description: INodeTypeDescription = {
displayName: DISPLAY_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import {
option as operation1Option,
properties as operation1Properties,
execute as executeOperation1,
} from './operations/operation_one';
} from './operations/operationOne';
import {
OPERATION_2_NAME,
option as operation2Option,
properties as operation2Properties,
execute as executeOperation2,
} from './operations/operation_two';
} from './operations/operationTwo';

// Resource name constant
export const RESOURCE_NAME = '$$RESOURCE_NAME';
Expand Down Expand Up @@ -49,7 +49,7 @@ export const operationSelect: INodeProperties = {
export const properties: INodeProperties[] = [
operationSelect,
...operation1Properties,
...operation2Properties,
...operation2Properties
];

// Router for this resource
Expand Down
6 changes: 3 additions & 3 deletions nodes/ApifyActorTemplate/resources/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import {
resourceOption as resource1Option,
properties as resource1Properties,
router as resource1Router,
} from './resource_one/resource';
} from './resourceOne/resource';

// Re-export resource and operation names for backward compatibility
export const RESOURCE_NAME = RESOURCE_1_NAME;
export { OPERATION_1_NAME } from './resource_one/operations/operation_one';
export { OPERATION_2_NAME } from './resource_one/operations/operation_two'
export { OPERATION_1_NAME } from './resourceOne/operations/operationOne';
export { OPERATION_2_NAME } from './resourceOne/operations/operationTwo'

// Resource selector with all resources
const resourceSelect: INodeProperties[] = [
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
"lint": "n8n-node lint",
"lint:fix": "n8n-node lint --fix",
"merge:api": "npx openapi-merge-cli --config ./openapi.config.json",
"create-actor-app": "npx tsx scripts/cli.ts"
"init-actor-app": "npx tsx scripts/cli.ts init",
"add-actor-resource": "npx tsx scripts/cli.ts add-resource",
"add-actor-operation": "npx tsx scripts/cli.ts add-operation"
},
"files": [
"dist"
Expand Down
63 changes: 0 additions & 63 deletions scripts/actorConfig.ts

This file was deleted.

Loading