mcpField
F
fcode-javascript

fcode-javascript

github.com/factorialco开发1400 次安装今天更新
代码仓库

关于 fcode-javascript

fcode-javascript 提供在 Factorial Code 上编写 JavaScript 流程的指南,运行时为 Node.js v22。内容涵盖参数、日志、存储、变量、邮件和执行结果等平台 API。

主要功能

  1. 01使用异步 main 入口组织流程
  2. 02读取参数和平台元数据
  3. 03使用数据存储、文件存储和变量
  4. 04通过共享 fcode-logs 模块记录日志
  5. 05发送邮件并返回流程结果

适用场景

  1. 01在 Factorial Code 上实现 JavaScript 流程
  2. 02持久化流程数据和凭据
  3. 03通过分级日志跟踪执行
  4. 04从流程发送邮件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/factorialco/factorial-code-skills --skill fcode-javascript

安装后在 Claude Code 中输入/fcode-javascript确认已加载。

详细介绍

Factorial Code — JavaScript

在 Factorial Code 上运行的 JavaScript 编写指南。运行时为 Node.js v22。平台模型(进程、模块、数据存储)请参阅 fcode-core-concepts。

方面指南
运行时Node.js v22
进程入口文件index.js
入口点async function main()
导出(必需)module.exports = { main }
参数fcode.context.parameters
变量process.env.X 或 fcode.env.X
导入模块fcode.import("module-slug")

注意事项

  • 始终导出 main:module.exports = { main }。否则进程 无法运行。
  • 切勿自行调用 main() —— Factorial Code 会调用它。
  • fcode.import() 的名称必须是硬编码的字符串字面量,不能使用变量: fcode.import("shopify-client") ✅,fcode.import(name) ❌。
  • 切勿为 fcode.i18n 设置别名 —— 必须直接调用(fcode.i18n("key") ✅, const t = fcode.i18n ❌):使用别名调用会在运行时抛出 "i18n is disabled"。 请参阅 fcode-i18n。
  • 数据存储只保存字符串/数字 —— 对象在调用 set 前使用 JSON.stringify, 调用 get 后再解析。
  • 加密保存在数据存储中的机密信息 —— 将 true 作为 set 的第三个参数传入 (fcode.datastore.set(key, token, true));get 会自动解密。普通的 set 会以明文保存值。
  • 所有异步操作都使用 async/await;在主流程外层使用 try/catch,通过 fcode-logs 记录捕获的错误及上下文(请参阅“日志记录”),并抛出可采取行动的错误。 使用 const/let,切勿使用 var。
  • 切勿硬编码或记录机密信息 —— 从 process.env 读取。

进程模板

async function main() {
  const { parameters } = fcode.context;

  // Your code here

  return { message: "Success!" };
}

module.exports = { main };

辅助工具

// Execution / process / schedule metadata
const { id, comment } = fcode.execution;
const { id: processId, name: processName } = fcode.execution.process;
const { id: scheduleId } = fcode.execution.schedule; // when run from a schedule
const timezone = fcode.execution.timezone;

// Workspace (team) metadata
const teamSlug = fcode.team.slug;

// Environment variables (secrets/config)
const apiKey = process.env.API_KEY; // or fcode.env.API_KEY

// Import a Factorial Code module (hardcoded name only)
const { myFunc } = fcode.import("module-name");
const { myFunc: v1 } = fcode.import("module-name", "v1.0.0"); // pinned version tag or alias

// Run another process
await fcode.processes.run("process-identifier", options);

// Translations (workspace locales — see fcode-i18n)
const greeting = fcode.i18n("greetings.hello", { name: "Ada" }); // %{name} filled in
fcode.i18n("greetings.hello", { name: "Ada" }, { locale: "es" }); // another locale, this lookup only (value may be dynamic)
const locale = fcode.i18n.locale; // the execution's locale

日志记录

通过共享的 fcode-logs 模块记录日志 —— 每个工作区都会继承按级别过滤的日志记录。 该模块读取团队变量 LOG_LEVEL (debug | info | warn | error,默认值为 info),并转发到相应的 console.*,因此调用处可以像直接调用 console 一样简洁:

const log = fcode.import("fcode-logs"); // import once; reuse `log` everywhere, including `catch`

log.info("sync started", { processSlug }); // console.log  when LOG_LEVEL ≤ info
log.debug({ requestPayload });              // console.debug only when LOG_LEVEL=debug
log.warn("token missing — skipping");       // console.warn  when LOG_LEVEL ≤ warn
log.error("sync failed", err.message);       // console.error — always emitted

记录尽可能详细 —— 日志策略(在 info 级别记录开始/结束、外部调用和决策; 在 debug 级别记录负载;始终在 catch 中记录上下文后再重新抛出错误)见 fcode-core-concepts §General rules。在本地或开发工作区中设置 LOG_LEVEL=debug 以跟踪完整运行过程;生产环境保持为 info。 切勿记录机密信息。每次执行最多保留 500 行日志/500 KB —— 后续条目将被丢弃 (fcode-core-concepts › Plans & limits)。

依赖项

外部 npm 包会自动安装 —— 直接 require 即可。如果导入名称与包名不同, 请使用 @add-package 声明:

// @add-package axios
const axios = require("axios");

父工作区提供的包已在此安装 —— 无需重复声明(请参阅 fcode-core-concepts)。

数据存储与存储

// Datastore (strings/numbers only)
await fcode.datastore.set("key", "value");
await fcode.datastore.set("key", JSON.stringify({ name: "John", age: 30 }));
const value = await fcode.datastore.get("key");
await fcode.datastore.del("key");
// Encrypted at rest with a key owned by the workspace — for tokens, credentials,
// personal data. The third argument must be a boolean; get() is transparent.
// Keys (entry names) are never encrypted.
await fcode.datastore.set("oauth.token", accessToken, true);
const token = await fcode.datastore.get("oauth.token");

// Storage (files)
const fs = require("node:fs");
const path = require("node:path");
const localPath = path.join(process.env.TMP_DATA_DIR, "localfile.txt");

await fcode.storage.upload("path/myfile.txt", fs.createReadStream(localPath));
const files = await fcode.storage.list();
const stream = await fcode.storage.download("path/myfile.txt");
stream.pipe(fs.createWriteStream(localPath));
// Form file params arrive as "fcode.storage://…" references — strip the
// prefix before download; see fcode-forms.
// Signed download URL — { url, expiresAt }. A real HTTPS link in the cloud,
// a file:// URL locally (same shape, no special-casing).
const signed = await fcode.storage.createSignedUrl("path/myfile.txt");
await fcode.storage.delete("path/myfile.txt");

本地磁盘: 在 process.env.TMP_DATA_DIR 下写入临时文件。

变量、计划任务与 OAuth

在运行时读取/写入团队变量并管理进程计划任务 —— 作用范围仅限于自己的团队, 无需 API 令牌(与数据存储/存储相同):

// Team variables (config/secrets)
// Default is SENSITIVE: fcode.variables.set(key, value) creates a sensitive
// (masked, immutable-sensitivity) variable. Pass { sensitive: false } for
// plain config values.
await fcode.variables.set("API_KEY", "secret"); // sensitive by default
await fcode.variables.set("BASE_URL", "https://api.acme.com", {
  sensitive: false, // required for non-secret config
});
const v = await fcode.variables.get("API_KEY"); // { key, value, resolvingTeamSlug, ... } or undefined
const all = await fcode.variables.list();       // includes variables inherited from parents
await fcode.variables.delete("API_KEY");        // no-op on an inherited variable

// Schedules (cron or one-off dateTime) for a process
const schedule = await fcode.schedule.create("my-process", {
  cron: "0 0 6 * * SUN", // or: dateTime: "2026-04-24T12:30:00.000"
  input: { parameters: { foo: "bar" } },
  allowConcurrentExecutions: false, // optional
});
const schedules = await fcode.schedule.list({
  processId: fcode.execution.process.id,
});
const current = await fcode.schedule.get(schedule.id);
await fcode.schedule.update(schedule.id, { cron: "0 0 7 * * SUN" });
await fcode.schedule.pause(schedule.id);
await fcode.schedule.resume(schedule.id);
await fcode.schedule.delete(schedule.id);
// delete every schedule for a process (pass the process UUID)
await fcode.schedule.deleteForProcess(fcode.execution.process.id);

// Start a third-party OAuth authorization. The platform holds the state, the PKCE
// verifier and the one redirect_uri registered with the provider, and invokes
// `onComplete` when the provider redirects back — so never build an authorization
// URL or a state by hand, and never expose a callback webhook.
const flow = await fcode.oauth.start({
  authorizeUrl: "https://login.example.com/authorize",
  clientId: fcode.env.PROVIDER_CLIENT_ID,
  scope: ["openid", "offline_access"],
  onComplete: "oauth-callback",     // the process that receives the code
  data: { companyId },              // carried back untouched; never a secret
  extraParams: { nonce },           // optional, provider-specific
  pkce: true,                       // default
});
flow.authorizationUrl; // hand this to the form's oauth widget

onComplete 会在 fcode.context.parameters 中接收 code、codeVerifier、 redirectUri、data 和 state(如果提供方拒绝请求,则接收 error / errorDescription)。

在令牌交换时原样重放 redirectUri —— 提供方会逐字节比较。 请参阅 fcode-examples 中的 references/oauth-connect.md。

fcode.variables.set/delete 只会在服务端持久化;在同一次运行中,它们不会反映到 fcode.env 中(fcode.env 是启动时获取的快照)。

继承的变量

list()/get() 会包含从父工作区继承的变量(模型见 fcode-core-concepts);继承的变量带有 resolvingTeamSlug,用于标明其所有者。 对继承的键调用 set() 会在此工作区创建覆盖项——这是在此处更改其值的唯一方式; 对其调用 delete() 则会静默无操作,因此卸载流程永远不会删除父级的凭据(如果必须报告实际删除了什么,请检查 resolvingTeamSlug)。 fcode.env.setEnvVar / delEnvVar 的行为相同。

发送电子邮件

使用内置的 fcode.sendMail 发送电子邮件——无需配置 SMTP(模型见 fcode-core-concepts):

const info = await fcode.sendMail({
  to: "[email protected]", // string or string[]
  subject: "Report ready",
  text: "Plain-text body", // provide text, html, or both
  html: "<b>HTML body</b>",
});
// info => { messageId, accepted, rejected }
  • From 地址由平台固定;你传入的 from 会被忽略。
  • 每次执行默认最多可发送 3 封电子邮件;达到上限后,后续调用会抛出异常。
  • 在本地(fcode run)没有管理器,因此电子邮件只会记录,不会发送。
  • 可接受的用途——谁可以作为收件人、正文可以包含什么——属于平台规则;违反规则会阻止发布。请参阅 fcode-core-concepts §发送电子邮件。

返回值

// Standard
return { message: "Success!" };

// Custom HTTP status (webhooks)
return { status: 404, body: { message: "Not found" }, headers: { "Content-Type": "application/json" } };

// Transient (not persisted in execution results)
return { transient: true, data: sensitiveData };

// Synchronous UI trigger button inside Factorial (see fcode-ui-triggers).
// Returned unchanged to the page; signal a failure with an error, not in the body.
return { synced: 42 };

返回值上限为 500 KB;更大的结果会导致执行失败。请将其放入存储中,并返回引用(fcode-core-concepts › 计划与限制)。

评论

支持 Markdown