@alessandro-afloarei/ 融入
一个用于节点22及后期的服务器端连接层. 仅限无害环境管理;安装于 pnpm add @alessandro-afloarei/[email protected]。 。 。 .
通过它的子路径导入您需要的模块 。 没有根管子。 TypeScript声明是API的参考.
errors 提供编码错误, 如 ProviderHttpError 财务报告和审定财务报表 GrantRevoked. Apps将其代码映射到自己的
消息和再连接行为;库错误从来不包括提供者响应机构或秘密.
ProviderHttpError.retryAfterMs 最后反应的诊断等待数以毫秒为单位,或 null 缺席时或
无效。 一个有效的 Retry-After 标题( 秒或 HTTP- 日期) 战胜 Breakcold 的延迟或萤火虫的时代
时间戳;过去的日期产生零分和分数的身体延迟。 字段不更改重试计数或
等待盖,一个应用程序必须仍然决定一个呼叫是否安全可以重试. HubSpot被录取 MISSING_SCOPES 财务报告和审定财务报表
VALIDATION_ERROR 类别出现在 detail;其他类别省略。 错误代码和信件保持不变.
providers 持有HubSpot,Slack,萤火虫,Granola,Breakcold,Unipile,Firecrawl和Exa等定义. 通过一个条目
例如 hubspot 到 OAuth 或 HTTP 呼叫 。 提供者模块拥有范围;工作空间特定基址仍然是应用配置.
vault 任意的 JSON 用 createVault({ tenantKeys, keys })调用 seal 财务报告和审定财务报表 open 与租户
连接ID。 它打开了gaja的现有格式1并写入了密钥源所选择的格式;格式2增加了AAD.
使用 rewrapTenantKey 将租户的数据密钥移动到目前的KEK或格式,而不重写其秘密.
oauth 构建同意 URL 与 authorizeUrl 处理 exchangeCode, (中文(简体) ), refreshGrant 财务报告和审定财务报表 revokeGrant 打开
oauth4webapi。 。 。 . pkcePair 支持的 PKCE。 在每个网络呼叫中导入抓取; 应用程序拥有状态
无. exchangeCode 只返回提供者的符号回答字段 extras 名字,从没有其他的.
connect 用品 startConnect(provider, options) 财务报告和审定财务报表 finishConnect(provider, input)开始返回方向,
秘密字段表或主机URL。 OAuth 完成 交换代码, 识别账户, 并撤销新代码
身份失败时给予最佳效果; 所需的 onRevokeFailed(error) 输入报告清理失败 。 每个 OAuth 模块
提供其吊销回调; 提供者在重新同意时返回相同的活的令牌, 在使用此流前需要适配器 .
该应用程序拥有非ce验证,
注册重定向 URI, 验证器存储并封存返回的秘密 . 永远不要发送 ConnectStart 转到浏览器 :
保留 codeVerifier 在服务器上并重定向到 url 一个人 空白的OAuth状态和缺失的必要核查人被拒绝.
slack 出口 slackConnect, (中文(简体) ), SLACK_SCOPES 财务报告和审定财务报表 slackClient({ token, fetch })。客户站一次,列出最多
5页的200个频道{ items, skipped, channelsCut }),并撤销赠款. channelsCut 说还有更多页子.
OAuth和Web API的答覆是 GrantRevoked,与
提供者代码在 detail; 已经失去的标志是成功的撤销。 那个假的 slack/fake 需要注册
绝对 redirectUri,拒绝其他目的地,并发布与授权客户绑定的单一用途代码
调用。 在交换假代码之前,测试必须授权.
credentials 用品 readSecret aPI 密钥和 accessToken 用于OAuth赠款。 通过商店,金库,锁和
刷新函数 。 刷新默认使用15分钟的比值,即提供者现有的30秒锁键,以及
相较而取取之. 拒绝的刷新允许同时编剧保存5秒,每500毫秒读取一次.
忙碌的锁可以提供仍然有效的信号; RefreshBusy 请应用程序稍后重试 .
http 创建认证客户端 createClient({ provider, token, fetch })调用 json 分类
JSON的答复或 request 用于原始状态、页眉和解析数据。 托肯被再用,直到401人要求续作.
客户端应用超时,节奏和封顶429等;只获取和明确化能调用重试,a
呼叫器的信号禁用重试等待 。 仅在同一来源(307/308或301-303)进行重新定向
最多5个跳 就连证书都找不到另一个主机了 传回被监视的软件 保存固定装置
和生产检查.
webhooks 验证 HMAC 签名 verifyWebhook(provider.webhook, request, secret) {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}在原生的身体上 {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}在原生的身体上
字节。 使用 readCappedBody(request, maxBytes) 在核查之前。 运行、重放保护、去dupe和收件箱
留在应用程序中.
exa, (中文(简体) ), firecrawl 财务报告和审定财务报表 unipile 是提供者模块 : exaClient, (中文(简体) ), firecrawlClient 财务报告和审定财务报表 unipileClient 拿着钥匙
和该应用程序的取回和回打的电话,所以该应用程序从不构建一个提供者请求或读取提供者的答案.
图书馆用Zod检查每个答案,没有公共类型名称,所以一个app自己的Zod版本从来没有遇到过;
错误形状的答案是 ProviderHttpError 有代码 invalid_response。Firecrawl 不发送浏览器动作
并读取一个页面. unipileOrigin (单位:千美元) providers,所以一个靴子检查负载
没有客户端)读取Unipile仪表板显示的工作空间地址,并且 parseAccountNotification 阅读主机签名通知; 检查其 name 是应用程序的.
unipileConnect({client, link, signal?}) 组成现有的 V1 主机登录 startConnect 财务报告和审定财务报表 finishConnect。 。 。 .
开始返回 {kind:'hosted', url}; 结束 {secret:accountId} 并返回该 id 作为秘密和账户
名称/编号,加 {createdAt} 细节。 可选的信号将账户搜索绑定 . authLink 拒绝空白状态;
非认证、账户所有权、接受的创建年龄和持久性都留在应用程序中.
granola 财务报告和审定财务报表 breakcold 是 API 源代码模块。 他们的客户返回提供者自己的字段名称,因为
一个应用程序存储他们读到的, 并回答列表一 Page 一次: { items, skipped, cursor }时 skipped
保存客户端无法读取的条目的id cursor 在最后一页是无效的. paginate(load) 走着走着
页面并拒绝重复光标; 应用程序在它自己的预算表明时停止 。 断线是 invalid_response 与
没有状态和图书馆自己的 detail (单位:千美元)cursor_repeated, (中文(简体) ), cursor_missing)),所以它从不读作提供者的代码. createClient是因为 beforeRequest(url)
一旦每通电话运行 任何信息发送之前, 一个应用的计量, 和拒绝 ProviderHttpError.detail 携带
提供商自己的代码,目录读取一个(Breakcold's usage_limit) (中文(简体) ).
hubspot 提供 hubspotClient 搜索对象、批次读取、交易关联、门户身份、阶段和
拥有者. changedRecords 按上升对象编号顺序行走已更改的记录,从 afterId 而不是一个
搜索偏移, 因此没有查询页面 超过 HubSpot 的 1万个结果上限 。 该应用程序提供访问端函数和
获取, 当扫描预算用完时可以停止 .
hubspotConnect 从 hubspot 编曲: startConnect 财务报告和审定财务报表 finishConnect,请求 OAuth 并读取访问
公司、联系人、交易和所有者。 身份用符号回答 hub_id 首先,否则账户-信息,并返回
account: { id: portalId, name: "Portal <portalId>" }, (中文(简体) ), details: { portalId },以及 secret: grant两种身份来源
需要正整数或字符串匹配 ^[1-9]\d*$; 畸形的符号身份失败而不会倒回.
这个秘密是保密的 Grant 形状. HUBSPOT_SCOPES 导出相同的命令范围列表
hubspotConnect. HubSpot可在重新同意时还原门户现有的刷新令牌,因此连接合同的
reusesGrant: true 跳过失败的识别清理。 孤儿补助金在下次同意后退还;取消
可以结束一个直播连接。 应用程序在放弃赠款前必须检查所有者。 仍然明确撤销
取消刷新令牌;仅限访问的赠款自然失效.
fakeHubSpot({ client: { clientId, clientSecret }, redirectUri, ...portalData }) 从 hubspot/fake 要求
注册客户端和绝对的HTTP(S)调用,无需用户信息或片段。 注册确切的召回
两者均使用 startConnect 财务报告和审定财务报表 finishConnect。将真实授权的 URL 输入到假的,然后提取其重定向
单用 code;静态固定码被拒绝. 授权需要注册客户ID和每个
HUBSPOT_SCOPES 范围。 交换、刷新和撤销需要匹配 client_id 财务报告和审定财务报表 client_secret无效
证书返回 401 invalid_client 而不花费有效的代码。 交换将代码绑定到确切的回调
并仅接受 authorization_code 或者说 refresh_token 补助金类型.
一个注册客户/门户网站拥有一个经过同意的新鲜信号。 它的最初形状是
fixture-refresh-<sha256(JSON.stringify([clientId, hubId]))>; 在撤销后, 下次同意会添加 UUID 后缀
并发行了一个新的符号。 如果在征得任何同意之前继续更换或恢复遗留物,就成为
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你说什么? 如果已经存在生活补助,则更新作为该补助持有人的持久象征物
并返回当前犬形标志;随后同意继续返回。 撤销任何一条小道具
或任何被接受的别名取消该赠款的所有持有人。 已知被吊销的持有人仍然被拒绝,并重复
取消不能终止以后的新赠款。 这种别名的卡通化是一种合成固定行为
生产 Grant 合同不变。 撤销后真正的 HubSpot 行为尚未被探测; 新建
发布是固定裁决。 代码和访问符保持了 per-intance UUID 命名空间,因此 stale codes不能交叉实例.
刷新只接受客户端/门户网站的固定符号形状和遗产 fixture-refresh 种子,包括
重新启动后持续有效符号。 代码,访问令牌,任意字符串和真实令牌无法刷新.
保留 每个进程一个假实例 跨授权,交换,刷新和撤销。 仅接受撤销
在此情况下,发出或恢复的刷新令牌会屡次成功,并防止进一步刷新.
身份不明的吊销额仍为400 invalid_token; 真正的HubSpot的响应没有被印出. 撤销历史
本地进程:其他进程看不到它,重启就会忘记它. 坚持的标志必须首先恢复
或经同意后返回,然后才能撤销。 这些都是合成的固定限制,不是
生产撤销担保。 该应用程序在完成前仍会消耗并验证回调状态.
import { startConnect, finishConnect } from '@alessandro-afloarei/integrations/connect';
import { hubspotConnect } from '@alessandro-afloarei/integrations/hubspot';
import { fakeHubSpot } from '@alessandro-afloarei/integrations/hubspot/fake';
import { fakeFetch } from '@alessandro-afloarei/integrations/testing';
const redirectUri = 'https://app.test/api/integrations/hubspot/callback';
const http = fakeFetch(fakeHubSpot({ ...portalData, client, redirectUri }));
const begun = await startConnect(hubspotConnect, { clientId: client.clientId, redirectUri, state });
if (begun.kind !== 'redirect') throw new Error('expected_redirect');
const consent = await http.fetch(begun.url, { redirect: 'manual' });
const back = new URL(consent.headers.get('location') ?? '');
if (back.searchParams.get('state') !== state) throw new Error('state_mismatch');
const code = back.searchParams.get('code');
if (!code) throw new Error('missing_code');
const connected = await finishConnect(hubspotConnect, {
client, code, redirectUri, fetch: http.fetch, onRevokeFailed,
});
这个例子使用应用软件 portalData缩写 client,新存储 state,则 onRevokeFailed 观察员.
在应用中, 消耗和验证该状态一次; 在服务器上保留返回的秘密 .
testing 提供脚本 fakeFetch 路径,重复 sequence 答复, memoryStores, (中文(简体) ), memoryLock 财务报告和审定财务报表
openLock。每个供应商模块旁边有一个假的(exa/fake, (中文(简体) ), firecrawl/fake, (中文(简体) ), unipile/fake, (中文(简体) ), granola/fake, (中文(简体) ),
breakcold/fake, (中文(简体) ), hubspot/fake: fakeExa, (中文(简体) ), fakeFirecrawl, (中文(简体) ), fakeUnipile, (中文(简体) ), fakeGranola, (中文(简体) ), fakeBreakcold 财务报告和审定财务报表
fakeHubSpot 从应用程序通过的数据中返回接听客户通话的路径
(每个客户自己的测试 支持其确切的要求; fakeGranola 内入每张笔录,所以它从来没有回答413. respondFrom(routes) 回答路径请求或返回无效,
是一个应用的固定模式.
fakeBreakcold 接受可选 readable: {notes?, meetings?} 编号必须可用的固定装置的集合
不输入摄入列表。 常规 notes 财务报告和审定财务报表 meetings 仍然提供这些名单,并优先考虑
重复编号。 失踪的身份证仍为404;只有直接会议使用现有的 segments 收集笔录.
fakeUnipile 可选择接受 hostedConsent: {consentUrl, successUrl, failureUrl, notifyUrl, notify, accountId}。 。 。 .
注册绝对的 HTTP( S) URL 不使用用户信息或片段 。 此模式取代遗留 authLink 回调 :
真实客户端的认证链接请求必须与这些目的地相匹配,并生成一个过期的单一用途同意URL.
从假货的路线取来 贴出V1 CREATION_SUCCESS 通知约束国和提供应用程序
账户编号。 接受的通知重定向到注册成功 URL; 失败或重定向的通知
转到失败的 URL。 从未遵循通知重定向,浏览器参数不能覆盖绑定.
捆绑是实例本地的:固定适配器应在同一请求中获取并消耗新的认证链接,
因此,重新启动dev服务器不会丢失较早的浏览器请求绑定. 生产主机签入时没有
图书馆-地方州。 该应用程序仍然提供账户固定 createdAt 重视并执行其非ce政策.
运行 checkCredentialStore 针对应用程序数据库测试层中每个真正的商店适配器,使用一个
孤立现有的连接固定器和一个没有密钥的租户;它恢复了连接最初被封存的秘密.
Apps 执行四个接合;库中没有数据库或 Redis 客户端:
SecretStore: read a connection secret and replace it only at the expected version.
TenantKeyStore: read, insert the winning tenant key, and replace at the expected version.
KeySource: expose current KEK version, write format, and get(version).
WithLock: run work under a named lock, or return "busy".
运行 pnpm install --frozen-lockfile,则 pnpm check 用于类型检查,带有零警告的 ESLint, knip 和 Vitest.
运行 pnpm build 无害环境管理和申报,或 pnpm pack 用于本地安装。 图书馆测试使用假提供者和
内存储,不需要服务器或数据库.
释放标记必须匹配软件包版本. 检查和合并后,维护者推出 v* 标记; CI 重复
并使用存储器公开发布 NPM_TOKEN 暗号 Apps Pin准确的版本.
萤火虫
firefliesClient({ apiKey, fetch, signal? }) 读取密钥所有者(user),笔录(transcript, (中文(简体) ),
关键字匹配( e)search页:1transcripts) (中文(简体) ). identify(client) 是 API- key 证明 .
changedTranscripts(client, { userId, fromDate, toDate, cursor? }) 输出页面通过 paginate窗口
文本创建日期的过滤器, 而非修改日期 : 一旦创建到外部, 将不会重新生成编辑
窗户。 Windows必须重叠(gaja使用三天). 萤火虫没有命令保证; 应用本身的分解
和页数预算。 打破重复以强制您自己的运行预算.
光标是 JSON 字符串,将偏移绑定在用户、日期窗口和固定的50个记录的页面大小上 null
在结尾。 只用相同的查询恢复; 一个新窗口开始时没有光标 。 光标不正确或错配
掷出 TypeError('cursor_invalid')。无效的日期和搜索限制 TypeError('date_invalid') 财务报告和审定财务报表
TypeError('limit_invalid'); 搜索接受从1到50的整数限制. skipped 无法读取的报告列表
条目,计算为平方。 Apps根据自己的存储合同验证记录. 无法正常
详细记录抛出 FirefliesTranscriptError 从 fireflies/errors页:1 ProviderHttpError 有代码
invalid_response, (中文(简体) ), detail: 'transcript_invalid' 和消毒的 path 仅包含字段名称和索引.
它不同于一个缺失的记录,它返回 null。 。 。 .
fireflies/fake 出口 fakeFireflies({ account: apiKey => ({ user, transcripts }) }); 返回时 null 拒绝
键。 传出路线 fakeFetch 或者说 respondFrom 从 testing包括身份、呼号、记录
和关键词搜索与呼叫者拥有的固定数据.
在验证原始请求后 verifyWebhook萤火虫 parseWebhook(body) 读取V2事件,
meeting_id 和时间戳(数字,或遗留字符串)。 未知字段被省略; 错误的事件返回为无效 .
断了 parseWebhook(headers) 读取 x-webhook-delivery-id. Apps 自身分解并保留原字节.
HubSpot 舞台历史
hubspotClient(...).dealStageHistory(ids) 返回 a Map<string, HubSpotStageRevision[]>,每次修订
形状为 { value: stageId, timestamp, sourceType? }先订出最老的 时间戳保存得准确;
等于乘以印章保留提供商的命令。 一个没有历史地图的回归交易 []缺少一个交易.
该方法使用单独的50ID历史限制来读取相继分批提供的所有ID(说明为100分)。 失败的批次拒绝
带有通常的 sanitized 提供者错误的呼叫, 包括提供者的批量限制 400; 它从不返回部分地图 .
历史意味着 仍然保留每个修订版HubSpot。 。
每个交易财产最多20个修订, (中文(简体) ),
没有日历保留窗口,也没有记录处理阶段的例外。 图书馆归还所有供应和
从不合成缺失的修改。 历史读取使用50个输入上限,基于供应商的批次历史400
报告年份 接发式HQ/接发式8462。报告的目的是
联系人; 我们对交易适用相同的财产历史上限。 枢纽点
发售 OpenAPI
警告请求历史会降低每个请求的最大,而不命名数字.
这个 发牌指南 文档
propertiesWithHistory: ["dealstage"]。没有文件记录的历史光标可以恢复被磨损的订正.
这个 官方 OpenAPI 计划
将时间戳描述为属性更新时间,但并不能明确保证其不可更改性贯穿读取.
限制来自所观察到的供应商错误和官方文件;我们没有运行一个真正的门户探测器.
fakeHubSpot(data) 还接受 fakeHubSpot(() => data)。回调一次在建设时运行,必须返回
有效数据。 它每提供一次当前门户内容
(c) 在施工时进行OAuth注册(客户、重定向URI、chubId),并授予状态
在内容变化中存活下来。 可选 dealStageHistory 用于已知同步和分组交易的映射处理 ID 到修订版数组.
可选 dealContacts 地图同步处理 ID 以联系 ID 阵列, 缺席时返回组图 ;
一个明确的空数组覆盖了组。 暗示这些领域保留了现有的行为.
dealCompanies 将交易映射到一个公司ID,或 { id, primary? }[] 服务于HubSpot的协会类型.
dealCompanies(ids) 返回每个交易的初级公司(HubSpot) HUBSPOT_DEFINED 第5类),否则其最低值
因为HubSpot没有命令交易协会.
假的回报了超过50个输入量的历史批次的400个,所以固定后置的消费者行使相同的限制.