关于 toolkit
@domoinc/toolkit 是面向 Domo 服务的 TypeScript 类型化客户端库,供 Domo 应用开发者调用各类服务 API。它涵盖存储、身份、SQL、AI、文件和工作流等客户端。
主要功能
- 01Domo 服务的类型化客户端
- 02AppDB 文档与集合操作
- 03身份、用户和群组 API
- 04SQL 查询与文件上传
- 05AI 生成与工作流访问
适用场景
- 01创建和查询 AppDB 文档
- 02获取当前登录用户身份
- 03对数据集执行 SQL 查询
- 04调用 AI 服务或 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 使用 data 而不是 body 作为响应负载!工具包将响应包装在 { 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 契约的直接调用模式。
如果你使用 Toolkit 文档示例,请在你的环境中验证运行时行为。
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 说明:使用 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');