mcpField
T
toolkit

toolkit

github.com/stahura開発24193 回インストール26 週間前に更新
リポジトリ

toolkit について

@domoinc/toolkit は、Domo サービス向けの型付き TypeScript クライアントライブラリです。Domo アプリ開発者が、ストレージ、ID、SQL、AI、ファイル、ワークフローなどの API を扱えます。

主な機能

  1. 01Domo サービス向け型付きクライアント
  2. 02AppDB のドキュメントとコレクション操作
  3. 03ID・ユーザー・グループ API
  4. 04SQL クエリとファイルアップロード
  5. 05AI 生成とワークフローへのアクセス

活用シーン

  1. 01AppDB ドキュメントの作成と検索
  2. 02認証済みユーザーの ID 取得
  3. 03データセットへの SQL クエリ実行
  4. 04AI サービスや Domo ワークフローの呼び出し

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/stahura/domo-ai-vibe-rules --skill toolkit

インストール後、Claude Code で/toolkitを入力して読み込まれたか確認します。

詳細

@domoinc/toolkit - サービスクライアント

このツールキットは、Domo サービス用の型付きクライアントクラスを提供します。

yarn add @domoinc/toolkit
import {
  AppDBClient,
  AIClient,
  IdentityClient,
  SqlClient,
  UserClient,
  GroupClient,
  FileClient,
  CodeEngineClient,
  WorkflowClient,
  DomoClient
} from '@domoinc/toolkit';

レスポンスラッパー

ツールキットのほとんどのメソッドは、レスポンスラッパーを返します。

interface ToolkitResponse<T> {
  body: T;        // The actual data
  status: number; // HTTP status code
  headers?: Record<string, string>;
}

// Usage
const response = await IdentityClient.get();
const user = response.body;  // Access the data
const status = response.status;

例外: AIClient は、多くの場合、ペイロードを response.data の下に返します。AI レスポンスは次のように処理してください。

const body = response.data || response.body || response;
const output = body.output || body.choices?.[0]?.output;

AppDBClient - NoSQL ドキュメントストア

CRUD アプリと長文テキストの保存にはこちらを推奨します。 コレクションは Domo データセットと同期できます。

DocumentsClient
// Define your document type
interface Task {
  title: string;
  description: string;
  status: 'active' | 'completed';
  priority: 'Low' | 'High' | 'Urgent';
  dueDate?: string;
}

// Create client for a collection
const tasksClient = new AppDBClient.DocumentsClient<Task>('TasksCollection');

ドキュメントの作成:

// Create single document
const response = await tasksClient.create({
  title: 'New Task',
  description: 'Task description',
  status: 'active',
  priority: 'High'
});
const newTask = response.body;
// Returns: { id: 'uuid', content: {...}, owner: 'userId', createdOn: '...', updatedOn: '...' }

// Create multiple documents
const response = await tasksClient.create([
  { title: 'Task 1', status: 'active', priority: 'Low' },
  { title: 'Task 2', status: 'active', priority: 'High' }
]);

ドキュメントの読み取り/クエリ:

// Get all documents
const response = await tasksClient.get();
const tasks = response.body;

// Filter with MongoDB-style queries
const activeTasks = await tasksClient.get({
  status: { $eq: 'active' }
});

const highPriority = await tasksClient.get({
  priority: { $in: ['High', 'Urgent'] },
  status: { $ne: 'completed' }
});

// Complex queries
const filtered = await tasksClient.get({
  $and: [
    { status: { $eq: 'active' } },
    { priority: { $in: ['High', 'Urgent'] } }
  ]
});

const either = await tasksClient.get({
  $or: [
    { priority: { $eq: 'Urgent' } },
    { status: { $eq: 'completed' } }
  ]
});

// With pagination and sorting
const paginated = await tasksClient.get(
  { status: { $eq: 'active' } },
  {
    limit: 10,
    offset: 0,
    orderby: ['priority', 'dueDate']
  }
);

// Aggregations
const statusCounts = await tasksClient.get(
  {},
  {
    groupby: ['status'],
    count: 'id'
  }
);

const priorityStats = await tasksClient.get(
  {},
  {
    groupby: ['priority'],
    count: 'id',
    avg: ['estimatedHours']
  }
);

重要なレスポンス形式に関する注意:

  • .get() はメタデータを含むドキュメントラッパーを返します。アプリのフィールドは doc.content にあります。
  • docs[0].fieldName と決めつけず、docs[0].content.fieldName を使用してください。
const response = await tasksClient.get();
const rawDocs = response.body || response;
const docs = Array.isArray(rawDocs) ? rawDocs : [];

const parsed = docs.map((doc) => ({
  id: doc.id,
  ...doc.content
}));

MongoDB クエリ演算子:

  • $eq - 等しい
  • $ne - 等しくない
  • $gt - より大きい
  • $gte - 以上
  • $lt - より小さい
  • $lte - 以下
  • $in - 配列内に含まれる
  • $nin - 配列内に含まれない
  • $regex - 正規表現に一致
  • $and - 論理 AND
  • $or - 論理 OR

ドキュメントの更新:

// Full update (replace content)
const response = await tasksClient.update({
  id: 'document-uuid',
  content: {
    title: 'Updated Title',
    description: 'Updated description',
    status: 'completed',
    priority: 'Low'
  }
});

// Bulk update
const bulkResponse = await tasksClient.update([
  { id: 'uuid-1', content: { title: 'Updated 1', status: 'active', priority: 'Low' } },
  { id: 'uuid-2', content: { title: 'Updated 2', status: 'active', priority: 'High' } }
]);
// Returns: { body: { updated: 2, inserted: 0 } }

// Partial update with MongoDB operators
const count = await tasksClient.partialUpdate(
  { status: { $eq: 'active' } },  // Filter
  { $set: { status: 'archived' } }  // Operation
);
// Returns number of documents updated

// Partial update operators
await tasksClient.partialUpdate(
  { priority: { $eq: 'Low' } },
  {
    $set: { priority: 'Medium', updatedAt: new Date().toISOString() },
    $unset: { tempField: 1 },
    $inc: { viewCount: 1 }
  }
);

MongoDB 更新演算子:

  • $set - フィールド値を設定
  • $unset - フィールドを削除
  • $inc - 数値フィールドをインクリメント
  • $push - 配列フィールドに追加

ドキュメントの削除:

// Delete single document
await tasksClient.delete('document-uuid');

// Bulk delete
const response = await tasksClient.delete(['uuid-1', 'uuid-2', 'uuid-3']);
// Returns: { body: { deleted: 3 } }
CollectionsClient
const collectionsClient = new AppDBClient.CollectionsClient();

// List all collections
const collections = await collectionsClient.list();

// Create collection
await collectionsClient.create({
  name: 'NewCollection',
  schema: {
    columns: [
      { name: 'field1', type: 'STRING' },
      { name: 'field2', type: 'LONG' }
    ]
  }
});

// Delete collection
await collectionsClient.delete('CollectionName');

// Export all collections
const exportData = await collectionsClient.export();

IdentityClient - 現在のユーザー(セキュア)

セキュリティが重要な操作では、Domo.env の代わりにこちらを使用してください。

// Get current authenticated user
const response = await IdentityClient.get();
const user = response.body;
// {
//   id: 12345,
//   displayName: 'John Doe',
//   userName: 'jdoe',
//   emailAddress: '[email protected]',
//   avatarKey: 'abc123',
//   role: 'Admin',
//   groups: [{ id: 1, name: 'Everyone' }, ...]
// }

// With options
const response = await IdentityClient.get(
  5000,  // timeout in ms
  false  // includeGroups - set false for faster response
);

SqlClient - 直接 SQL クエリ

注意: SQL エンドポイントはページフィルターを尊重しません。ダッシュボードに埋め込むアプリでは、Query エンドポイントを使用してください。

const sqlClient = new SqlClient();

// Execute SQL query
const response = await sqlClient.get(
  'sales-dataset-alias',
  'SELECT region, SUM(amount) as total FROM sales-dataset-alias GROUP BY region ORDER BY total DESC'
);
const result = response.body;
// {
//   columns: ['region', 'total'],
//   rows: [{ region: 'North', total: 50000 }, ...],
//   numRows: 4,
//   numColumns: 2
// }

// Complex query
const response = await sqlClient.get(
  'sales',
  `SELECT 
    DATE_TRUNC('month', order_date) as month,
    product_category,
    SUM(revenue) as revenue,
    COUNT(*) as orders
   FROM sales
   WHERE order_date >= '2024-01-01'
   GROUP BY 1, 2
   ORDER BY 1, 3 DESC`
);

// Parse page filters into SQL (static method)
const predicates = SqlClient.parsePageFilters(['dataset1', 'dataset2']);
// Returns: { 'dataset1': [{ where: '"column" = \'value\'', having: '' }], ... }

// Get concatenated clauses
const clauses = SqlClient.parsePageFilters(['dataset1'], true);
// Returns: { 'dataset1': { whereClause: 'WHERE ...', havingClause: '' } }

UserClient - ユーザー API

// Get paginated list of users
const response = await UserClient.get(
  50,    // limit
  0,     // offset
  true   // includeDetails
);
const users = response.body;

// Get specific user
const response = await UserClient.getUser(
  12345,  // user ID
  true    // includeDetails
);
const user = response.body;

// Get user avatar
const avatarBlob = await UserClient.getAvatar(
  'avatar-key-from-user',
  'medium'  // 'small' | 'medium' | 'large'
);

GroupClient - グループ API

// Get all groups
const response = await GroupClient.get(50, 0);  // limit, offset
const groups = response.body;

// Get specific group
const response = await GroupClient.getGroup(456);
const group = response.body;

// Get group members
const response = await GroupClient.getMembers(456);
const members = response.body;  // Array of User objects

FileClient - ファイルストレージ

const fileClient = new FileClient();

// Upload file
const response = await fileClient.upload(
  fileObject,        // File object
  'report.pdf',      // Display name
  'Monthly report',  // Description (optional)
  true,              // isPublic (optional, default true)
  10000              // timeout (optional)
);
const fileId = response.body.id;

// Upload new revision
const response = await fileClient.uploadRevision(
  newFileObject,
  existingFileId
);

// Download file
const blob = await fileClient.download(
  fileId,
  'filename.pdf',
  revisionId  // optional, latest if omitted
);

// List files with details
const response = await fileClient.detailsList(
  [123, 456],  // File IDs (empty for all)
  ['metadata', 'permissions', 'revisions']  // Expand options
);

// Get/update permissions
const perms = await fileClient.getPermissions(fileId);
await fileClient.updatePermissions(fileId, JSON.stringify({
  public: false,
  users: [123, 456],
  groups: [789]
}));

// Delete file revision
await fileClient.delete(fileId, revisionId);

AIClient - AI サービス

すべてのメソッドは静的で、snake_case の命名規則を使用します。

レスポンス構造: 重要: AIClient はレスポンスペイロードに body ではなく data を使用します。ツールキットはレスポンスを { data, status, statusCode } でラップします。API レスポンスには、トップレベルの output フィールドと choices 配列の両方が含まれます。利用可能な場合は、トップレベルの output フィールドを優先してください。

// Text generation
const response = await AIClient.generate_text(
  'Explain this sales trend in simple terms',
  { template: 'You are a business analyst. ${input}' },  // promptTemplate
  { tone: 'professional' },  // parameters for template
  'model-id',  // optional model override
  { temperature: 0.7 }  // model configuration
);

// Response structure: { data: { output: string, choices: [{ output: string }], ... }, status: "OK", statusCode: 200 }
// NOTE: AIClient uses 'data' not 'body'!
// Prefer top-level output field (more reliable)
const responseBody = response.data || response.body || response;
const text = responseBody.output || responseBody.choices?.[0]?.output;

// Text to SQL
const response = await AIClient.text_to_sql(
  'Show me total sales by region for Q4',
  [{
    dataSourceName: 'Sales',
    description: 'Sales transactions table',
    columns: [
      { name: 'region', type: 'string' },
      { name: 'amount', type: 'number' },
      { name: 'order_date', type: 'date' }
    ]
  }]
);
const responseBody = response.data || response.body || response;
const sql = responseBody.output || responseBody.choices?.[0]?.output;
// NOTE: second argument must be DataSourceSchema[] (array), not a single schema object.
// Passing an array allows multi-dataset SQL generation.

// Text to Beast Mode (calculated field)
const response = await AIClient.text_to_beastmode(
  'Calculate year over year growth percentage',
  {
    dataSourceName: 'Revenue',
    columns: [
      { name: 'revenue', type: 'number' },
      { name: 'date', type: 'date' }
    ]
  }
);
const responseBody = response.data || response.body || response;
const beastMode = responseBody.output || responseBody.choices?.[0]?.output;

// Text summarization
const response = await AIClient.summarize(
  longTextContent,
  undefined,  // promptTemplate
  undefined,  // parameters
  undefined,  // model
  undefined,  // modelConfiguration
  undefined,  // system prompt
  [],         // chatContext
  { separatorType: 'paragraph' },  // chunkingConfiguration
  'bullets',  // outputStyle: 'paragraph' | 'bullets'
  100         // outputWordLength
);
const responseBody = response.data || response.body || response;
const summary = responseBody.output || responseBody.choices?.[0]?.output;

CodeEngineClient - サーバーレス関数

アプリを実装する際は、domo.post と packagesMapping コントラクトを使用した、動作する直接呼び出しのパターンを優先してください。 ツールキットのドキュメントにある例を使う場合は、お使いの環境でのランタイム動作を確認してください。

import domo from 'ryuu.js';

// Execute function by alias
const response = await domo.post('/domo/codeengine/v2/packages/calculateTax', {
  amount: 1000,
  state: 'CA'
});

// Inspect first run response shape
console.log('Code Engine response:', response);

const body = response?.body ?? response?.data ?? response;
const result =
  body?.output ??
  body?.result ??
  body?.value ??
  body;

マニフェストに関する注意:packagesMapping(s 付き)を使用し、パラメーターと出力のスキーマフィールドをすべて含めてください。

WorkflowClient - Domo ワークフロー

// List available workflow models
const response = await WorkflowClient.getAllModels();
const models = response.body;
const modelsWithPermissions = await WorkflowClient.getAllModels(true);

// Get model details by workflow alias from manifest workflowMapping.alias
const response = await WorkflowClient.getModelDetails('myWorkflow');
const model = response.body;

// Start workflow instance by alias (NOT UUID)
const response = await WorkflowClient.startModel(
  'myWorkflow',
  { inputVar: 'value', anotherVar: 123 }
);
const instance = response.body;
// { id: 'instance-uuid', modelId: '...', status: 'RUNNING', ... }

// Check instance status by alias + instanceId
const response = await WorkflowClient.getInstance('myWorkflow', 'instance-uuid');
const status = response.body;
// { id: '...', status: 'COMPLETED' | 'RUNNING' | 'FAILED', ... }

WorkflowClient のすべてのメソッドは、アプリコード内でエイリアスベースで呼び出します。

  • WorkflowClient.startModel(workflowAlias, variables)
  • WorkflowClient.getAllModels() / WorkflowClient.getAllModels(true)
  • WorkflowClient.getModelDetails(workflowAlias)
  • WorkflowClient.getInstance(workflowAlias, instanceId)

ワークフロー UUID は manifest.json の workflowMapping[].modelId にあります。ランタイムのクライアント呼び出しでは、エイリアスを渡します。

DomoClient - ryuu.js の代替

// Same as Domo.get/post/put/delete but from toolkit
const data = await DomoClient.get('/data/v1/sales');
await DomoClient.post('/api/items', { name: 'test' });
await DomoClient.put('/api/items/123', { name: 'updated' });
await DomoClient.delete('/api/items/123');

コメント