cap-apps-toolkit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

@domoinc/toolkit - Service Clients

@domoinc/toolkit - 服务客户端

The toolkit provides typed client classes for Domo services.
bash
yarn add @domoinc/toolkit
typescript
import {
  AppDBClient,
  AIClient,
  IdentityClient,
  SqlClient,
  UserClient,
  GroupClient,
  FileClient,
  CodeEngineClient,
  WorkflowClient,
  DomoClient
} from '@domoinc/toolkit';
该Toolkit为Domo服务提供了类型化的客户端类。
bash
yarn add @domoinc/toolkit
typescript
import {
  AppDBClient,
  AIClient,
  IdentityClient,
  SqlClient,
  UserClient,
  GroupClient,
  FileClient,
  CodeEngineClient,
  WorkflowClient,
  DomoClient
} from '@domoinc/toolkit';

Response Wrapper

响应包装器

Most toolkit methods return a response wrapper:
typescript
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;
Exception:
AIClient
often returns payload under
response.data
. Handle AI responses with:
typescript
const body = response.data || response.body || response;
const output = body.output || body.choices?.[0]?.output;
大多数Toolkit方法会返回一个响应包装器:
typescript
interface ToolkitResponse<T> {
  body: T;        // 实际数据
  status: number; // HTTP状态码
  headers?: Record<string, string>;
}

// 使用示例
const response = await IdentityClient.get();
const user = response.body;  // 访问数据
const status = response.status;
例外情况:
AIClient
的响应负载通常在
response.data
中。请按以下方式处理AI响应:
typescript
const body = response.data || response.body || response;
const output = body.output || body.choices?.[0]?.output;

AppDBClient - NoSQL Document Store

AppDBClient - NoSQL文档存储

PREFERRED for CRUD apps and long text storage. Collections can sync to Domo datasets.
适用于CRUD应用和长文本存储的首选方案。 集合可以与Domo数据集同步。

DocumentsClient

DocumentsClient

typescript
// 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 Documents:
typescript
// 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' }
]);
Read/Query Documents:
typescript
// 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']
  }
);
CRITICAL response shape note:
  • .get()
    returns document wrappers with metadata; your app fields are in
    doc.content
    .
  • Do not assume
    docs[0].fieldName
    ; use
    docs[0].content.fieldName
    .
typescript
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 Query Operators:
  • $eq
    - Equals
  • $ne
    - Not equals
  • $gt
    - Greater than
  • $gte
    - Greater than or equal
  • $lt
    - Less than
  • $lte
    - Less than or equal
  • $in
    - In array
  • $nin
    - Not in array
  • $regex
    - Regular expression match
  • $and
    - Logical AND
  • $or
    - Logical OR
Update Documents:
typescript
// 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 Update Operators:
  • $set
    - Set field values
  • $unset
    - Remove fields
  • $inc
    - Increment numeric fields
  • $push
    - Add to array fields
Delete Documents:
typescript
// 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 } }
typescript
// 定义文档类型
interface Task {
  title: string;
  description: string;
  status: 'active' | 'completed';
  priority: 'Low' | 'High' | 'Urgent';
  dueDate?: string;
}

// 为集合创建客户端
const tasksClient = new AppDBClient.DocumentsClient<Task>('TasksCollection');
创建文档:
typescript
// 创建单个文档
const response = await tasksClient.create({
  title: 'New Task',
  description: 'Task description',
  status: 'active',
  priority: 'High'
});
const newTask = response.body;
// 返回结果:{ id: 'uuid', content: {...}, owner: 'userId', createdOn: '...', updatedOn: '...' }

// 创建多个文档
const response = await tasksClient.create([
  { title: 'Task 1', status: 'active', priority: 'Low' },
  { title: 'Task 2', status: 'active', priority: 'High' }
]);
读取/查询文档:
typescript
// 获取所有文档
const response = await tasksClient.get();
const tasks = response.body;

// 使用MongoDB风格的查询进行过滤
const activeTasks = await tasksClient.get({
  status: { $eq: 'active' }
});

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

// 复杂查询
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' } }
  ]
});

// 带分页和排序的查询
const paginated = await tasksClient.get(
  { status: { $eq: 'active' } },
  {
    limit: 10,
    offset: 0,
    orderby: ['priority', 'dueDate']
  }
);

// 聚合查询
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
typescript
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
    - 逻辑与
  • $or
    - 逻辑或
更新文档:
typescript
// 全量更新(替换内容)
const response = await tasksClient.update({
  id: 'document-uuid',
  content: {
    title: 'Updated Title',
    description: 'Updated description',
    status: 'completed',
    priority: 'Low'
  }
});

// 批量更新
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' } }
]);
// 返回结果:{ body: { updated: 2, inserted: 0 } }

// 使用MongoDB操作符进行部分更新
const count = await tasksClient.partialUpdate(
  { status: { $eq: 'active' } },  // 过滤条件
  { $set: { status: 'archived' } }  // 操作
);
// 返回更新的文档数量

// 部分更新操作符示例
await tasksClient.partialUpdate(
  { priority: { $eq: 'Low' } },
  {
    $set: { priority: 'Medium', updatedAt: new Date().toISOString() },
    $unset: { tempField: 1 },
    $inc: { viewCount: 1 }
  }
);
MongoDB更新操作符:
  • $set
    - 设置字段值
  • $unset
    - 删除字段
  • $inc
    - 递增数值字段
  • $push
    - 向数组字段添加元素
删除文档:
typescript
// 删除单个文档
await tasksClient.delete('document-uuid');

// 批量删除
const response = await tasksClient.delete(['uuid-1', 'uuid-2', 'uuid-3']);
// 返回结果:{ body: { deleted: 3 } }

CollectionsClient

CollectionsClient

typescript
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();
typescript
const collectionsClient = new AppDBClient.CollectionsClient();

// 列出所有集合
const collections = await collectionsClient.list();

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

// 删除集合
await collectionsClient.delete('CollectionName');

// 导出所有集合
const exportData = await collectionsClient.export();

IdentityClient - Current User (SECURE)

IdentityClient - 当前用户(安全)

Use this instead of Domo.env for security-sensitive operations.
typescript
// Get current authenticated user
const response = await IdentityClient.get();
const user = response.body;
// {
//   id: 12345,
//   displayName: 'John Doe',
//   userName: 'jdoe',
//   emailAddress: 'jdoe@company.com',
//   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
);
对于安全敏感操作,请使用该客户端替代Domo.env。
typescript
// 获取当前已认证用户
const response = await IdentityClient.get();
const user = response.body;
// {
//   id: 12345,
//   displayName: 'John Doe',
//   userName: 'jdoe',
//   emailAddress: 'jdoe@company.com',
//   avatarKey: 'abc123',
//   role: 'Admin',
//   groups: [{ id: 1, name: 'Everyone' }, ...]
// }

// 带选项的调用
const response = await IdentityClient.get(
  5000,  // 超时时间(毫秒)
  false  // 是否包含用户组 - 设置为false可加快响应速度
);

SqlClient - Direct SQL Queries

SqlClient - 直接SQL查询

Note: SQL endpoint does NOT respect page filters. Use Query endpoint for dashboard-embedded apps.
typescript
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: '' } }
注意: SQL端点不遵守页面过滤器。对于嵌入仪表板的应用,请使用查询端点。
typescript
const sqlClient = new SqlClient();

// 执行SQL查询
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
// }

// 复杂查询
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`
);

// 将页面过滤器解析为SQL(静态方法)
const predicates = SqlClient.parsePageFilters(['dataset1', 'dataset2']);
// 返回结果: { 'dataset1': [{ where: '"column" = \'value\'', having: '' }], ... }

// 获取拼接后的查询子句
const clauses = SqlClient.parsePageFilters(['dataset1'], true);
// 返回结果: { 'dataset1': { whereClause: 'WHERE ...', havingClause: '' } }

UserClient - User API

UserClient - 用户API

typescript
// 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'
);
typescript
// 获取分页用户列表
const response = await UserClient.get(
  50,    // 每页数量
  0,     // 偏移量
  true   // 是否包含详细信息
);
const users = response.body;

// 获取指定用户信息
const response = await UserClient.getUser(
  12345,  // 用户ID
  true    // 是否包含详细信息
);
const user = response.body;

// 获取用户头像
const avatarBlob = await UserClient.getAvatar(
  'avatar-key-from-user',
  'medium'  // 可选值:'small' | 'medium' | 'large'
);

GroupClient - Groups API

GroupClient - 用户组API

typescript
// 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
typescript
// 获取所有用户组
const response = await GroupClient.get(50, 0);  // 每页数量, 偏移量
const groups = response.body;

// 获取指定用户组信息
const response = await GroupClient.getGroup(456);
const group = response.body;

// 获取用户组成员
const response = await GroupClient.getMembers(456);
const members = response.body;  // 用户对象数组

FileClient - File Storage

FileClient - 文件存储

typescript
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);
typescript
const fileClient = new FileClient();

// 上传文件
const response = await fileClient.upload(
  fileObject,        // 文件对象
  'report.pdf',      // 显示名称
  'Monthly report',  // 描述(可选)
  true,              // 是否公开(可选,默认true)
  10000              // 超时时间(可选)
);
const fileId = response.body.id;

// 上传新版本文件
const response = await fileClient.uploadRevision(
  newFileObject,
  existingFileId
);

// 下载文件
const blob = await fileClient.download(
  fileId,
  'filename.pdf',
  revisionId  // 可选,省略则下载最新版本
);

// 列出包含详细信息的文件
const response = await fileClient.detailsList(
  [123, 456],  // 文件ID数组(空数组表示所有文件)
  ['metadata', 'permissions', 'revisions']  // 扩展信息选项
);

// 获取/更新文件权限
const perms = await fileClient.getPermissions(fileId);
await fileClient.updatePermissions(fileId, JSON.stringify({
  public: false,
  users: [123, 456],
  groups: [789]
}));

// 删除文件版本
await fileClient.delete(fileId, revisionId);

AIClient - AI Services

AIClient - AI服务

All methods are static and use snake_case naming.
Response Structure: IMPORTANT: AIClient uses
data
instead of
body
for the response payload! The toolkit wraps responses in
{ data, status, statusCode }
. The API response includes both a top-level
output
field and a
choices
array. Prefer the top-level
output
field when available.
typescript
// 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;
所有方法均为静态方法,采用蛇形命名法(snake_case)
响应结构: 重要提示: AIClient使用
data
而非
body
存储响应负载!Toolkit会将响应包装为
{ data, status, statusCode }
格式。API响应同时包含顶层
output
字段和
choices
数组。优先使用顶层
output
字段(更可靠)。
typescript
// 文本生成
const response = await AIClient.generate_text(
  'Explain this sales trend in simple terms',
  { template: 'You are a business analyst. ${input}' },  // 提示模板
  { tone: 'professional' },  // 模板参数
  'model-id',  // 可选:模型覆盖
  { temperature: 0.7 }  // 模型配置
);

// 响应结构: { data: { output: string, choices: [{ output: string }], ... }, status: "OK", statusCode: 200 }
// 注意:AIClient使用'data'而非'body'!
// 优先使用顶层output字段(更可靠)
const responseBody = response.data || response.body || response;
const text = responseBody.output || responseBody.choices?.[0]?.output;

// 文本转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;
// 注意:第二个参数必须是DataSourceSchema数组,不能是单个Schema对象。
// 传入数组支持跨数据集SQL生成。

// 文本转Beast Mode(计算字段)
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;

// 文本摘要
const response = await AIClient.summarize(
  longTextContent,
  undefined,  // 提示模板
  undefined,  // 参数
  undefined,  // 模型
  undefined,  // 模型配置
  undefined,  // 系统提示
  [],         // 对话上下文
  { separatorType: 'paragraph' },  // 分块配置
  'bullets',  // 输出样式:'paragraph' | 'bullets'
  100         // 输出字数限制
);
const responseBody = response.data || response.body || response;
const summary = responseBody.output || responseBody.choices?.[0]?.output;

CodeEngineClient - Serverless Functions

CodeEngineClient - 无服务器函数

In app implementations, prefer the working direct-call pattern via
domo.post
and
packagesMapping
contracts. If you use Toolkit docs examples, verify runtime behavior in your environment.
typescript
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;
Manifest note: use
packagesMapping
(with
s
) and include full parameter/output schema fields.
在应用实现中,优先通过
domo.post
packagesMapping
契约使用直接调用模式。 如果使用Toolkit文档中的示例,请在你的环境中验证运行时行为。
typescript
import domo from 'ryuu.js';

// 通过别名执行函数
const response = await domo.post('/domo/codeengine/v2/packages/calculateTax', {
  amount: 1000,
  state: 'CA'
});

// 首次运行时检查响应格式
console.log('Code Engine response:', response);

const body = response?.body ?? response?.data ?? response;
const result =
  body?.output ??
  body?.result ??
  body?.value ??
  body;
清单注意事项:使用
packagesMapping
(带
s
)并包含完整的参数/输出Schema字段。

WorkflowClient - Domo Workflows

WorkflowClient - Domo工作流

typescript
// 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', ... }
All
WorkflowClient
methods are alias-based in app code:
  • WorkflowClient.startModel(workflowAlias, variables)
  • WorkflowClient.getAllModels()
    /
    WorkflowClient.getAllModels(true)
  • WorkflowClient.getModelDetails(workflowAlias)
  • WorkflowClient.getInstance(workflowAlias, instanceId)
The workflow UUID lives in
manifest.json
under
workflowMapping[].modelId
; runtime client calls pass the alias.
typescript
// 列出可用的工作流模型
const response = await WorkflowClient.getAllModels();
const models = response.body;
const modelsWithPermissions = await WorkflowClient.getAllModels(true);

// 通过清单workflowMapping.alias中的工作流别名获取模型详情
const response = await WorkflowClient.getModelDetails('myWorkflow');
const model = response.body;

// 通过别名启动工作流实例(注意:不是UUID)
const response = await WorkflowClient.startModel(
  'myWorkflow',
  { inputVar: 'value', anotherVar: 123 }
);
const instance = response.body;
// 返回结果: { id: 'instance-uuid', modelId: '...', status: 'RUNNING', ... }

// 通过别名+实例ID检查工作流实例状态
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 - Alternative to ryuu.js

DomoClient - ryuu.js的替代方案

typescript
// 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');
typescript
// 功能与Domo.get/post/put/delete一致,但来自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');