fcode-javascript について
fcode-javascriptは、Node.js v22ランタイムでFactorial CodeのJavaScriptプロセスを書くためのガイドです。パラメーター、ログ、ストレージ、変数、メール、実行結果などのプラットフォームAPIを扱います。
主な機能
- 01非同期mainエントリーポイントでプロセスを構成
- 02パラメーターとプラットフォーム情報の取得
- 03データストア、ストレージ、変数の利用
- 04共有fcode-logsモジュールによるログ記録
- 05メール送信とプロセス結果の返却
活用シーン
- 01Factorial Code上でJavaScriptプロセスを実装
- 02プロセスデータと認証情報を保存
- 03レベル別ログで実行状況を追跡
- 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の後に解析してください。 - データストアに保存するシークレットは暗号化してください —
setの第 3 引数にtrueを渡します (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 › Plans & limits)。