mcpField
F
fcode-javascript

fcode-javascript

github.com/factorialco開発1400 回インストール今日更新
リポジトリ

fcode-javascript について

fcode-javascriptは、Node.js v22ランタイムでFactorial CodeのJavaScriptプロセスを書くためのガイドです。パラメーター、ログ、ストレージ、変数、メール、実行結果などのプラットフォームAPIを扱います。

主な機能

  1. 01非同期mainエントリーポイントでプロセスを構成
  2. 02パラメーターとプラットフォーム情報の取得
  3. 03データストア、ストレージ、変数の利用
  4. 04共有fcode-logsモジュールによるログ記録
  5. 05メール送信とプロセス結果の返却

活用シーン

  1. 01Factorial 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 の後に解析してください。
  • データストアに保存するシークレットは暗号化してください — 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)。

コメント