LogoCyanPrint
ProcessorsReference

Project Structure

Standard file layout for processor projects

Project Structure

A processor project follows a standard layout for consistency and ease of development.

Basic Structure

index.ts
package.json
bun.lockb
Dockerfile
cyan.yaml
tsconfig.json

File Descriptions

index.ts

The main entry point using StartProcessorWithLambda:

index.ts
import { StartProcessorWithLambda } from '@atomicloud/cyan-sdk';
StartProcessorWithLambda(async (input, fileHelper) => {
const files = fileHelper.resolveAll();
files.forEach(file => {
// Transform file content
file.content = transform(file.content);
file.writeFile();
});
return { directory: input.writeDirectory };
});
main.py
from atomicloud_cyan_sdk import start_processor_with_lambda
async def handler(input, file_helper):
files = file_helper.resolve_all()
for file in files:
# Transform file content
file.content = transform(file.content)
file.write_file()
return {"directory": input.write_directory}
start_processor_with_lambda(handler)
Program.cs
using AtomiLoud.CyanSdk;
await Processor.StartAsync(async (input, fileHelper) =>
{
var files = fileHelper.ResolveAll();
foreach (var file in files)
{
// Transform file content
file.Content = Transform(file.Content);
file.WriteFile();
}
return new ProcessorOutput { Directory = input.WriteDirectory };
});

package.json

Define dependencies and scripts:

package.json
{
"name": "my-processor",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "bun run index.ts",
"build": "bun build index.ts --outdir=dist"
},
"dependencies": {
"@atomicloud/cyan-sdk": "^1.0.0"
},
"devDependencies": {
"@types/bun": "latest"
}
}

Dockerfile

Container definition for the processor:

Dockerfile
FROM oven/bun:1.1.31
WORKDIR /app
# Required: Mark as CyanPrint processor
LABEL cyanprint.dev=true
# Install dependencies
COPY package.json bun.lockb* ./
RUN bun install --frozen-lockfile
# Copy processor code
COPY . .
# Run processor
CMD ["bun", "run", "index.ts"]

The LABEL cyanprint.dev=true line is required for the container to be recognized as a CyanPrint processor.

cyan.yaml

Metadata and documentation:

cyan.yaml
name: myorg/my-processor
version: 1.0.0
description: Description of what the processor does
author: Your Name
license: MIT
processor:
inputs:
- name: option1
type: string
default: "value"
description: Description of the option

tsconfig.json

TypeScript configuration:

tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true
},
"include": ["*.ts", "src/**/*.ts"]
}

Optional Directories

src/

Organize larger processors into modules:

index.ts

tests/

Unit tests for processor logic:

transforms.test.ts
utils.test.ts

Multi-File Example

For complex processors, split logic into modules:

index.ts
// index.ts
import { StartProcessorWithLambda } from '@atomicloud/cyan-sdk';
import { transformMarkdown } from './src/transforms/markdown';
import { transformCode } from './src/transforms/code';
StartProcessorWithLambda(async (input, fileHelper) => {
const files = fileHelper.resolveAll();
const config = input.config as ProcessorConfig;
files.forEach(file => {
if (file.relative.endsWith('.md')) {
file.content = transformMarkdown(file.content, config);
} else if (file.relative.endsWith('.ts')) {
file.content = transformCode(file.content, config);
}
file.writeFile();
});
return { directory: input.writeDirectory };
});
main.py
# main.py
from atomicloud_cyan_sdk import start_processor_with_lambda
from .transforms.markdown import transform_markdown
from .transforms.code import transform_code
async def handler(input, file_helper):
files = file_helper.resolve_all()
config = input.config # Cast to your config type
for file in files:
if file.relative.endswith('.md'):
file.content = transform_markdown(file.content, config)
elif file.relative.endswith('.ts'):
file.content = transform_code(file.content, config)
file.write_file()
return {"directory": input.write_directory}
start_processor_with_lambda(handler)
Program.cs
// Program.cs
using AtomiLoud.CyanSdk;
using MyProcessor.Transforms;
await Processor.StartAsync(async (input, fileHelper) =>
{
var files = fileHelper.ResolveAll();
var config = input.Config; // Cast to your config type
foreach (var file in files)
{
if (file.Relative.EndsWith(".md"))
{
file.Content = MarkdownTransform.Transform(file.Content, config);
}
else if (file.Relative.EndsWith(".ts"))
{
file.Content = CodeTransform.Transform(file.Content, config);
}
file.WriteFile();
}
return new ProcessorOutput { Directory = input.WriteDirectory };
});