Apport 服务
AppPort Services提供可持久运行的应用能力,它们坐落在AuthPort旁边.
服务集包括API Keys,Jobs, Schedule, Secrets, Webhooks, Files, 以及通知等. 通知由AppPort服务公司储存和交付;它们不是注意管理 层。 Attn可能会消耗它们以分别引起注意.
创建和运行应用程序
对于新的申请:
npx create-appport my-app
cd my-app
npm run dev
生成源仅包含业务处理器. 它不创建HTTP服务器,配置持久性,执行CORS/SSE,运行工作员,发送webhoks,或安装信号处理器.
对于现有应用程序:
在应用程序中安装软件包 :
npm install @appport/runtime
初始化每个功能的 AppPort, 或者只选择应用程序的用途 :
npx @appport/runtime init
npx @appport/runtime init --use api,webhooks,jobs
没有旗帜, init 询问哪些能力可以启用和默认每个是。 这个 --use 表格可用于脚本和 CI.
这就产生了两个应该执行的文件:
appport.toml声明您的应用程序使用的 AppPort 能力 .feltdb.flow是您的应用程序的权威 FeltDB 合同 。 AppPort的内部模板留在npm包内;应用程序开发者不编辑或导入AppPort存储内部.
合同中的靴子AppPort:
import { appport } from '@appport/runtime';
const app = await appport();
// Only capabilities declared in appport.toml are initialized.
await app.api.keys.createApiKey(/* ... */);
appport() 读取 ./appport.toml 并拥有服务建设、持久性、审计基础设施和生命周期。 打电话 await app.close() 在优雅的关闭期间 获取未申报的能力将产生 CapabilityNotDeclaredError 和必要的声明,使之得以实现.
appport.toml 是权威的申请合同。 它在启动时被解析、验证、正常化并被冻结。 它宣布应用程序的身份、部署和州权力、租赁、HTTP/CORS、API密钥、网页快递、工作类型、事件、授权、可观察性、生命周期和发展默认。 哥哥们 feltdb.flow 作为权威性国家合同被部署到联邦贸易局.
仅包含的遗留文件 use api, (中文(简体) ), use webhooks,以及 use jobs 继续支持。 将其中一项扩展至可收回备份的峡谷合同,使用:
npx @appport/runtime config migrate
应用程序代码提供行为 :
import { appport } from '@appport/runtime';
const application = await appport({
routes: {
'POST /invoices': async ({ body, tenantId }) => createInvoice(body, tenantId),
},
jobs: {
'invoice.process': async (job) => processInvoice(job.payload),
},
});
await application.publish('invoice.created', { id: 'inv-123' });
公众 application.state 财务报告和审定财务报表 application.events API提供提供者中立状态并订阅. 应用程序代码从未通过访问其私人数据库的能力到达.
运行时间拥有稳定管理合同:
/_appport/health
/_appport/overview
/_appport/capabilities
/_appport/events
/_appport/api/keys
/_appport/webhooks
/_appport/jobs
卫生为公用. /_appport/capabilities 是未经认证的发现表面,并返回运行中的应用程序的挂载能力目录。 其他终点遵循合同的授权和租户规则。 事件使用 SSE 用于 GET 并发布域事件 POST; API 键,webhooks, 和工作支持运行时拥有的创建/列表操作.
@appport/services 提供CLI和能力实施,但只进口应用源 @appport/runtime现有应用程序可继续使用 createServices() 从 @appport/services 作为兼容的 API.
以常规命令运行您的应用程序, 例如 npm run dev。通过安装的二进制可操作的 CLI 命令 :
npx @appport/runtime api-key list --tenant acme
npx @appport/runtime webhook list --tenant acme
npx @appport/runtime job list --tenant acme
独立管理主机
您不需要应用程序来操作 AppPort 服务 . serve 启动拥有持久状态的管理主机, ServiceGateway,认证,管理路由器,以及 HTTP 服务器:
npx @appport/services init # appport.toml + feltdb.flow for this deployment
npx @appport/services serve # GET /v1/ui, /services, and the other management pages
它的束缚 127.0.0.1:4100 默认; 覆盖到 --host 编号 : --port。状态是相同的持久 FeltDB 部署 。 管理请求使用 AppPort API 密钥进行认证(Authorization: Bearer <secret>)或操作员身份适配器;授权留在AuthBoundry。 见 文件/管理。 。 。 .
AppPort 管理其 FeltDB 运行时依赖性; 消费者不导入 @feltdb/core 或者AppPort的内部商店.
存储器定义 AppPort 能力 租户范围 API 密钥, (中文(简体) ), 持久网点, (中文(简体) ), 长期工作 (包括附表),提供者中立 秘诀 元数据/生命周期和范围解析合同, 持久通知,以及 文件. 遗留的运行时态用途 @feltdb/core (主机副本:0.16.1或后为0.x. 机密材料仍由经授权的提供者提供,从来就不是可耐用的AppPort状态.
Application
│
┌───────────┴───────────┐
│ │
AuthPort AppPort Services
│ │
identity/authz API Keys, Webhooks, Jobs, Secrets
│ │
└───────────┬───────────┘
│
FeltDB
消费者 API
共享主机应用程序的 FeltDB 实例
已经拥有其应用程序的 FeltDB 实例的主机可以运行其中的每一项服务, 而不是让 AppPort 服务打开二审 :
import { createFeltDB } from '@feltdb/core';
import { createServices } from '@appport/services';
const db = createFeltDB({ mode: 'local', namespace: 'invoices', path: './state' });
const services = createServices({ db, application: 'invoices', authorizer: authBoundry });
// Service stores, effect evidence, and services.transaction() all use `db`.
主机保留了所有权: AppPort Services从未关闭过它给过的一个实例. 这个
实例本身的部署模式( e)db.capabilities().deployment用于
模式依赖行为。 使用一份副本 @feltdb/core 对主机和此软件包: 它是
同伴依赖( e)>=0.16.1 <1.0.0),所以主机的复制是服务部使用的,npm安装
没有第二个.
要检查服务对象运行在哪个实例( 本地、 内存或远程) , 请使用
services.db (只读)或 services.usesInstance(db)比较身份;
services.ownsDb 实值 false 对于提供主机的实例:
assert.ok(services.usesInstance(db));
版本、健康、证据和配置转移
import { VERSION } from '@appport/services'; // equals package.json "version"
import manifest from '@appport/services/package.json' with { type: 'json' };
const health = await services.health({ tenantId: 'acme' });
// health.status: 'ok' | 'degraded' | 'unconfigured'; health.services.webhooks.state; health.attention.failedWebhookDeliveries
const principal = services.identify({ principalId, principalType: 'user', tenantId, runId: requestId });
await services.invoke('files.write', input, { principal });
const { state, records } = await services.evidence.findByRunId(requestId); // state: 'none' | 'started' | 'completed' | 'failed'
const document = await services.configuration.export({ principal, environment: 'staging' });
const report = await other.configuration.import(document, { principal, dryRun: true });
services.health()——服务状态和计数需要注意,从有界限的询问中得出. 见 医生/保健。 。 。 .services.evidence.findByRunId()——记录在运行标识下的效果证据(呼叫者的相关标识),以及什么是started排行是指坠机后. 见 文件/授权。 。 。 .services.configuration.export()编号 :import()——环境之间的非秘密配置;秘密值永远不会离开. 见 文件/配置。 。 。 .webhooks.deliveries.read其本身的阅读网页传送的能力(invoke('webhooks.deliveries.read', { status: 'failed' }), (中文(简体) ),GET /_appport/webhooks/deliveries) (中文(简体) ).
现有认证的Express应用程序可以按其现有的服务实例挂起所支持的管理运行时间:
import { createManagementRouter, createServices } from '@appport/services';
const services = createServices({ path: '.appport', application: 'invoices', authorizer: authBoundry, credentials: authBoundryCustody });
app.use(createManagementRouter({
services,
authority: services.gateway,
authenticate: (request) => hostAuthentication(request), // identity only
}));
主机拥有认证,AuthBoundry拥有授权,而AppPort Services则在任何效果之前执行AuthBoundry的决定. @appport/服务执行效果. 它不决定允许谁造成这些后果. 见 权力模式, (中文(简体) ), 网络商店安全,以及 就业保障. API 密钥管理需要 apikeys.read, (中文(简体) ), apikeys.create,以及 apikeys.revoke (单位:千美元) apikeys.update, (中文(简体) ), apikeys.rotate,以及 apikeys.audit 用于编辑、轮换和审计),总是使用经认证的租户,并返回仅用于创建和轮换答复的简单文字证书。 见 可构成的管理运行时间 完全合同和独立/嵌入行为。 其他软件包可以通过 : 管理扩展。 。 。 .
出界证书使用只限服务器范围的协议. AppPort 定义了引用,上下文,生命周期,审计,出错,以及召回合同; AuthBoundry 授权和 AppBoundry 解决提供者持有的材料. AppPort船没有解析器,秘密商店,供应商适配器,或政策引擎,并暴露出没有浏览器的认证-值路由.
当主人的监护权是 SecretCustody (单位:千美元)withSecret 加号 store 财务报告和审定财务报表 status, (中文(简体) ), credential.store 收集一个值(授权、审计、版本、在FeltDB中从未重复或坚持)并将其交给主机,以及 credential.status 报告是否存在材料。 主机仍然拥有物质生活的地方;一个只解决器的主机得到 CUSTODY_READ_ONLY。 。 。 .
await secrets.withSecret({
reference: { secretId, tenantId: 'acme', provider: 'pipedrive' },
context: { tenantId: 'acme', principalId: 'integration:pipedrive', purpose: 'person.lookup', authorizationRef },
}, async ({ value }) => callProvider(value));
见 外出证书向导 拥有、授权交接、生命周期和故障语义.
见 能力清单 财务报告和审定财务报表 能力授权摘要 综合能力矩阵和挂载状态规则.
合同确定可用的运行时间API:
import { appport } from '@appport/runtime';
const app = await appport({ authorizer: authBoundry, credentials: authBoundryCustody });
// Identity comes from authentication; AuthBoundry authorizes each capability.
const principal = await app.authenticate(request);
// Machine identity (an API key identifies a caller; it carries no scopes)
await app.invoke('apikeys.create', { name: 'server-key' }, { principal });
// Durable outbound notifications, bound to a signing credential in AuthBoundry custody
await app.invoke('webhooks.register', {
url: 'https://acme.example.com/webhooks',
events: ['invoice.created'],
signingCredentialRef: 'credential-ref:whsec_acme',
}, { principal });
// Durable deferred execution; the job runs as this principal and is re-authorized on every run
await app.invoke('jobs.create', {
type: 'invoice.process',
payload: { invoiceId: 'inv-123' },
maxAttempts: 3,
}, { principal });
消费者不需要知道FeltDB在下面存在. 只有申报的能力才得以建立,它们共享一个持久的运行时间.
什么是Apport服务?
Apport 服务答案 :
该应用程序暴露出哪些操作能力?
AuthPort仍然回答身份,认证和授权问题.
见它的行动
完整的示例应用程序可在 examples/services-demo/它表明:
- API 以租户范围为主的密钥认证
- 建立具有自动网签和工作意图的持久发票
- 使用重试和重放的 Webhook 送出
- 以租赁为基础的货币控制处理背景工作
- 租户与世隔绝和耐久性
见 examples/services-demo/README.md 五分钟的快速启动.
建筑
Apport 服务使用流程 @feltdb/core 合同语言)作为权威的持久计划. 包裹的内部 appport.flow 是模板,从中 appport init 生成应用程序的权威 feltdb.flow数字 :
API 键垂直 :
ApiKeys— API 密钥证书( 密钥仅以 scrypt hash 存储)ApiKeyPrefixes——高效秘密验证前置查询ApiKeyAuditEvents——查阅审计线索
垂直 Webhoks :
WebhookEndpoints- 已注册的网页接收器WebhookDeliveries- 有重试状态的出货记录WebhookAuditEvents- Webhook生命周期审计线索
垂直任务 :
Jobs具有执行状态和租赁跟踪的个人工作JobSchedules经常性的工作定义JobAuditEvents工作执行审计线索
垂直密钥 :
Secrets- 租户范围合理的秘密身份和生命周期元数据SecretVersions——提供商参考和明确轮换版本SecretAuditEvents- 创建、解决、轮换、撤销、退休和失败审计记录
秘密行动区分 describeSecret (仅元数据)来自 resolveSecret (授权提供者解决)。 机密值、 平白文本、 已解密的材料和提供者证书不是 appport.flow 或审计活动.
所有藏品均通过租户范围 tenant_id 字段为 tenant_idx 用于高效查询.
依赖方向
feltdb.flow (generated authoritative application contract)
↓
TypeScript implementation
↓
FeltDB (@feltdb/core, the host's copy)
流程合同在测试时进行解析和验证。 TypeScript商店(FeltDbApiKeyStore,FeltDbWebhook EndpointStore等)直接针对FeltDB收藏执行合同语义.
为什么API密钥和AuthPort分开?
API 密钥认证机器主机. 没错 没有 替换 AuthPort 授权.
API key
↓
machine principal
↓
AuthPort authorization
↓
resource/action decision
安装
npm install
npm run build
@feltdb/core 是一个对等依赖:在 Services 旁安装( 最近的 0.x 发布; npm 7 和
服务处使用这个副本:
{
"peerDependencies": {
"@feltdb/core": ">=0.16.1 <1.0.0"
}
}
我如何启用 API 密钥 ?
用 FeltDB 的真正部署模式创建服务 :
import { createApiKeyService } from '@appport/services';
const service = createApiKeyService({
mode: 'local',
namespace: 'appport-services',
path: './.feltdb/appport-services'
});
远程 FeltDB 部署可以使用相同的导出部署字段 resolveFeltDBDeployment() 明白吗.
我该怎么创造呢?
// `operator` is a verified principal (host authentication or an existing API key).
const created = await service.createApiKey({ name: 'production' }, operator);
console.log(created.secret); // only returned once
API 键可以识别一个呼叫器及其应用. 它没有瞄准镜:
AuthBoundry决定 打电话者可以做什么。 通过 scopes 以
迁移错误文件/授权) (中文(简体) ).
可以给出密钥 限制,这个天花板只缩小什么 AuthBoundry允许,加上一个过期. 密钥可以编辑、旋转并使用 可选重叠,一次或批次撤销一次,并审计:
const key = await services.apiKeys.createApiKey({
name: 'reporting-worker',
restrictions: { capabilities: ['files.read'], resources: [{ type: 'file', attributes: { owner: 'reporting' } }] },
expiresAt: new Date(Date.now() + 90 * 86_400_000),
}, operator);
const next = await services.apiKeys.rotateApiKey({ id: key.id, overlapSeconds: 300 }, operator); // next.secret shown once
await services.apiKeys.updateApiKey({ id: next!.id, name: 'reporting-worker-v2' }, operator);
const events = await services.apiKeys.listApiKeyAuditEvents({ credentialId: next!.id }, operator);
await services.apiKeys.revokeAllApiKeys({ createdBy: '[email protected]' }, operator);
撤销和限制更改适用于每次的下一个操作 进程。 见 文档/按键 对于许可模式, 旋转语义,校验键,出错,和迁移注释.
CLI( 通过 APPPORT_AUTHORITY 或者说 APPPORT_API_KEY:
APPPORT_AUTHORITY=./authority.mjs appport api-key create --tenant tenant-123 --name production
应用程序如何认证?
备选案文1:框架中立的HTTP适配器
对于使用普通节点HTTP请求/响应语义的应用程序:
import { createApiKeyAuth } from '@appport/services';
const auth = createApiKeyAuth({ service });
// Optional authentication (returns null if missing/invalid)
const principal = await auth.authenticate(request);
// Required authentication (throws if missing/invalid)
const principal = await auth.require(request);
适配器提取 Authorization: Bearer <api-key> 页眉并返回一个 AuthenticatedPrincipal数字 :
interface AuthenticatedPrincipal {
principalId: string;
principalType: 'api_key';
tenantId: string;
applicationId: string;
credentialId: string;
verifiedBy: 'api_key';
}
校长有品牌:服务只接受校长 认证路径, 绝不是对象字符串或演员字符串 .
备选案文2: 中间快件
对快件应用程序:
import { apiKeyAuth, requireApiKeyAuth } from '@appport/services';
const app = express();
// Optional authentication
app.use(apiKeyAuth(service));
app.get('/invoices', async (req, res) => {
const principal = req.auth; // null if missing/invalid
if (!principal) {
return res.status(401).json({ error: 'Unauthenticated' });
}
// Handle request with principal
});
// Or, require authentication
app.use(requireApiKeyAuth(service));
app.get('/protected', async (req, res) => {
const principal = req.auth; // guaranteed, or middleware rejects
// Handle request with principal
});
中间器件将本金附在 req.auth ,并通过 req.authContext。 。 。 .
租户安全
如果您的申请独立接受租户情况,请对照委托人确认:
import { assertTenant } from '@appport/services';
assertTenant(principal, tenantIdFromRequest); // throws if mismatch
低级接头符提取
关于自定义框架:
import { authenticateBearerToken } from '@appport/services';
const principal = await authenticateBearerToken(
authorizationHeader,
service,
);
授权是怎么发生的?
认证返回一个身份 。 授权属于 AuthBoundry: every
服务效果由配置授权 ServiceAuthorizer 摆在它面前
证书只有在决定之后才能解决,证据是
写给 FeltDB 。 见 文件/授权。 。 。 .
我该怎么用网球?
Webhooks为外部的HTTP端点提供可持久签名的发送.
设置
import { createServices } from '@appport/services';
const services = createServices({ path: './.appport', application: 'invoices', authorizer: authBoundry, credentials: authBoundryCustody });
const service = services.webhooks;
注册终点
const endpoint = await service.createWebhookEndpoint({
url: 'https://customer.example.com/webhooks',
events: ['invoice.created', 'invoice.paid'],
// The signing secret lives in AuthBoundry custody; the endpoint stores only the reference.
signingCredentialRef: 'credential-ref:whsec_customer',
}, principal);
// Private, loopback, link-local, and metadata destinations are rejected; redirects are never followed.
// See docs/WEBHOOK-SECURITY.md.
释放事件
await service.emitWebhookEvent({
type: 'invoice.created',
payload: { id: 'inv-456', amount: 100 }
}, principal);
// Delivery records created automatically for matching endpoints
工人:提供网络呼号
const delivery = await service.getWebhookDelivery(tenantId, deliveryId);
const result = await service.deliverWebhook(tenantId, deliveryId);
if (result.success) {
// Delivered
} else {
// Failed or queued for retry
}
交货由HMAC-SHA256签署. 每次交付包括:
{
"id": "delivery-uuid",
"eventId": "event-uuid",
"type": "invoice.created",
"data": { "id": "inv-456", "amount": 100 },
"timestamp": "2026-09-10T22:30:00Z"
}
页眉 : X-AppPort-Signature: <hex-encoded-hmac-sha256>
申请阅读 webhooks.deliveries.read (每拨电话最多200次)
const failed = await services.invoke('webhooks.deliveries.read', { status: 'failed', limit: 50 }, { principal });
const one = await services.invoke('webhooks.deliveries.read', { id: deliveryId }, { principal });
消费者核查:
import crypto from 'node:crypto';
function verify(payload, signature, secret) {
const expected = Buffer.from(crypto.createHmac('sha256', secret).update(payload).digest('hex'));
const actual = Buffer.from(signature);
return expected.length === actual.length && crypto.timingSafeEqual(expected, actual);
}
重试策略
- 第2条 已交付
- 408 / 429 / 5xx / 网络故障 + 重试,使用有边界的指数回放
- 3⁄4 ̄ ̧漯b → 失败( 最终) : 从未遵循过方向
- 其他 4xx (中文(简体) ) 失败( 最终)
- 拒绝授权 — 失败; 提供者从未被调用
- AuthBundry 不可用/ 超时 ——以后再审;提供者从不叫
- 最大尝试 − 5 (可配置)
无法执行可手动重放 :
await service.replayWebhookDelivery(tenantId, deliveryId, principal); // webhooks.replay
禁用端点
await service.disableWebhookEndpoint({ id: endpoint.id }, principal); // webhooks.remove
// No new deliveries created; existing pending deliveries blocked
网络呼号是 至少一次交货消费者应当治疗 eventId 编号 : deliveryId 作为一能识别符.
我该怎么用耐用的工作?
工作提供可靠的背景任务执行,提供再试支助,通过租赁进行货币控制,以及从工人倒闭中自动恢复.
设置
import { createServices } from '@appport/services';
const services = createServices({ path: './.appport', application: 'invoices', authorizer: authBoundry });
const service = services.jobs;
登记处理器
service.register('invoice.process', async (job, execution) => {
const { invoiceId } = job.payload as { invoiceId: string };
// The job runs as its durable principal; every effect is authorized again.
await services.invoke('notifications.send', { recipient: 'finance', type: 'invoice.processed', title: invoiceId }, { principal: execution.principal });
});
选中任务
const job = await service.enqueue({
type: 'invoice.process',
payload: { invoiceId: 'inv-456' },
maxAttempts: 3,
delegationId: 'del_quote_agent', // optional AuthBoundry delegation, checked on every run
}, principal);
没有永久校长的工作从未被执行,被撤销的代表团 停止下一个运行。 见 医生/。 。 。 .
执行工作(工人)
const result = await service.executeJob(tenantId, jobId, 'worker-1');
if (result) {
// Job completed successfully
}
经常性工作时间表
const schedule = await service.scheduleRecurring({
type: 'invoice.reconcile',
payload: { batchSize: 100 },
interval: '1h',
}, principal);
重试策略
- 成绩 工作标志完成
- 失败 + 用指数反转重试(2^ attremptCount)
- 最大尝试超过 工作标记失败
- 工人租赁期满 • 有资格由另一名工人恢复的工作
- 手动重试 将失败的工作重置为待决状态
工作是 持久和专有. 工作状态在重新启动过程中幸存下来;工人通过基于版本的乐观锁定要求工作.
我怎么发通知?
通知是指通过一个或多个送货渠道传递的持久应用事件. 申请决定发生了什么。 AppPort Services决定如何交付持久通知.
Application = meaning
AppPort Services = delivery infrastructure
FeltDB = durable state and evidence
Attn = attention and judgment
const { notification, deliveries } = await app.notifications.notify({
tenantId: 'tenant-a',
recipient: 'user-1',
type: 'monitor.triggered',
title: 'Status changed',
source: { type: 'monitor', id: 'monitor-7', eventId: 'observation-123' },
channels: ['browser', 'in-app'],
}, principal);
await app.notifications.markRead('tenant-a', notification.id, recipientPrincipal);
await app.notifications.acknowledge('tenant-a', notification.id, recipientPrincipal);
- 每个频道都有自己的持久交付记录(
pending, (中文(简体) ),delivered, (中文(简体) ),failed, (中文(简体) ),retrying) (中文(简体) ). - 重复相同的源事件返回相同的通知.
- 现有就业基础设施的回收工作.
expiresAt停止过时的交货,但保留记录作为证据.- 证书(密码、饼干、授权信头、信使、API密钥、私人密钥)被拒绝.
- 关闭浏览器不会销毁通知 。 浏览器是一个传送通道,一个新的
会话追赶从
GET /notifications?unread=true。 。 。 .
电子邮件、移动推取、短信和网络呼取频道是注册在 registerChannel()。 。 。 .
见 文件/通知.md 用于资源模型、生命周期、HTTP API、,
和敏感数据边界.
耐久状态住在哪里?
Apport 服务公司通过主机直接在 FeltDB 收藏中存储所有状态 @feltdb/core (0.16.1或后为0.x).
feltdb.flow (generated Flow contract)
│
▼
AppPort Services
│
├─→ FeltDbApiKeyStore (ApiKeys, ApiKeyPrefixes, ApiKeyAuditEvents)
├─→ FeltDbWebhookEndpointStore (WebhookEndpoints, WebhookAuditEvents)
├─→ FeltDbWebhookDeliveryStore (WebhookDeliveries)
├─→ FeltDbJobStore (Jobs, JobSchedules, JobAuditEvents)
└─→ Secrets protocol (Secrets, SecretVersions, SecretAuditEvents)
│
▼
@feltdb/core (the host's copy)
│
▼
real FeltDB
秘密怎么办?
对于 AppPort Secrets,边界为:
application .flow → capability contract → AuthBoundry authorization → secret provider
申请书 secrets ,但从不将暗中值输入 .flowAppPort只公布身份、生命周期、租户、审计和提供商参考元数据; AppBoundry 提供商在AuthBoundry授权后执行.
AppPort是宣告性的:它定义了"秘密能力"的含义. AppBoundry决定如何运行,AuthBoundry决定谁可以使用. 保密合同没有规定提供商、储存、缓存、注射或授权执行.
- 以密码随机性生成
- 创建时返回一次
- 持续前用碎屑
- 从未存储在耐用 API- key 记录
- 不包括在审计记录中
仓库布局
appport.flow——用于生成消费者的内部包模板feltdb.flow合同/src/api-keys——API-键型和语义服务/src/authority- 政策执行点:能力表、经核实的主要负责人、执行背景、AuthBoundry协议、目的地政策、效果证据/src/webhooks- Webhook 模型、服务和签名助手models.ts- 终点、交货、活动合同service.ts- Webhook生命周期和交付协调secrets.ts- 秘密生成、加密、HMAC签名
/src/jobs- 工作模式、服务和执行models.ts- 工作和时间表合同service.ts工作周期、重试和时间安排store.ts——FeltDB后置存储并乐观地锁定worker.ts- 与投票同时执行工作
/src/storage— FeltDB 支持的存储和审计槽api-keys.tsAPI 密钥存储webhooks.ts— Webhook 端点/交付存储
/src/runtime——HTTP/Express认证适配器和取出 Bearer-tokenapi-keys.ts——取出持证人证http-adapter.ts- 框架中立的HTTP适配器express-middleware.ts——快递中件
/src/contract- AuthPort主要合同/tests——节点/脚本测试contract.test.ts——流量DSL验证和收集验证api-keys.test.ts- 核心服务测试http-adapter.test.ts- HTTP适配器测试(安全、隔离、租户安全)integration-app.test.ts真正的 HTTP 应用程序固定express-integration.test.ts——快递中件集成测试webhooks.test.ts- Webhook 生命周期和耐用性测试webhooks-delivery.test.ts- HTTP的交付、签字、重试和货币测试jobs.test.ts工作周期、时间安排和耐久性测试jobs-execution.test.ts- 同时执行、租赁和回收测试
/docs——建筑说明