A sample ByteChef embedded catalog code project written in JavaScript. The whole project is one file,
src/sample_catalog_code_project.js, and that file is what you deploy - there
is no build step. The file is a single parenthesized object expression, ({ ... }). The server evaluates it and
reads the object's name, description, version and workflows, then calls each task's perform(context)
when the workflow runs. Keep it a bare expression: a bundler or module wrapper hides the object from the server.
A catalog project is an ordinary automation code project - the same format the automation ProjectHandler path
parses - imported under Embedded → Automations (the Automation Workflows page) instead of Automation → Projects.
Importing publishes it to the embedded catalog straight away. A catalog workflow is called through the embedded public
endpoints by its request or app-event (appEvent/newEvent) trigger, or runs on its own when a component
trigger such as Gmail New Email starts it. A workflow with no trigger that can start it - none, or only a manual
one - still imports, but the import returns a warning for it (the UI keeps the dialog open and shows the warning).
The project, "Sample Catalog Code Project JavaScript", has four workflows:
greetOnRequest, started by arequest/v1/autoRespondWithHTTP200trigger. It runs one task,greet, that logs and returns a greeting, and exposes that as thegreetingoutput.summarizeNewEmail, started by the Gmail New Email polling trigger (googleMail/v1/newEmailPolling). It runs once for every new email in the connected user's inbox and returns a one-line summary as thesummaryoutput. It has no request trigger, so it needs no call - once provisioned and enabled it runs whenever an email arrives.fetchRecentEmails, started by arequest/v1/awaitWorkflowAndRespondtrigger. ItsfetchEmailstask calls the Gmail Search Email action and returns the matching messages as theemailsoutput. The optional request body{"from": "...", "maxResults": 5}narrows the search.notifySlackOnNewEmail, started by the Gmail New Email trigger, with a requiredchannelinput; its options come from Slack's ownchannelinput (componentName,componentVersionandgroupNameon the input), so it is picked from the Slack workspace's channels. ItspostToSlacktask calls the Slack Send Channel Message action, so it declares aslackconnection and passes its name. Provisioning binds it to one of the connected user's Slack connections; a user with none gets the reference created disabled and a409namingslack.
A task names the connections it uses and calls a component action through one of them:
connections: [{componentName: "googleMail", name: "gmail"}],
perform: function (context) {
return context.component.googleMail.searchEmail({maxResults: 10}, "gmail");
}When a connected user provisions a reference to a workflow, ByteChef binds every declared connection, and every
component trigger, to one of that user's connections on the same component - for example the one they created when
they connected a Gmail integration. Pass {"connections": {"googleMail": <connectionId>}} in the provision body to pick
one. A user with no Gmail connection gets the reference created disabled and a 409 naming the missing component
(missingConnectionComponentName).
npm run checkEvaluates the file the same way the server does, checks its shape and runs each task once with a stub context. It needs only Node.js; the JavaScript file has no dependencies to install.
src/sample_catalog_code_project.ts is the same project written in TypeScript. It
takes its types from @bytechef/workflow-api through a
/// <reference types="@bytechef/workflow-api" /> directive and ends in satisfies ByteChef.ProjectDefinition, so
context is typed inside every perform and a missing name or a misspelled perform fails the build. The server
runs only JavaScript, so compile the file and deploy the output:
npm install
npm run check:tscheck:ts compiles the file to dist/sample_catalog_code_project.js and runs the same check on it. Deploy
dist/sample_catalog_code_project.js in place of src/sample_catalog_code_project.js; the directive and satisfies
leave nothing behind, so the output is the same bare ({ ... }) expression. Don't import or export anything in the
.ts file: either one turns it into a module, the output stops being a bare expression and the check fails. It is named
"Sample Catalog Code Project TypeScript", so deploying it publishes a catalog project of its own next to the JavaScript
one.
Upload src/sample_catalog_code_project.js. Deploying a project with the same name again publishes a new version of
that catalog project instead of creating a second one.
Embedded → Automations → the arrow next to New Project → Import Code Project, then pick the file.
POST /api/embedded/v1/automation-project-code-workflows/deploy with a multipart/form-data body holding one file
part, projectFile: the .js file. The file name must end in .js; the server picks the language from the
extension. A successful deploy returns 200 with the import warnings, for example {"warnings": []}.
GET /api/embedded/v1/automation-project-code-workflows lists the published catalog projects.
Authenticate with Authorization: Bearer <API key>, using an Embedded API key (Embedded → Settings →
API Keys) that belongs to an administrator - deploying requires the admin role. This endpoint takes only a typed
API key: an organization admin key (Settings → Organization → Admin API Keys) is rejected with 401. The key is
looked up in the environment named by the X-ENVIRONMENT header (DEVELOPMENT, STAGING or PRODUCTION;
PRODUCTION when the header is absent), so send the environment the key was created in. The request runs as the
key's own ByteChef user, not as a connected user.
curl -X POST "$BYTECHEF_URL/api/embedded/v1/automation-project-code-workflows/deploy" \
-H "Authorization: Bearer $BYTECHEF_EMBEDDED_API_KEY" \
-H "X-ENVIRONMENT: DEVELOPMENT" \
-F "projectFile=@src/sample_catalog_code_project.js"BYTECHEF_URL is the server's base URL, for example http://localhost:9555 for a local development server.