自由式SDK
官方 JavaScript/ TypeScript SDK 为 Freelo.io (英语) API (英语).
特征
- 从 OpenAPI 自动生成 总是与Freelo API同步
- 带有类型定义的完整类型脚本支持
- 0 运行时间依赖( 使用本地获取)
- 树能震动 ——只导入您需要的
- 在Node.js 18+、浏览器和所有主要框架工作
- 基于承诺的合成/等待API
- 多租户假想的每个请求授权
- 建造的平面、货币和日期公用事业
安装
npm install @freeloapp/js-sdk
快速启动
import { createFreelo, getProjects, createTask } from '@freeloapp/js-sdk';
// Initialize client (sets global default)
createFreelo({
auth: { type: 'basic', email: '[email protected]', apiKey: 'your-api-key' },
userAgent: 'YourApp/1.0 ([email protected])',
});
// Get all projects
const { data: projects } = await getProjects();
// Create a task
const { data: task } = await createTask({
path: { tasklist_id: 123 },
body: {
name: 'New Task',
worker_ids: [userId],
},
});
认证
SDK支持三种认证方法:
基本认证
获取您的 API 密钥 Freelo 设置。 。 。 .
createFreelo({
auth: { type: 'basic', email: '[email protected]', apiKey: 'your-api-key' },
userAgent: 'YourApp/1.0',
});
守护者托肯
使用预取的JWT或 PASETO 令牌 :
createFreelo({
auth: { type: 'bearer', token: 'your-jwt-token' },
userAgent: 'YourApp/1.0',
});
OAuth 2.1 (PKCE) (捷克语)
对于通过Freelo的身份提供者认证用户的应用程序(identity.freelo.io) (中文(简体) ). SDK处理自动令牌刷新——你处理初始授权流.
第1步: 启动 OAuth 流量
import {
generatePKCEChallenge,
buildAuthorizationUrl,
} from '@freeloapp/js-sdk';
// Generate PKCE challenge (store verifier for step 2)
const pkce = await generatePKCEChallenge();
sessionStorage.setItem('pkce_verifier', pkce.codeVerifier);
// Build authorization URL and redirect the user
const authUrl = buildAuthorizationUrl({
clientId: 'your-client-id',
redirectUri: 'https://yourapp.com/callback',
codeChallenge: pkce.codeChallenge,
scope: ['read', 'write', 'projects', 'tasks'],
state: crypto.randomUUID(),
});
window.location.href = authUrl;
第2步: 将授权代码换为令牌
import { exchangeCode } from '@freeloapp/js-sdk';
// In your callback handler (e.g. /callback)
const params = new URLSearchParams(window.location.search);
const tokens = await exchangeCode({
code: params.get('code')!,
codeVerifier: sessionStorage.getItem('pkce_verifier')!,
clientId: 'your-client-id',
redirectUri: 'https://yourapp.com/callback',
});
步骤 3: 创建 SDK 客户端
import { createFreelo, getProjects } from '@freeloapp/js-sdk';
createFreelo({
auth: {
type: 'oauth',
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
clientId: 'your-client-id',
expiresAt: tokens.expiresAt,
onTokenRefreshed: (newTokens) => {
// Persist new tokens (localStorage, database, etc.)
localStorage.setItem('freelo_tokens', JSON.stringify(newTokens));
},
},
userAgent: 'YourApp/1.0',
});
// Use the SDK normally — token refresh happens automatically
const { data: projects } = await getProjects();
SDK主动刷新令牌(到期前为30个)并反应(401个回复). 同步请求共享一个刷新呼叫 .
其它 OAuth 公用事业:
import {
refreshAccessToken, // Manually refresh a token
revokeToken, // Revoke an access or refresh token
discoverOAuthServer, // Fetch OAuth server metadata (RFC 8414)
} from '@freeloapp/js-sdk';
配置
import { createFreelo } from '@freeloapp/js-sdk';
const client = createFreelo({
auth: { // Required: authentication credentials
type: 'basic', // Basic Auth with email + API key
email: '[email protected]',
apiKey: 'your-api-key',
},
userAgent: 'YourApp/1.0', // Required: Identifies your application
baseUrl: 'https://api.freelo.io/v1', // Optional: API base URL
logging: true, // Optional: Log requests to console
headers: { // Optional: default headers on every request
'X-Custom-Header': 'custom-value',
},
});
默认信头
使用 headers 选项,当您需要在每个请求中发送一个信头时 -
例如,添加跟踪或客户身份识别元数据,或何时
User-Agent 无法从 JavaScript( 浏览器, 嵌入的网络) 设置
视图),您需要通过自定义头来识别客户端:
createFreelo({
auth: { type: 'bearer', token: '...' },
userAgent: 'YourApp/1.0',
headers: {
'X-Custom-Header': 'custom-value',
},
});
按请求 headers 覆盖这些默认值 。 内置 Authorization
财务报告和审定财务报表 User-Agent 信头总是获胜——使用 auth 财务报告和审定财务报表 userAgent 来改变它们.
多用途/ 请求认证
为不同的用户创建多个客户端实例 :
import { createFreelo, getProjects } from '@freeloapp/js-sdk';
// Basic Auth client
const basicClient = createFreelo({
auth: { type: 'basic', email: '[email protected]', apiKey: 'admin-key' },
userAgent: 'MyApp/1.0',
});
// Bearer token client
const tokenClient = createFreelo({
auth: { type: 'bearer', token: 'your-jwt-token' },
userAgent: 'MyApp/1.0',
});
// OAuth client
const oauthClient = createFreelo({
auth: { type: 'oauth', accessToken: '...', refreshToken: '...', clientId: '...' },
userAgent: 'MyApp/1.0',
});
// Use default client (last one created)
const { data: projects } = await getProjects();
// Or pass client explicitly
const { data: adminProjects } = await getProjects({ client: basicClient });
API 参考
所有 SDK 函数都是自动生成的 Freelo OpenAPI 光谱。每个函数直接映射到一个API端点.
项目
import {
getProjects,
getAllProjects,
getProject,
createProject,
deleteProject,
archiveProject,
activateProject,
getProjectWorkers,
} from '@freeloapp/js-sdk';
// List own active projects
const { data: projects } = await getProjects();
// List all projects (paginated)
const { data } = await getAllProjects({ query: { p: 0 } });
// Get project by ID
const { data: project } = await getProject({ path: { project_id: 42 } });
// Create project
const { data: newProject } = await createProject({
body: { name: 'New Project', currency: 'CZK' },
});
// Delete / archive / activate
await deleteProject({ path: { project_id: 42 } });
await archiveProject({ path: { project_id: 42 } });
await activateProject({ path: { project_id: 42 } });
任务
import {
getAllTasks,
getTask,
createTask,
editTask,
finishTask,
deleteTask,
moveTask,
} from '@freeloapp/js-sdk';
// List all tasks (paginated)
const { data } = await getAllTasks({ query: { p: 0 } });
// Get task by ID
const { data: task } = await getTask({ path: { task_id: 99 } });
// Create task in a tasklist
const { data: newTask } = await createTask({
path: { tasklist_id: 5 },
body: { name: 'New Task', worker_ids: [1] },
});
// Edit task (name, description, labels, worker, due dates, priority, tracking users)
await editTask({
path: { task_id: 99 },
body: {
name: 'Updated Name',
description: '<p>Rewritten task body</p>', // overwrites the whole description
},
});
// Finish / delete / move
await finishTask({ path: { task_id: 99 } });
await deleteTask({ path: { task_id: 99 } });
await moveTask({
path: { task_id: 99 },
body: { tasklist_id: 10 },
});
任务标签
import {
findAvailableTaskLabels,
createTaskLabels,
addTaskLabelsToTask,
removeTaskLabelsFromTask,
mergeTaskLabels,
getTaskLabelColors,
} from '@freeloapp/js-sdk';
// All labels available to the caller, optionally narrowed to one project
const { data: all } = await findAvailableTaskLabels();
const { data: inProject } = await findAvailableTaskLabels({
query: { project_id: 42 },
});
// Fetch-or-create — an existing label with the same name AND color is reused
await createTaskLabels({ body: { labels: [{ name: 'bug', color: '#ff0000' }] } });
// Attach / detach on a task (by uuid, or by name + color)
await addTaskLabelsToTask({
path: { task_id: 99 },
body: { labels: [{ name: 'bug', color: '#ff0000' }] },
});
await removeTaskLabelsFromTask({
path: { task_id: 99 },
body: { labels: [{ uuid: 'aaaaaaaa-...' }] },
});
// Merge labels — every task carrying a source label ends up with the target label
await mergeTaskLabels({
body: {
from_uuids: ['aaaaaaaa-...', 'bbbbbbbb-...'],
to_uuid: 'cccccccc-...',
},
});
合并注释:目标的名称和颜色来自现有的 to_uuid 标签,
所有UUID必须归呼叫者所有( 否则 404),替换适用
仅用于呼叫者为指挥官的项目中的任务,以及源标签
定义与任务脱节,但不被删除.
通知自己自己的行动
默认情况下,API会从通知收件人中省略动作的作者.
过 notify_author: true 用于自动化
运行在自己的标志下。 获得支持 createTask 联合国 subtasks, (中文(简体) ),
editTask, (中文(简体) ), activateTask, (中文(简体) ), finishTask, (中文(简体) ), editTaskcheck, (中文(简体) ), finishTaskcheck, (中文(简体) ),
createComment, (中文(简体) ), editComment 财务报告和审定财务报表 editNote。 。 。 .
await createComment({
path: { task_id: 99 },
body: { content: 'Deployed to production', notify_author: true },
});
它只有在您是用户、工人或跟踪用户时才生效 目标.
任务列表
import {
getAllTasklists,
getTasklist,
createTasklist,
} from '@freeloapp/js-sdk';
const { data } = await getAllTasklists();
const { data: tasklist } = await getTasklist({ path: { tasklist_id: 5 } });
const { data: newTasklist } = await createTasklist({
path: { project_id: 42 },
body: { name: 'New Tasklist' },
});
评论
import { getAllComments, createComment, editComment } from '@freeloapp/js-sdk';
const { data } = await getAllComments({ path: { task_id: 99 } });
const { data: comment } = await createComment({
path: { task_id: 99 },
body: { content: 'Hello!' },
});
时间跟踪
import { startTimeTracking, stopTimeTracking, editTimeTracking } from '@freeloapp/js-sdk';
await startTimeTracking({
path: { task_id: 99 },
body: { note: 'Working on feature' },
});
await stopTimeTracking({ path: { task_id: 99 } });
搜索
import { search } from '@freeloapp/js-sdk';
const { data: results } = await search({
body: { search: 'bug fix' },
});
倾斜
SDK提供处理分解反应的公用设施:
import { fetchAllPages, iteratePages, createPaginator, getAllProjects } from '@freeloapp/js-sdk';
// Iterate through all items one by one
for await (const project of iteratePages(
(page) => getAllProjects({ query: { p: page } }),
(response) => response.data ?? []
)) {
console.log(project.name);
}
// Fetch all pages at once
const allProjects = await fetchAllPages(
(page) => getAllProjects({ query: { p: page } }),
(response) => response.data ?? []
);
// Create a reusable paginator
const paginator = createPaginator(
(page) => getAllProjects({ query: { p: page } }),
(response) => response.data ?? []
);
const all = await paginator.fetchAll();
处理错误
import { getProject, isFreeloError, isRateLimited, isUnauthorized, isNotFound } from '@freeloapp/js-sdk';
const { data, error, response } = await getProject({ path: { project_id: 123 } });
if (error) {
if (isRateLimited(error)) {
console.log(`Rate limited, retry after ${response?.headers.get('Retry-After') ?? '?'} s`);
} else if (isUnauthorized(error)) {
console.log('Invalid credentials');
} else if (isNotFound(error)) {
console.log('Project not found');
} else if (isFreeloError(error)) {
console.log('API error:', error.message);
}
} else {
console.log('Project:', data);
}
限制费率
每个 Freelo 用户的 API 费率限制请求( token buck) 。 限制由同一用户的所有应用程序和符号共同使用,而准确的数字是可配置并可能改变的——不要硬编码.
- 超过时,你会得到一个
429状态代码为 aRetry-After头(秒). 在重试前至少要等那么长时间; 在重复的429s上使用指数回放 。 SDK自动登录警告. - 答复还附有信息 机构间工作组
RateLimit页眉,比如说.RateLimit-Policy: "default";q=60;w=20(单位:千美元)q请求数w秒) 和 时间RateLimit: "default";r=42;t=5(单位:千美元)r剩余请求, 全部填入t页:1.Retry-After是权威的.
工具函数
日期公用事业
import { dateToApi, dateFromApi, today, daysFromNow } from '@freeloapp/js-sdk';
dateToApi(new Date()); // "2024-01-15"
dateFromApi('2024-01-15'); // Date object
today(); // Today in API format
daysFromNow(7); // 7 days from now
货币
import { currencyToApi, currencyFromApi, formatCurrency } from '@freeloapp/js-sdk';
currencyToApi(123.45); // "12345"
currencyFromApi("12345"); // 123.45
formatCurrency(123.45, 'CZK'); // "123,45 Kc"
更新 SDK 当 API 更改时
SDK来自在线 OpenAPI spec at https://api.freelo.io/docs/v1/freelo-api.yaml。 。 。 .
npm run generate # Re-generate from latest spec
npm run generate:check # Verify generated code matches committed version
CI 管道检查 每周一次的光谱变化.
类型脚本支持
所有类型都是自动生成和完全输入的 :
import type { ProjectFull, TaskFull, UserBasic, TaskCreate } from '@freeloapp/js-sdk';
从v1移徙
v2 将基于类的 API 替换为可树动函数 :
// v1 (class-based)
import { Freelo } from '@freeloapp/js-sdk';
const freelo = new Freelo({ email, apiKey, userAgent });
const projects = await freelo.projects.list();
// v2 (function-based, tree-shakeable)
import { createFreelo, getProjects } from '@freeloapp/js-sdk';
createFreelo({ auth: { type: 'basic', email, apiKey }, userAgent });
const { data: projects } = await getProjects();
捐款
欢迎捐款! 在提交拉动请求之前,请阅读我们提供的资料准则.
许可证
麻省理工学院