@fluid-app/exigo-connection-sdk (英语)
流水滴子和迷雾应用程序与 Exigo 交谈的一个方法:一个 REST 客户端, a 缓存了 SQL 池,一个证书界面和打出的错误. 包拥有 连接, 认证和只错误 。 每个应用程序都保留商业查询.
安装
在 npmjs 上公开:
pnpm add @fluid-app/exigo-connection-sdk
# Only for apps that query the SQL replica:
pnpm add mssql
pnpm add -D @types/mssql
# Only for apps that reach Exigo through Fluid's egress proxy:
pnpm add undici
| 导入 | 提供 | 需求 mssql |
|---|---|---|
@fluid-app/exigo-connection-sdk | defineExigoCredentials,证书类型,错误 | 没有 |
@fluid-app/exigo-connection-sdk/rest | createExigoRestClient错误 | 没有 |
@fluid-app/exigo-connection-sdk/sql | getExigoPool, (中文(简体) ), closeExigoPool错误 | 对 |
在"节点"20+上运行:"云跑"和"Vercel"的"节点"运行时间. 不在边道上.
1. 每个应用程序一次的全权证书
软件包没有读取任何环境变量,也不存储任何东西. 应用程序说
证书来自何处; 缺少的字段丢出 ExigoCredentialsError
点名.
// src/lib/exigo.ts — a multi-tenant droplet
import { defineExigoCredentials } from "@fluid-app/exigo-connection-sdk";
export const resolveExigoCredentials = defineExigoCredentials(
async (companyId: string) => {
const c = await prisma.credentials.findUniqueOrThrow({
where: { companyId },
});
return {
rest: {
baseUrl: c.exigoApiBaseUrl,
username: c.exigoApiUser,
password: c.exigoApiPassword,
company: c.exigoCompanyName,
},
sql: {
host: c.exigoDbHost,
database: c.exigoDbName,
username: c.exigoDbUsername,
password: c.exigoDbPassword,
// Required, no default. true skips server certificate verification,
// which Exigo's replicas need: they present a certificate that does
// not verify against the host (e.g. SQL Server's self-signed one).
trustServerCertificate: true,
},
};
},
);
一个单租入的Mist app从同一个函数返回它的env vars. 解析器运行在每一个呼叫, 所以缓存在应用程序中,如果查取费用昂贵.
2. 减少排放
import {
createExigoRestClient,
ExigoAuthError,
ExigoTimeoutError,
} from "@fluid-app/exigo-connection-sdk/rest";
const { rest } = await resolveExigoCredentials(company.id);
const exigo = createExigoRestClient(rest);
try {
const account = await exigo.get<PointAccount>(
"/customers/{id}/pointaccounts/{accountId}",
{ params: { id: customerId, accountId: pointAccountId } },
);
} catch (error) {
if (error instanceof ExigoAuthError) {
/* wrong credentials: tell the admin */
}
if (error instanceof ExigoTimeoutError) {
/* retry, or fail the callback fast */
}
throw error;
}
客户端:
- 添加
/3.0到基址, 当存储的 URL 时, 不将其加倍 已有它; 以另一个版本结束的基址, 如/2.0掷出ExigoCredentialsError而不是把客户扣在身上; - 需要一个
https基础 URL, 因为每个请求都带有密码 (单位:千美元)http仅限localhost,用于本地根茎; - 发送 Basic 认证为
username@company· ; - 默认在 15 s 之后的乘数( )
timeoutMs客户或每个电话,在 2,147,483,647 ms,最多setTimeout(b) 能够保持; - 解析 JSON,或
undefined给一个空的躯体; - 掷出
ExigoApiError和200人的身体是 HTML 页面与否 JSON, 而不是将页面作为数据递回 密码和 Basic 令牌从它的消息中编辑bodySnippet· ; - 拒绝绝对 URL 路径, 因此证书只能使用
所配置的主机,以及从 API 版本开始的路径(
/3.0/..., (中文(简体) ), 因为客户添加了它; - 拒绝一条空路,
.或者说..,否则 解决到与路径名称不同的端点.
get, (中文(简体) ), delete 带 params, (中文(简体) ), query, (中文(简体) ), headers, (中文(简体) ), timeoutMs 财务报告和审定财务报表 signal· ;
post, (中文(简体) ), put, (中文(简体) ), patch 还要一个 body作为JSON发送.
通过 Fluid 的 Egress 代理(Mist apps)
Exigo 允许列表通过源 IP 调用程序, 而 Vercel 上的 Mist 应用程序没有固定
离开IP。 Fluid 的 Egress 代理服务器( :services/egress-proxy借给它:a
CONNECT唯一的前方代理 其静态IP Exigo租户许可列表. TLS 留下来
结束在应用程序和Exigo之间,所以代理从未看到Exigo
证书.
pnpm add undici
const exigo = createExigoRestClient(rest, {
egressProxy: process.env.FLUID_EGRESS_PROXY_URL
? {
url: process.env.FLUID_EGRESS_PROXY_URL,
// The install webhook's authentication_token (dit_…).
token: installation.authenticationToken,
}
: undefined,
});
- 流体组合
FLUID_EGRESS_PROXY_URL在一个与水滴相链接的雾软件上 环境有一个代理.fluid mist env pull故意离开: 代理拒绝调用 Fluid 的平台, 所以本地运行调用 Exigo 直接,上面的代码在变量未被设置时会这样做. - 代理认证滴盘安装令牌,然后通过 只有液滴和Exigo主机在自己的许可列表中.
- URL必须是
https(单位:千美元)http仅用于回转代理运行于本地),, 因为CONNECT的要求 将信使带出隧道. - 拒绝掷出
ExigoProxyError,一个子类ExigoConnectionError谁status是代理的回答: 407作为它不接受的标志, 403 对于一个液滴或宿主 它不能通过,502或504 当它不能通过 联系Esigo,503,当它无法核实该标志或能力. - 客户端以相同的代理 URL 和 ocid 共享一个代理, 所以 a 客户端每个请求仍然重复使用打开的地道.
- SQL 通过相同的代理; 见 SQL 通过 Egress 代理服务器。 。 。 .
3. SQL
import { getExigoPool } from "@fluid-app/exigo-connection-sdk/sql";
const { sql: creds } = await resolveExigoCredentials(company.id);
const pool = await getExigoPool(creds);
const { recordset } = await pool
.request()
.input("email", email)
.query("SELECT CustomerID FROM Customers WHERE Email = @email");
getExigoPool 返回一个 mssql ConnectionPool,每个主机、端口缓存,
数据库和用户名,每个密码都在其中。 重复通话重复使用
它, 并行的首通电话共享一个连接, 一个失败的连接不是
已缓存 。 一个旋转的密码打开自己的池而不关闭上一个
一,所以飞行中的请求 通过旋转,继续工作 和回滚
立即连接; 前一个游泳池一旦无任何要求就关闭
五分钟后,一个数据库的当前游泳池 曾经没有要求它
30岁。 池子很小(有4个连接,10 s闲后关闭),因为每个正在运行的实例都会自开. 过
{ max, idleTimeoutMs, connectTimeoutMs, requestTimeoutMs } 作为第二个
参数以更改该参数; 当池打开时, 选项适用.
对于输入的参数,请从 mssql 本身
(单位:千美元)import sql from "mssql"; request.input("id", sql.Int, id)) (中文(简体) ).
连接失败以 ExigoAuthError, (中文(简体) ), ExigoTimeoutError 或者说
ExigoConnectionError写着要检查的信息 出错
应用程序本身的查询是单独处理的; 通过一个 translateExigoSqlError 改为
以同样的方式映射超时或已丢弃的连接 。 查询出错( T)RequestError(中文(简体) )
除非其代码是传送代码,否则返回时不变(ETIMEOUT, (中文(简体) ),
ECONNCLOSED, (中文(简体) ), ESOCKET),因此一个不好的表格名称从未作为网络报告
失败.
关闭时关闭池 :
import { closeAllExigoPools } from "@fluid-app/exigo-connection-sdk/sql";
process.once("SIGTERM", () => void closeAllExigoPools());
在下一个, 保留 mssql 从捆绑和边缘:
// next.config.ts
export default { serverExternalPackages: ["mssql"] };
// every route that queries
export const runtime = "nodejs";
通过Fluid的Egress代理
与 REST 相同的代理,原因相同: Exigo 允许复制
由源代码 IP. mssql 忽略代理服务器设置, 因此池手乏味 a
打开 CONNECT 隧道通往复制主机和端口的连接器; TDS,
包括其TLS握手,然后在隧道中运行不变. 没有额外
需要软件包.
const pool = await getExigoPool(creds, {
egressProxy: process.env.FLUID_EGRESS_PROXY_URL
? {
url: process.env.FLUID_EGRESS_PROXY_URL,
token: installation.authenticationToken, // dit_…
}
: undefined,
});
- 代理机必须允许复制主机和端口(1433年),而Exigo必须 允许列表 SQL 侧面的代理服务器 IP .
- 代理和代号是游泳池身份的一部分:一个不同的声音 一个得到自己的游泳池.
- 需要通过代理加密.
encrypt: false被拒绝 (单位:千美元)ExigoCredentialsError) (中文(简体) ). 而因为SQL Server 谈判 TLS (乏味) 跳过它,发送登录 密码仅仅是模糊的,当 服务器的 PRELOGIN 答案不提供加密,连接器读取 在登录前回答并挂起, 除非加密ON或者说REQ, (中文(简体) ), 掷出ExigoConnectionError。没有以这种方式检查直接连接. - 拒绝投掷
ExigoProxyError与source: "sql"; 无法为 已到达抛出ExigoConnectionError点名. - 已知缺口 : 连接是加密的,但是
trustServerCertificate: true没有证据表明TLS的另一端是 远征。 代理在隧道内部没有读到任何信息,然而在隧道之间没有任何信息 冒充复制品的代理和Exigo可以读取登录. 直接 连接带有相同的漏洞。 关闭它需要证明 Exigo的 可以验证的一侧.
错误
每个错误都会延伸 ExigoError。没有一个密码或密码
授权头.
| 错误 | 何时 |
|---|---|
ExigoCredentialsError | 缺少或无效的字段( y)fields 给他们起名) |
ExigoAuthError | REST 401/403 或 SQL 登录失败 |
ExigoTimeoutError | 一个 REST 呼叫, SQL 连接或 SQL 查询运行太长 |
ExigoConnectionError | DNS、 拒绝连接、 TLS、 网络 |
ExigoProxyError | egress代理拒绝隧道(status(中文(简体) ) |
ExigoApiError | REST回答错误 或身体不是JSON |
source 实值 "rest" 或者说 "sql" 关于认证、超时和连接错误.
释放
列于 .github/workflows/frontend-publish-rep-packages.yml: 合并为
main 将此软件包修改为 npm , 并折叠补丁
当当前版本已经发布时.