@appport/core

中文文档
1.7.0发布于 2026/11/06Apache-2.0TypeScriptES Module近 30 天下载 2605

AppPort 能力运行时间:注册,调度,事件,流,会话.

中文使用文档
文档目录6 节
  1. 输油管
  2. 运行时间提供
  3. 同上(第13.1节)
  4. 申请登记(PR20)
  5. 供应商生命周期和移交
  6. 警械能力(1.3.0)

@ appport/ 核心

能力运行时间:登记、发送管道、审定、会话、, 事件、溪流、操作和遥测.

Core对HTTP,WebSocket,IPC或任何存储引擎一无所知.

import { createApplication, defineCapability, defineEvent } from "@appport/core";
import { s } from "@appport/schema";

const application = createApplication({
  application: { id: "com.example.docs", name: "Docs", version: "1.0.0" },
  capabilities: [documentsSave],
  events: [documentsChanged],
  authorizer: permissionAuthorizer()
});

const response = await application.handleRequest(envelope, { session, transport: "http" });

输油管

receive -> validate -> authorize -> execute -> serialize -> respond

授权总是先于特权逻辑。 输入在 授权,所以政策会看到完善的输入. 输出也经过验证,所以 操作者不能无声地打破其公布的合同.

运行时间提供

  • 书记官处和清单 - 申请合同,作为JSON Schema提交.
  • 申请登记 确定申请、核实申请和登记申请 有身份、身份、指纹和核查状态的持久追踪.
  • 活动 ——最多一次发布,并附有有效载荷验证.
  • 流线 - 同步移动或 context.createStream(),取消.
  • 会议 ——运输中性,可插件存储.
  • 目 录 - 重新播放对宣布支助能力的回应,包括 处理者运行前编写的持久在建工程索赔(见下文).
  • 货币 —— 说 parallel, (中文(简体) ), serialized,或 keyed(field)。 。 。 .
  • 超时 ——每个能力和每个请求,被服务器夹住.
  • 业务 —— 说 operations.status, (中文(简体) ), operations.cancel, (中文(简体) ), operations.events 工作超过要求.
  • 遥测 识别特征和结果,从不合格或有效载荷.
  • 卫生 生产错误没有堆放痕迹、路径或秘密.

保留 appport.manifest 财务报告和审定财务报表 appport.ping 能力已登记 自动的,因此发现在没有URL的传输上同样有效.

同上(第13.1节)

能力 idempotency: "supported",请求附有 idempotencyKey 实值 由呼叫者负责(会议,或 principal:<id>并受其请求摘要的约束.

  1. 说法. 处理器运行前,运行时间会写一个 IdempotencyClaim (单位:千美元)key, (中文(简体) ), requestId, (中文(简体) ), requestDigest范围, claimedAt, (中文(简体) ), expiresAt, (中文(简体) ), status: "in-progress"与 store.claim()原子创造,如果没有.
  2. 记录. 关于成功,它写道 IdempotencyRecord 与 store.set(),哪个 替换索赔。 同声回放得到存储的响应.
  3. 已知失败. 当处理者投掷(或从未启动)时,索赔要求是 与 store.release() 并进行重试,不记录失败, 和以前一样.
  4. 未知结果. 在处理器运行时超时或取消时, 失败 返回后(输出验证,状态承诺)或无法保存的记录 写着, 索赔保留下来。 重放则失败 CONFLICT, (中文(简体) ), details.reason: "IDEMPOTENCY_OUTCOME_UNKNOWN" (单位:千美元)IdempotencyOutcomeUnknownError, (中文(简体) ), 与原样 requestId),处理者是 没有 再来一次 一样 答案跟随效果和记录之间的进程崩溃,条件是 商店是耐用的。 索赔持续到 expiresAt (24小时)或直至操作员 决定store.set(record) 或者说 store.release({ key, requestId })· ; store.findByRequestId(requestId) 发现它.

一项索赔或记录之下的不同请求是: CONFLICT 编号 : IDEMPOTENCY_KEY_REUSED. 发送到一个能力而无一能支持的密钥 在开发过程中被拒绝INVALID_REQUEST 编号 : IDEMPOTENCY_KEY_UNSUPPORTED和 生产中每个容量版本记录一次;设定 unsupportedIdempotencyKey: "reject" | "warn" 选择.

库存合同. get 财务报告和审定财务报表 set 需要这样做. claim 财务报告和审定财务报表 release 可选 联合起来(只有一家商店申请被拒绝)。 商店没有 保存1.4前的保证:重复在一个过程中被复制 只有,在效果和记录之间发生相撞,可以再次重放执行. findByRequestId 是可选的,只供运算符使用. MemoryIdempotencyStore 全部执行; 持久存储属于应用程序并可被检查 与 runIdempotencyStoreConformance 从 @appport/testing。 。 。 .

申请登记(PR20)

定义、核实和登记持久跟踪的应用程序:

import { defineApplication, ApplicationRegistry, MemoryApplicationStateStore } from "@appport/core";

// 1. Define an application (PR18)
const application = defineApplication({
  identity: { id: "invoicing", name: "Invoicing", version: "1.0.0" },
  provides: [invoiceCreate, invoiceSend],
  requires: [{ name: "payments.charge", version: 1 }],
  implementations: { "invoice.create@1": createImpl, "invoice.send@1": sendImpl }
});

// 2. Verify the application (PR19)
const verification = application.verify();
if (!verification.ready) throw new Error("Application verification failed");

// 3. Get the canonical manifest and fingerprint (PR19)
const manifest = application.manifest();
const fingerprint = application.fingerprint();

// 4. Register for durable tracking (PR20)
const store = new MemoryApplicationStateStore();
const registry = new ApplicationRegistry(store);

const registered = await registry.register({
  identity: application.identity,
  manifest,
  fingerprint,
  verification
});

// Tracked application state with identity, manifest, fingerprint, verification
console.log(registered.id, registered.status, registered.revision);

注册的申请状态是可移植的,没有执行 细节——只有合同、身份、核查状态和生命周期.

供应商生命周期和移交

分辨率遵循提供者生命周期状态。 在符合要求的供应商中 active (促进) 一个排除那些只是 registered,所以一个准备好的替代 永远不会取代或模糊提供者 服务中。 没有主动提供者,注册提供者将一如既往地解决;两个主动提供者含糊不清;已退休 供应商从来不是候选人,即使被身份证明所左右.

为了取代一个提供者,用自己的身份和赠款来准备替换,然后在原子的一个步骤中交出:

import { ApplicationLifecycleOperations, ApplicationRegistryLifecycleGateway, MemoryApplicationLifecycleStore } from "@appport/core";

const lifecycle = new ApplicationLifecycleOperations(
  new MemoryApplicationLifecycleStore(),
  new ApplicationRegistryLifecycleGateway(registry, verifyReplacement) // validation and promotion checks
);

await lifecycle.define(replacement.manifest());
await lifecycle.validate("payments.v2");   // verifyReplacement runs here
await lifecycle.register("payments.v2");   // registered: does not compete with the active provider
await grants.grant({ consumerId: "shop", providerId: "payments.v2", capabilityName: "payments.charge", capabilityVersion: 1 });

const { handover } = await lifecycle.handover("payments.v1", "payments.v2", {
  capability: { name: "payments.charge", version: 1 },
  authorization: grants // every consumer granted payments.v1 must hold its own grant for payments.v2
});
// payments.v1 is retired and payments.v2 active, in one conditional store write.

ApplicationRegistry.handover() 是下面的原始注册: 它检查两个注册是预期的 在预期的州,如果有同样的能力合同,则一个退休,另一个通过 存储可选 replaceIfCurrent (由 MemoryApplicationStateStore;没有它的商店被拒绝 atomic-store-unsupported) (中文(简体) ). 每一次拒绝都是 ProviderHandoverRejected 带有 reason 改变什么.

在执行之前,包括何时,拒绝援引对前提供方发出的约束力 交接土地经过约束权限检查。 已经交给前供应商的工作在那里完成 移交不会排出或取消。 保证和限制: docs/architecture/provider-handover.md。 。 。 .

警械能力(1.3.0)

企业能力可以具有自己的特性:a 警犬合同,独立发布,不管是否有任何东西执行 这个 申请以自己的名义予以执行 索赔 * 对警犬能力的要求只能解决 通过一项索赔,该索赔被评为: valid规格: spec/fulfillment-1.md 在仓库.

import { CanonicalContractRegistry, ApplicationDependencyResolver, CapabilityBinder, defineCapability, resolvedDependency } from "@appport/core";
import { claimFor } from "@appport/protocol";

const contracts = new CanonicalContractRegistry();
await contracts.register(ordersContract);          // a manifest advertising appport.canonical-contract/1, serving no transport
await contracts.activate("org.example.orders");

// A provider implements order.hold@1 under its own name, and claims it (the claim pins the canonical revision by digest).
const hold = defineCapability({ name: "oms.hold", version: 1, authorization: ["orders.hold"], fulfills: [claimFor(ordersContract, "order.hold", 1)], /* … */ });

const resolver = new ApplicationDependencyResolver(registry, { contracts, authorityDecisions });
const candidates = await resolver.discoverCanonical({ contract: "org.example.orders", capability: "order.hold", versionConstraint: "^1" });
const result = await resolver.resolveRequirement({ name: "order.hold", version: 1, versionConstraint: "^1", canonical: { contract: "org.example.orders" } });
if (result.kind === "resolved") {
  result.capability.name;                         // "oms.hold": invocation targets the provider's own capability
  resolvedDependency(result);                     // lock-ready: contract revision and digests, provider registration, claim outcome
  await binder.bindResolution(consumer, result);  // authorizes oms.hold; result.canonical travels beside it
}
  • 合同对供应商. 合同存在于 CanonicalContractRegistry,从来没有在 ApplicationRegistry: 可以发现 但从未解决、约束或援引。 供应商的能力是运行.
  • 对索赔进行评价,不可信. discoverCanonical 根据合同的当前修订对每一项索赔进行估价 evaluateFulfillment。仅限 valid 索赔符合条件; unverified, (中文(简体) ), stale 财务报告和审定财务报表 invalid 他们的发现被退回 A 类 从犬科许可到提供者许可的绘图只有在提供者强制执行犬科许可本身或 明确 AuthorityEquivalence 裁决予以确立.
  • 没有名字匹配 . 犬科的要求永远无法解决 能力,因为它有 相同的名称, 犬科和只命名 声明从不满足对方。 报告两个符合条件的供应商为: ambiguous。 。 。 .
  • 三个身份. 能力身份(合同、能力、主要版本、摘要)、供应商身份(申请、登记、, 指纹、自身能力)和授权是分开的。 一项索赔没有给予赔偿:有约束力的政策认为 供应商 能力(capabilityName, (中文(简体) ), capabilityVersion)),赠款必须注明姓名,并注明在 context.canonical。 。 。 .
  • 装订出的证据. 犬科约束要求所附的解决者提供证据(result.canonical合同编号、修订和 contractDigest,犬类 capabilityDigest、供应商登记和指纹、索赔及其 valid 状况,以及所需 和强制许可。 失踪、伪造或不匹配的证据被拒绝(provider_not_authorized) (中文(简体) ).
  • 什么使约束无效. 任何新的合同修订(不同) contractDigest,即使所声称的能力保持不变)a 退休合同,或重新登记或退休的提供者。 在执行之前,在援引围栏上拒绝接受约束; 决心再次评估目前的修订.

限制: 权威等同决定提供给解决者,而不是存储,因此,约束在改变时不会重新确认 同步取出栅栏是每个登记册实例.

版本与发布记录

@appport/core 共发布 13 个版本,首次发布于 2026/09/21;过去 12 个月发布了 13 个版本。

版本发布日期距今
1.7.0latest2026/11/062 天前
1.6.02026/11/052 天前
1.5.02026/11/034 天前
1.4.02026/10/2810 天前
1.3.12026/10/2217 天前
1.3.02026/10/1919 天前

关于 @appport/core 的常见问题

@appport/core 是什么?

AppPort 能力运行时间:注册,调度,事件,流,会话.

如何安装 @appport/core?

在项目目录运行 npm install @appport/core,或使用 pnpm add / yarn add / bun add。

@appport/core 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@appport/core 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@appport/core 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@appport/core 可以商用吗?

@appport/core 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@appport/core 的下载量有多少?

根据 npm 官方下载统计,@appport/core 在 2026/10/07 – 2026/11/05 这 30 天内被下载 2,605 次,日均约 87 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@appport/core 还在维护吗?

最新版本 1.7.0 发布于 2026/11/06(2 天前);至今共发布 13 个版本,其中过去 12 个月发布了 13 个;首次发布于 2026/09/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。