@north-light/plugin

中文文档
0.3.573发布于 2026/11/02UNLICENSEDTypeScriptES Module

crouter

中文使用文档
文档目录8 节
  1. 安装
  2. 定义一个插件
  3. 安装到crtr中
  4. 作为在目录中注册的应用程序
  5. 计量提供商工具
  6. 参考
  7. 相关
  8. 许可证

@ northlight /plugin -在TypeScript中定义一次crtr命令,并通过HTTP提供它们

crouter

npm

@north-light/plugin 控件中添加命令 crtr 对运行它的每个代理也是如此。您编写一个键入的命令树。包将其转换为一个Fetch处理程序 commands.json 清单,然后存档 crtr pkg plugin install --endpoint 读取。您不需要编写清单、路由表或 plugin.json.

它是一个服务器端创作工具包,而不是运行时:处理程序是一个标准的Fetch { fetch } 您部署在任何提供导出的主机上的默认导出。它不运行代理;代理调用您的命令的方式与调用其他命令的方式相同 crtr 命令, crtr 向端点发出HTTP请求。不需要服务器的插件,比如本地可执行文件,可以从市场安装;看到 插件文档.

文档 · 命令 · 部署 · 官方市场 · 克劳特库

安装

npm install @north-light/plugin

该软件包仅支持esm。从ES模块导入它或使用动态 import() CommonJS。要尝试插件,您还需要 crtr CLI: npm install -g @north-light/cli,然后跑 crtr 一次登录到模型提供程序。

定义一个插件

创建 src/crtr-plugin.ts:

import {
  createFetchHandler,
  defineBranch,
  defineLeaf,
  definePlugin,
  field,
  LeafError,
  param,
} from '@north-light/plugin';

export const plugin = definePlugin({
  name: 'acme',
  description: 'Manage Acme applications.',
  whenToUse: 'you need to create or inspect an Acme application.',
  summary: 'Acme application management',
  rootEntry: {
    concept: 'an Acme application',
    description: 'Create and inspect applications.',
    whenToUse: 'the task is about an Acme application.',
  },
  commands: {
    app: defineBranch({
      description: 'Create and inspect applications.',
      whenToUse: 'you are working with an application.',
      summary: 'application operations',
      children: {
        create: defineLeaf({
          description: 'Create an Acme application.',
          whenToUse: 'an application does not exist yet.',
          summary: 'create an application',
          params: {
            name: param.positional('The application name.', { required: true }),
            region: param.enum(['us-east', 'eu-west'], 'The region for the application.', { default: 'us-east' }),
          },
          output: {
            appId: field.string('The created application id.'),
            url: field.string('The application URL.'),
          },
          effects: ['Creates an Acme application.'],
          handler(input) {
            if (input.name === 'taken') {
              throw new LeafError({
                code: 'name_taken',
                message: 'That application name is already in use.',
                status: 409,
                field: 'name',
              });
            }
            return {
              appId: `app_${input.name}`,
              url: `https://${input.name}.${input.region ?? 'us-east'}.acme.example.com`,
            };
          },
        }),
      },
    }),
  },
});

export default {
  fetch: createFetchHandler(plugin, { token: process.env.ACME_CRTR_TOKEN }),
};

处理程序输入是从 params: name 是必需的 region 是可选的。在crtr到达的URL上部署默认导出。相同的URL句柄 GET 存档请求和 POST 命令请求。

安装到crtr中

在运行crtr的机器上设置相同的承载令牌,然后安装处理程序的实际挂载路径:

export ACME_CRTR_TOKEN='replace-with-a-secret'
crtr pkg plugin install --endpoint https://acme.example.com/crtr --name acme --auth-env ACME_CRTR_TOKEN
crtr acme app create my-app --region eu-west

export 涵盖您自己键入的命令。代理的 crtr acme … 在它的代理中运行,其env来自配置文件env存储,而不是来自您的shell -所以对于代理,也将令牌存储在那里: echo -n "$ACME_CRTR_TOKEN" | crtr profile env set <profile> --name ACME_CRTR_TOKEN. 从那时起,在该配置文件下启动的节点携带它。

使用中的实际挂载路径 --endpoint. 生成的归档文件在该路径下声明命令路径,而crtr存储以后命令调用的源文件。只安装 https://acme.example.com 会发送呼叫到原始根而不是 /crtr.

作为在目录中注册的应用程序

向连接它的人提供命令的应用程序通过目录身份验证,而不是静态令牌:

import { createFetchHandler, createNodeHandler } from '@north-light/plugin';

const handler = createFetchHandler(plugin, {
  auth: { issuer: 'https://directory.example', audience: 'https://acme.example.com/crtr', providerId: CLIENT_ID },
  requests,
});

providerId 是应用程序的客户端id(它的OAuth客户端id),裸或作为 app:<id>. 目录将范围划分为 <provider id>:<group>,所以工具包要求 <providerId>:<group> 在每一片叶子上。没有 providerId 它需要 <plugin name>:<group>只有名字等于其id的第一方提供商才会携带这个号码——来自任何其他应用程序的每个呼叫都会回答403 scope_missing,以及误差 next 命名要设置的id。

声明应用的工具组在它的叶子旁边 definePlugin({ provider: true, version, groups }). groups 由组id作为关键字;每个值都有 consentLine 和(可选) who (own, user, allowlist, any, team:<id>;省略手段 user), allowlist (app:<id> 校长,只与 who: 'allowlist'). 每一片叶子的 group 必须为声明的组命名,并且每个声明的组都必须由叶子使用,或者 definePlugin 抛出。的服务 bundle.json 将其作为 "groups": {"<id>": {"consent_line": "...", "who"?: "...", "allowlist"?: [...]}} 目录在刷新提供商的清单时应用它。请参阅文档中的命令。

在Node、Express或Nest上,用 createNodeHandler(handler, { bodyLimit?, origin? }). 它将请求转换为Fetch Request (使用 req.rawBody 当框架对其进行缓冲时(否则流),将拒绝body over bodyLimit (默认65536字节)与413处理程序运行之前,流响应与重复的头和 set-cookie,如果处理程序抛出,则回答500。在Nest中,控制器方法是 @All(['', '*path']) serve(@Req() req, @Res() res) { return node(req, res); };与 node:http, createServer((req, res) => void node(req, res))。通过 origin 当公共源与Host头不同时。

计量提供商工具

使用目录身份验证,配置 createFetchHandler(plugin, { auth, receipts: { provider: 'app:acme', outbox } }). provider 必须是提供者的身份验证 app:<id> Principal,而不是插件名。发出收据 tool 值,以及 tool 那 ctx.checkSpend() 发送,是命令路径 后 插件名称: send 用于 crtr acme send,或者 messages send 用于 crtr acme messages send. 处理程序调用 ctx.meter({ units, unit }) 发出 Crtr-Receipt;提供者持久化并将相同的收据提交到目录分类账。 ctx.meter 可以分别叫一次吗 unit 在调用中(重复单元抛出);通过 receiptId 为收据命名(默认是请求id,调用中的每个收据都需要自己的id)。一张收据进来了 Crtr-Receipt 作为一个对象,几个作为一个JSON数组,收据在一个 LeafError 利用错误响应。

该工具包没有价格:目录拥有每一个价格,最高限额和津贴(设置在控制台或与 crtr cloud apps provider pricing),并从收据中收取费用 units 或者它的报告成本。 ctx.meter 设置收据 usd_equivalent 致第一个 usdEquivalent 你通过了(一个报告其成本的工具通过了它); units 这个请求的价格行 ctx.checkSpend() 回答的 unit 火柴,用于单价工具;否则 0. 它永远不会因为丢失的价格而抛出。这个数字是运行时显示的调用成本;目录自己重新计算费用,并且从不信任它。 ReceiptOptions.rates 不再存在:当你升级时删除它(TypeScript标记它;JavaScript配置中仍然通过它会被忽略)。

ctx.causedBy 是 request:<this request's Crtr-Request-Id> (当请求不携带时不存在)。调用运行时的处理程序本身会传递它,因此这些调用的花费被跟踪到这个调用: new Crouter({ causedBy: ctx.causedBy }),或者 causedBy 在 runs.start.

ctx.caller.payer 这通电话是收费的吗? user:<id> 或者 app:<id>:代币 payer 要求,或 sub 当令牌没有时。 ctx.meter 在收据上盖章。在收费电话之前, await ctx.checkSpend() 询问目录(POST <auth.issuer>/v1/billing/check(发送请求的出站令牌)付款人是否可以在此命令上花费(它发布) { token, tool }, tool 作为上面的命令路径),并保留它所应答的价格行 ctx.meter;它不保留任何东西,用它来解决 { prices } (每一行组的价格, [price] 当目录应答时 price(未定价时为空)。它需要 receipts.ledger: { clientId, privateKey, keyId? }和你传递的证书一样 postReceipt,并抛出一个平原 Error 没有他们或没有经过验证的来电者。它解决了调用何时可以继续,抛出 SpendRefusedError { code, message, next } 拒绝(payment_required 或者 limit_reached, next 修复它的页面),并抛出 ReceiptPostError 当支票无法完成时。要拒绝调用,请将其重新抛出为 new LeafError({ code: e.code, message: e.message, status: 402, next: e.next }).

回答一个速率限制,扔一个 LeafError 与 retryAfter (秒,或一 Date): throw new LeafError({ code: 'rate_limited', status: 429, message: 'Slow down.', retryAfter: 30 }) 回答429 Retry-After: 30. headers: { 'X-RateLimit-Reset': '…' } 设置任何其他响应头; Content-Type, Content-Length, Content-Encoding, Transfer-Encoding 和 Crtr-Receipt 属于工具箱。对于副作用叶,套件将头传递给 requests.store 作为 answer.headers (小写的名字);存储并返回它们的存储将使用相同的标头重复请求回答。

对于副作用的叶子,提供 requests: { record, read, store, delete }. record(requestId, identity) 自动插入id和 {sub, grantee} 来自已验证的调用方(或 null 对于遗留的static-token插件); read(requestId) 返回 {identity, recordedAt, answer}. 该工具拒绝来自不同调用者的重复id,而不是重播另一个人的结果。 store 用发件箱以事务方式保存结果和收据。 answer.receipt 是来电的第一个收条,一如既往;当一个电话超过一个时, answer.receipts 还列出了所有这些(首先包括)和商店必须保存和返回它 read (重播重建 Crtr-Receipt 从 receipts 在场时,否则 receipt). 未记录的请求将每个收据保存为自己的收据 outbox.save 呼叫。 onError 得到 (error, path, receipt, receipts?) 和 onAnswer 得到 receiptIds 在同样的规则下。对于提供者日志记录, onAnswer(event) 每个应答的叶子POST接收一个仅元数据事件(主链字段、请求/运行id、相对工具、状态、持续时间、接收id、重放标志);它从不接收承载令牌、参数或结果体,日志记录失败也不会改变答案。 createCallerVerifier(auth) 为在Fetch处理程序之外验证请求的提供程序导出。

参考

这个 插件指导 涵盖了 命令, 参数, 输出, 错误和流, 部署, 捆包和文档.

许可证

专有的。版权所有2026 Northlight Systems版权所有。看到 LICENSE.

版本与发布记录

@north-light/plugin 共发布 155 个版本,首次发布于 2026/10/10;过去 12 个月发布了 155 个版本。

版本发布日期距今
0.3.573latest2026/11/021 天前
0.3.5722026/11/021 天前
0.3.5712026/11/021 天前
0.3.5702026/11/021 天前
0.3.5692026/11/012 天前
0.3.5682026/11/012 天前

关于 @north-light/plugin 的常见问题

如何安装 @north-light/plugin?

在项目目录运行 npm install @north-light/plugin,或使用 pnpm add / yarn add / bun add。

@north-light/plugin 支持 TypeScript 吗?

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

@north-light/plugin 支持 ESM 还是 CommonJS?

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

@north-light/plugin 可以商用吗?

@north-light/plugin 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@north-light/plugin 还在维护吗?

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