コンテンツへスキップ
CADCAMFUN
ドキュメント

ドキュメント

API クライアント統合を構築する

Promise SDK、完全な Effect コントラクト クライアント、または実際の入力とエラー動作を含む生成された Effect アダプターを使用します。

英語から自動翻訳されています。 英語の原文を見る

クライアントを選択してください

リポジトリには、関連する 3 つのクライアント サーフェスがあります。これらはエンドポイント宣言を共有しますが、その構造、入力形状、実行時の依存関係、およびエラー チャネルは異なります。慎重に 1 つを選択し、その表面からの例をまとめて保存します。

表面エントリーポイント実行
プロミスSDK@cadcamfun/api/sdk、輸出された CadCam.make普通の結果を約束します。 SSE の非同期反復可能。提供されたフェッチまたはグローバルフェッチを使用します。
完全契約のお客様ApiClient から @cadcamfun/apiその層によって提供されるトランスポートおよびベアラーミドルウェアを使用した効果的なサービス。
生成されたエフェクトアダプターpackages/api/src/client/generated/index.tsコントラクトクライアントを中心としたフラット化されたメソッド。呼び出し元は、必要なトランスポートとミドルウェアを提供します。

API パッケージは、ソース エクスポートを備えたプライベート ワークスペースです。以下のインポートは、このモノリポジトリ、または実際にそれらのエクスポートを提供するディストリビューションを対象としています。このページでは、別途入手可能なパブリック npm パッケージを要求していません。独立したクライアントは、 OpenAPIドキュメント またはプレーン HTTP。

クライアント ライブラリのセットアップを行わない最初のリクエストの場合は、 キャプチャされた HTTP ウォークスルー。これは、成功した本体と失敗した本体が操作間でどのように異なるかを確立します。

接続を解決する

現在のサイドカー起動に属する URL とアプリケーション ベアラー トークンを使用します。タウリはそれらを次の方法で取得します。 get_sidecar_endpoint。手動開発プロセスでは、割り当てられたポートが準備完了イベントに出力されます。オリジンは、ドキュメント サイトや Vite アセットではなく、サイドカーまたは許可されたコンパニオン ゲートウェイを指す必要があります。

サイドカーの再起動後、接続を再度解決します。以前のポートを再利用すると、接続が拒否されたり、誤って別のプロセスにアドレス指定されたりする可能性があります。古い起動トークンを再利用すると、認証エラーが発生します。公衆衛生上の対応が成功したからといって、保護されたリクエストが受け入れられることは証明されません。

アカウントの選択、アプリケーションの許可、デバイスの許可、および外部エージェントのアクセスは異なります。オプションの x-session-token 申請受付後にアカウントを選択します。プロジェクト スコープのブリッジ トークンは、そのアクション ブリッジ エンドポイントに限定されます。電話トークンは、ゲートウェイの許可リストを通じて機能します。フォローしてください 認証リファレンス 統合のための接続を選択する前に。

プロミスSDK

エクスポートされた名前空間は次のとおりです。 CadCam、そのコンストラクターは make。ベース URL とデフォルトのヘッダーを指定します。以下の create メソッドと get メソッドは、ネストされたフィールドではなくフラット化されたフィールドを使用します。 payload または params 物体。

@cadcamfun/api を使用するワークスペース内
import { CadCam } from "@cadcamfun/api/sdk"

const client = CadCam.make({
  baseUrl,
  headers: { Authorization: "Bearer " + token },
})

const projects = await client.projects.list()
const created = await client.projects.create({
  name: "Fixture plate",
  description: "An integration-created project",
})
const detail = await client.projects.get({ id: created.id })
console.log(projects.length, detail.name, detail._count.drawings)

各呼び出しは、そのエンドポイントの成功ペイロードに直接解決されます。 projects.list() 配列を返します。 projects.create() プロジェクト行を返します。普遍的なものはない { data, error } ラッパーといいえ throwOnError この SDK のコンストラクター オプション。一部のエンドポイント ペイロード自体には、 data または success それが彼らのHTTP契約だからです。

SDK は、エンドポイント パスと構成されたベース URL から URL を準備し、パス識別子をエンコードし、宣言された JSON 入力をシリアル化し、操作の宣言された正確な成功ステータスを確認します。次に、JSON を解析し、型指定された値を返します。 Promise ランタイムは、返されたすべてのペイロードに Effect スキーマ デコーダーを適用しません。 TypeScript 出力タイプは、任意のサーバー実装を検証しません。

宣言されたエラーとトランスポートエラー

宣言された HTTP 失敗は、デコードされた応答本文で拒否されます。その値は、JavaScript Error のインスタンスではなく、タグ付きのプレーン オブジェクトである場合があります。トランスポートおよびプロトコルの障害には SDK が使用されます ClientError.

両方のエラー チャネルを処理する
import { ClientError } from "@cadcamfun/api/sdk"

try {
  await client.projects.create({})
} catch (error) {
  if (error instanceof ClientError) {
    console.error(error.reason, error.message)
  } else if (error && typeof error === "object" && "message" in error) {
    console.error(String(error.message))
  } else {
    console.error("Unrecognized API failure", error)
  }
}
クライアントエラーの理由解釈
Transportフェッチのセットアップ、接続、中止、またはストリーム読み取りの失敗。原因と現在の接続を調べてください。
UnexpectedStatusサーバーは、操作の宣言された成功ステータスおよび失敗ステータス以外のステータスを返しました。
UnsupportedContentTypeストリーム応答に、予期されたイベント ストリーム コンテンツ タイプがありませんでした。
MalformedResponseJSON または予期された応答ストリームをデコードできませんでした。
SseEventTooLargeイベント ストリーム バッファーが、生成されたランタイムのフレーム ガードを超えました。

たとえば、作成入力タイプで省略が許可されている場合でも、プロジェクト名が欠落している場合は、HTTP 400 ビジネス障害となります。プロジェクトの作成中に接続がリセットされる場合は異なります。書き込みが完了したかどうかがクライアントに不明なままになります。ミューテーションを繰り返す前にリソースの状態を読み取ります。 SDK は、アプリケーション全体の冪等性プロトコルを追加したり、拒否された呼び出しをすべて自動的に再試行したりすることはありません。

キャンセルとヘッダー

ClientOptions 受け入れる baseUrl、オプションのフェッチ実装、およびデフォルトのヘッダー。通話ごと RequestOptions シグナルと追加のヘッダーを受け入れます。エンドポイント入力のないメソッドの場合、リクエスト オプションは最初の引数です。入力を持つメソッドは、その後にリクエスト オプションを受け取ります。

通話ごとのキャンセルとアカウントの選択
const controller = new AbortController()
const pending = client.projects.get(
  { id: projectId },
  {
    signal: controller.signal,
    headers: { "x-session-token": accountSessionToken },
  },
)
// Call controller.abort() when the operation is no longer needed.
const project = await pending

リクエスト ビルダーは、デフォルトのヘッダー、エンドポイントで宣言されたヘッダー、そして呼び出しごとのヘッダーを適用します。呼び出しごとの値はデフォルトをオーバーライドできます。アカウントを追加したりヘッダーをトレースしたりするときに、誤って Authorization を置き換えることを避けます。ログにコピーされるエンドポイント URL に資格情報を含めないでください。

注射中 fetch インプロセステストトランスポートまたは制御されたアダプターをサポートします。アダプターは、要求ヘッダー、本文、キャンセル、コンテンツ タイプ、および応答ステータスのセマンティクスを尊重する必要があります。デスクトップ独自のエフェクト統合と携帯電話のピン留めされたネイティブ トランスポートは追加の作業を行います。任意のフェッチを置き換えても、それらのネイティブ境界は再現されません。

フルエフェクトクライアント

ApiClient.layer 完全な HttpApi クライアント、フェッチ トランスポート、およびベアラー ミドルウェアを構築します。これは、基礎となる HttpApi リクエスト形状を持つエンドポイント メソッドを公開します。突然変異のペイロードが低下する payload、パス値は以下になります params.

完全契約のお客様
import { ApiClient } from "@cadcamfun/api"
import { Effect } from "effect"

const createProject = Effect.gen(function* () {
  const api = yield* ApiClient
  return yield* api.projects.create({
    payload: { name: "Fixture plate" },
  })
}).pipe(Effect.provide(ApiClient.layer({ baseUrl, token })))

const project = await Effect.runPromise(createProject)

このクライアントは API 宣言全体から派生し、生成されたターゲットから省略されたエンドポイントのオプションです。 Effect の型付きエラー チャネルとスキーマ対応トランスポートが保持されます。リソースの有効期間、ストリームの中断、およびレイヤーのプロビジョニングは、呼び出し側のエフェクト プログラムに属します。エフェクトを作成しても実行されません。

再利用可能な層はアプリケーション トークンを提供します。デスクトップは独自のレイヤーを構築します apps/desktop/src/app/client.ts オプションのアカウントセッション状態と注入されたトランスポートをアタッチします。デスクトップ内で作業する場合は、コンポーネントごとに 2 番目の接続/ランタイムを作成するのではなく、その統合を再利用します。

生成されたエフェクトアダプター

生成されたエフェクト クライアントは実際のスキーマをインポートし、メソッドをフラット化されたフィールドに適応させます。その CadCam.make 適応されたクライアントを構築する Effect を返します。独自のフェッチ トランスポートやアプリケーション認証層を提供しないため、呼び出し元は対応するサービスとミドルウェアを提供する必要があります。

生成されたエラー アダプターは、トランスポート/スキーマ/SSE エラーをタグ付きエラーにマッピングします。 ClientError 宣言されたドメイン障害を保持しながら。このエラー クラスは、Promise SDK の JavaScript エラー クラスとは別のものです。 reason 弦。名前が似ているからといって、それらの処理を交換できるわけではありません。

入力例を明示的に保ちます。 Promise および生成された Effect フォームでは、 projects.get({ id });生の契約書は使用します projects.get({ params: { id } })。チェックされていないタイプ アサーションを通じて、あるサーフェスの入力オブジェクトを別のサーフェスに渡すことは避けてください。

ストリーミング

Promise SSE 操作は非同期イテラブルを返します。ネットワークのセットアップは反復の開始時に行われます。ランタイムは、成功ステータスとイベント ストリームのコンテンツ タイプをチェックし、増分 UTF-8 データを読み取り、フレーム境界を正規化し、データ フレームを JSON デコードします。不正なフレームは反復に失敗します。リーダーのクリーンアップは、反復の終了時または終了時に実行されます。

ランタイムのガードは 16 * 1024 * 1024 バッファリングされた JavaScript 文字列ユニット。フレーム境界前の蓄積を制限します。任意のすべての 16 MB ペイロードがアプリケーションのイベント スキーマにとって有用または有効であることを保証するものではありません。

AI イベントをその識別子に従って消費し、セッション識別子を保持します。終了したトランスポートは、端末での会話イベントの証拠にはなりません。使用 AI ストリーミングとリカバリ キュー、中止、許可、質問、および状態回復の動作について。 EventSource は、認証ヘッダーと JSON 本文を含む POST リクエストのドロップイン置き換えではありません。

カバレッジと再生

ジェネレーターには、表現できない形状の明示的な省略リストがあります。共有省略には、マルチパート プロファイル/プラグインのアップロード、複数の成功スキーマを使用した MCP の作成、入力名の衝突、ストリーム上の応答ヘッダーを使用して提供されるプラグインが含まれます。その他の Promise の省略には、生の署名付き Webhook、JavaScript プラグインのブートストラップ、バイナリのダウンロード、および自由形式のジェネレーター リクエストが含まれます。

正確な現在のリストを読む packages/api/scripts/generate-clients.ts そして APIの概要。生成されたメソッドが存在しない場合、サーバー エンドポイントが利用できないことはわかりません。その操作には完全なコントラクト クライアントまたは適切な RAW トランスポートを使用します。

リポジトリのルート
bun run generate
bun run generate:check
bun run --filter @cadcamfun/web generate:api-reference
bun run --filter @cadcamfun/web check:api-reference

クライアントの再生成とドキュメントの再生成は、同じ契約からの個別の出力です。エンドポイントの変更後も両方を最新の状態に保ちます。生成されたメソッド本体を編集してサーバーの入力要件を変更しないでください。

生成されたコードは次の場所に書き込まれます packages/api/src/client/generated そして packages/api/src/sdk/generated。これらのファイルを手動で編集しないでください。契約を変更して再生成します。

統合検証

ここで示されている Promise の作成/読み取り/プレーン結果の動作とスローされた宣言された失敗は、移行された使い捨てデータベースを使用して実際のサイドカー ハンドラー スタックに対して実行されました。 HTTP ウォークスルーには、対応する観察された応答が含まれています。ジェネレーター、認証、またはエンドポイントのスキーマを変更する場合は、重点的なチェックを繰り返します。

For an integration acceptance check, verify public health; a protected request without a token; the same request with the current token; a valid create/read cycle; a declared validation failure; a cancelled request; and a stream whose terminal state is checked. Use a disposable project and never infer successful persistence from a frontend fixture alone.

実装ソースは次のとおりです。 packages/api/src/sdk/generated/client.ts、 その client-error.ts, packages/api/src/client.ts, packages/api/src/client/generated、 そして packages/httpapi-codegen/src/index.ts。ジェネレーターとコミットされた出力が組み合わされて、実際のクライアントの動作が確立されます。

Promise SDK オプションのリファレンス

オプションどこEffect
baseUrlCadCam.makeで解決しました new URL(path, baseUrl);スキームとポートを含めます。
fetchCadCam.makeReplace the transport, for example to add logging or to inject a test double.デフォルトは globalThis.fetch.
headersCadCam.makeすべてのリクエストとともに送信されます。置く authorization ここ。
signal通話ごとにリクエストを中止します。拒絶反応は ClientError("Transport").
headers通話ごとに1 つの呼び出しのヘッダーをオーバーライドまたは追加します。 x-session-token。コールごとの値がクライアントの値よりも優先されます。

身体が存在する場合と存在しない場合 content-type ヘッダーが設定され、SDK が設定されました application/json で連載しています JSON.stringify。パスパラメータは常に通過します encodeURIComponent, したがって、次のようなキー docs.walkthrough.units またはそれを含むもの / 単一セグメントのままです。

クライアントエラーの理由

理由いつ発生するか典型的な応答
Transportfetch スロー (拒否、リセット、DNS、中止) またはストリームの読み取りに失敗しましたサイドカー URL を再解決します。読み取りを再試行します。書き込みを再試行する前に状態を再読み取りします。
UnexpectedStatusステータスは成功ステータスでも、宣言されたエラー ステータスでもありません。原因は当てはまります { status }.契約の不一致として扱います。多くの場合、サーバーのバージョンが異なります。
UnsupportedContentTypeストリーム操作の応答が次のもの以外でした text/event-stream、または非 JSON タイプの JSON 操作プロキシとサーバーのバージョンを確認してください。
MalformedResponse空または無効な JSON、本文の欠落、または SSE data: jSON ではないブロック生の応答をログに記録します。それを報告してください。
SseEventTooLarge未解析の SSE バッファが 16 MiB を超えましたイベントは拒否されました。ストリームを再開します。

のメッセージ ClientError 理由の後に原因メッセージが続きます (例: Transport: fetch failed)、したがってログを記録します error.message それだけですでに診断可能です。

べき等読み取りのみの再試行
import { CadCam, ClientError } from "@cadcamfun/api/sdk"

async function withRetry<T>(read: () => Promise<T>, attempts = 3): Promise<T> {
  for (let attempt = 1; ; attempt++) {
    try {
      return await read()
    } catch (error) {
      const transient = error instanceof ClientError && error.reason === "Transport"
      if (!transient || attempt >= attempts) throw error
      await new Promise((resolve) => setTimeout(resolve, 250 * 2 ** attempt))
    }
  }
}

const projects = await withRetry(() => client.projects.list())

やみくもに書き込みを再試行しないでください

失敗した書き込み Transport 適用されている可能性があります。リソースを再度読み取り、存在しない場合にのみ再送信します。 API にはべき等キーがありません。

SDK を使用したストリームの使用

アシスタント イベントを反復する
const controller = new AbortController()
const events = client.ai.chatStream(
  { message: "Pocket the 40 x 30 rectangle, 3 mm deep", projectId },
  { signal: controller.signal },
)

for await (const event of events) {
  switch (event.type) {
    case "delta": render(event); break
    case "permission_request": askUser(event); break
    case "done": finish(event); break
    case "error": showError(event); break
  }
}

イテレータは各 SSE ブロックを解析します。 data: ブロックの行を解析し、JSON を解析して生成します。なしのコメントとブロック data: スキップされます。ループを早期に終了する (break、例外、または中止)リーダーをキャンセルし、接続を解放します。イベント type 値はアシスタント ストリーミング ガイドにリストされている値です。生成されたものを確認します AiChatStreamOutput 厳密な結合のタイプ。

例: SDK を介した設定

キーと値の往復
const key = "docs.walkthrough.units"

try {
  await client.kv.get({ key })
} catch (error) {
  if ((error as { _tag?: string })._tag !== "NotFound") throw error   // first run: 404
}

const saved = await client.kv.set({ key, value: { units: "mm" } })
// saved: { key, value: { units: "mm" }, updatedAt: "2026-…" }

const { entries } = await client.kv.list({ prefix: "docs." })
await client.kv.remove({ key })   // { message: "…" }

キーは 512 文字に制限されており、空白以外のテキストを含める必要があります。値は JSON 互換である必要があります (サイクル、関数、または非有限数は禁止)。

3Dで

クライアントがカバーする内容 ドラッグして周回します · スクロールしてズーム · 右ドラッグしてパンします
Every API group as a column, height = operations counted from the generated OpenAPI document (270 in total). Rows are the six sidebar categories; ai (34), history (22) and costs (21) are the largest groups.