@columenlabs/lumen-ops

中文文档
0.1.219发布于 2026/11/09MITTypeScriptES Module近 30 天下载 4.3万

Lumen的操作部分:每个请求,事件,数据查询和工具调用一个应用程序作为一个分析引擎点(只有模板,代码,形状和散列)运行,并签名出网.

中文使用文档
文档目录11 节
  1. 安装
  2. 设置
  3. 说得有道理
  4. 出口
  5. 请求
  6. 约束和外出电话
  7. 活动
  8. 浏览器遥测
  9. 工具调用
  10. 网络呼出
  11. 版本数

@columenlabs/ lumen- ops

Lumen的"Cloudflare Workers"的操作部分:每个请求的应用程序回答,每个事件和每个数据查询都成为一个分析引擎点,这样你就可以发现出错,错配以及慢或重的查询并修正. 计数器将你的装订包了一次,所以新的代码是不选择加入的。 它只写每个查询的形状,从来不是值. 它也是仪表工具调用( I)/tools)并发送签名的webhoks(/webhooks) (中文(简体) ).

安装

bun add @columenlabs/lumen-ops

把它固定在与你其他的鲁门软件包相同的准确版本上. 用这个 AsyncLocalStorage,所以工人们需要 nodejs_compat 旗帜.

设置

将分析引擎数据集装入 wrangler.jsonc数字 :

"analytics_engine_datasets": [{ "binding": "QUERIES", "dataset": "myapp_queries" }]

将包好的装订件 交给您的应用程序:

import { foldRoute, meteredClickHouse, meteredD1, setQueryCallerOf, setQuerySink } from '@columenlabs/lumen-ops';

setQuerySink(env.QUERIES);
// Name the request in scope: the app (or part of it), the route, and the tool when an MCP call runs.
setQueryCallerOf(() => {
  const req = currentRequest(); // your own request scope
  return req && { app: 'myapp', kind: 'fetch', route: foldRoute(new URL(req.url).pathname) };
});
const db = meteredD1(env.DB);
const clickhouse = meteredClickHouse(env.CLICKHOUSE); // any ClickHouse HTTP service binding

在永久对象中,测量其SQLite:

import { meteredSql } from '@columenlabs/lumen-ops';

const sql = meteredSql(state.storage.sql, { app: 'myapp', kind: 'do', route: 'Person' });

运行、排队或提醒名本身

import { withQueryCaller } from '@columenlabs/lumen-ops';

await withQueryCaller({ app: 'myapp', kind: 'cron', route: 'nightly-rollup' }, () => rollup(env));

另一个引擎(R2 SQL,一个HTTP数据库)调用 meterQuery({ engine, sql, method, ok, ms, ... }) 从它的一个客户端.

说得有道理

每回合发言一次1分:同一语句多次运行一次(插入圈)是总数的一分 statements 说多少跑。 以平分为正. 列单是读取数据集的合约:

栏持有
index1引擎 : d1, (中文(简体) ), clickhouse, (中文(简体) ), do_sqlite, (中文(简体) ), r2_sql 或属于自己的
blob1 . blob5发动机、应用程序、种类(fetch, (中文(简体) ), cron, (中文(简体) ), queue, (中文(简体) ), alarm, (中文(简体) ), do页:1 :id),工具
blob6 . blob8操作( O)select, (中文(简体) ), insert, (中文(简体) ), update, (中文(简体) ), delete, (中文(简体) ), ddl, (中文(简体) ), pragma, (中文(简体) ), other),指纹,查询的形状(最多 1 KB)
blob9, (中文(简体) ), blob10ok 或者说 error方法(all, (中文(简体) ), first, (中文(简体) ), run, (中文(简体) ), raw, (中文(简体) ), batch, (中文(简体) ), query, (中文(简体) ), insert, (中文(简体) ), exec(中文(简体) )
double1 . double10壁 ms,引擎本身的 ms,行读取,字节读取,行回取,行写取,回取字节(每个共取),HTTP状态,语句,最慢 ms

形状有每个字符串和数字字面 ?, (中文(简体) ), IN 已折叠到 (?...),评论和点击之家 FORMAT 掉下去,插入的一行被切断。 指纹是形状的散列, 一种查询.

以分析引擎SQL API为例

SELECT blob7 AS fingerprint, any(blob8) AS shape,
       sum(IF(double9 > 0, double9, 1) * _sample_interval) AS calls,
       sum(double1 * _sample_interval) / sum(IF(double9 > 0, double9, 1) * _sample_interval) AS mean_ms,
       max(double10) AS slowest_ms
FROM myapp_queries
WHERE timestamp > NOW() - INTERVAL '1' DAY
GROUP BY fingerprint ORDER BY mean_ms DESC LIMIT 20

出口

导出它会做什么
setQuerySink(binding)数据集每个点; 在设定之前什么都不是写入的
setQueryCallerOf(fn)在没有任务时在范围中列出请求
withQueryCaller(caller, fn)充电内部的每个查询 fn 改为 caller
meteredD1(db)D1, 计量吸入器: prepare 财务报告和审定财务报表 batch,其中D1自己的行读取并写出并持续时间
meteredClickHouse(binding)一个 ClickHouse HTTP 服务绑定, 当答案被读取后调制: 墙上时间到最后一个字节, ClickHouse 自己的统计
meteredSql(sql, caller?)持久对象 storage.sql;其光标保持 toArray, (中文(简体) ), one, (中文(简体) ), raw, (中文(简体) ), next,重复和 columnNames
meterQuery(point)一分一分,对任何其他引擎
queryShape(sql)查询的形状、指纹和操作
foldRoute(path)有类似 id 的片段的路径 :id
setQueryRowCap(n)最多一行的语句应返回; 更多返回的语句应标记 capped 内 blob11

请求

@columenlabs/lumen-ops/hono meth 每一个请求一个Hono应用程序的答案:先挂载一次,然后该应用程序的每一个路由在后面写出一个有其路由模板,状态,结果代码和时间的点. 它将请求命名为范围,所以里面的事件和询问都带有它的ID.

import { requestId } from 'hono/request-id';
import { requestMeter } from '@columenlabs/lumen-ops/hono';
import { setRequestSink } from '@columenlabs/lumen-ops/requests';

app.use('*', async (c, next) => {
  setRequestSink(c.env.REQUESTS, { log: true }); // also one JSON line per point in Workers Logs
  await next();
});
app.use('*', requestId());
app.use('*', requestMeter({
  app: 'myapp',
  env: (c) => c.env.DEPLOY_ENV,
  describe: (c) => ({ surface: 'api', subject: c.get('accountId'), callerKind: 'key' }),
}));
栏持有
index1主体:应用程序给谁打电话的不透明标识,或 anon
blob1 . blob7App,表面,方法,路由模板,结果(ok,一个 error jSON的密码, exception, (中文(简体) ), http_<status>),呼叫者种类,呼叫者编号
blob8 . blob13区域, env, 版本, colo, 国家, 请求 id
double1 . double6状态, ms, 字节在, 字节在外, 上游 ms, 子请求

路径没有匹配的路由被写入为 *所以扫描仪的垃圾不会落地 没有贺野 就把处理器包起来 withRequest(scope, route, fn) 打电话 meterRequest(point) 你自己来.

约束和外出电话

在条目和补丁时包起嵌入器 fetch 一次,每个持久对象RPC方法,工人AI,矢量化,KV,R2,服务或VPC呼叫和每个出站 fetch 被定时并收费于请求的范围:

import { meterFetch, meteredBindings } from '@columenlabs/lumen-ops';
import { requestMeter } from '@columenlabs/lumen-ops/hono';

meterFetch();
app.use('*', requestMeter({ app: 'myapp', serverTiming: true }));
export default { fetch: (req, env, ctx) => app.fetch(req, meteredBindings(env, { kinds: { AI: 'ai', INDEX: 'vectorize' }, skip: ['METRICS'] }), ctx) };

呼叫按其约束性和方法命名(DIRECTORY.seen, (中文(简体) ), AI.run, (中文(简体) ), fetch.api.example.com),从不争论. 请求点 upstream ms 财务报告和审定财务报表 subrequests 添加; serverTiming: true 将拆分寄回 Server-Timing (单位:千美元)do, (中文(简体) ), ai, (中文(简体) ), fetch. . . . . . . , app, (中文(简体) ), total),当请求结束时,每个调用代码是一个 call 活动(code 电话, ref 同类的, ms 总计, 计数: 呼叫, 失败 。 在请求(警报)之外,每个电话都是自己的事件. app 可能是一种功能,而且 route 当一个工人通过路径向其他应用程序请求时,请指定路径.

活动

@columenlabs/lumen-ops/events 写一个应用程序所做的不是它回答的请求: 呼叫另一个服务, 网约车进出,同步的开始和结束, 登录。 以这些要求的要点,他们表明,是否已经采取行动.

import { meterEvent, setEventSink } from '@columenlabs/lumen-ops/events';

setEventSink(env.EVENTS);
meterEvent({ event: 'bank.call', code: '/accounts/get', ok: res.ok, ms, status: res.status, upstream: true });
meterEvent({ event: 'sync.done', ok: true, subject: accountId, ref: connectionId, counts: [added, modified, removed] });
栏持有
index1主题,或 anon
blob1 . blob10App,事件,代码,结果, ref,触发,请求id,上游id,env,版本
double1 . double6ms,状态,数一,数二,数三,尝试

upstream: true 在请求中增加通话时间 upstream ms在永久对象中,没有请求范围: setEventSink(binding, { app, env, version }) 默认,然后通过一个 requestId 如果你有电话就派来.

浏览器遥测

useLumenTelemetry 内 @columenlabs/lumen-ui 将打开的屏幕、 未发现的错误( 类和堆栈的散列, 永远不发送信件) 、 失败的请求和Web Vitals 分批发送到 /api/t工人检查并写道:

import { meterClientBatch, setClientSink } from '@columenlabs/lumen-ops/client';

setClientSink(env.CLIENT);
app.post('/api/t', async (c) => {
  meterClientBatch(await c.req.json().catch(() => null), { app: 'console', subject: c.get('accountId') });
  return c.body(null, 204);
});
栏持有
index1主题,或 anon
blob1 . blob9类App(view, (中文(简体) ), error, (中文(简体) ), fetch_fail, (中文(简体) ), vital),路由模板,名称,堆栈指纹,请求代号,版本,设备,env
double1, (中文(简体) ), double2数值(毫分或分数),状态

一批失败的 schema 被全部删除; 只有代码,模板和数字通过 .

工具调用

@columenlabs/lumen-ops/tools mm每个调用助手或代理制作:每调用1分,随时间,结果和所运行代码的散列,如此缓慢或失败的工具出现,相同的脚本被分组到各跑.

import { meteredCall, meterToolCall, setToolSink } from '@columenlabs/lumen-ops/tools';

setToolSink(env.TOOL_CALLS); // an Analytics Engine dataset binding

// Wrap a call: latency and outcome are taken for you.
const rows = await meteredCall({ app: 'trade', tool: 'portfolio_list', kind: 'call' }, () => run(args));

// Or write one by hand, with the code a script ran.
meterToolCall({ app: 'trade', tool: 'script', kind: 'script', ok: true, ms: 840, code: source, rows: 120 });
栏持有
index1应用
blob1.blob9应用、工具、种类、结果(ok 或者说 error),错误类型、代码散列、源、级、运行 id
double1.double6毫秒、行、字节、字节、符号、符号

争论和结果从不写;只写出其大小.

导出它会做什么
setToolSink(binding)数据集工具点进入; 在设定之前没有写入
meterToolCall(point)一分一分的手头
meteredCall(point, fn, errorKind?)运行 fn,定出时间并撰写结果
codeHash(code)一个简短的散列脚本, 白空间折叠

网络呼出

@columenlabs/lumen-ops/webhooks 发送一份快递,按 标准网络呼号 给定一个秘密时的 spec, 这样接收器就可以用任何标准的 Webhooks 库来验证它. 它从不扔出:结果说明它是如何走的,为的是应用自己的送货日志和回放.

import { newWebhookSecret, sendWebhook } from '@columenlabs/lumen-ops/webhooks';

const secret = newWebhookSecret(); // whsec_…, shown to its owner once, kept sealed
const r = await sendWebhook({
  url: endpoint.url,
  secret,
  id: event.id, // the same id on a retry
  body: JSON.stringify(event.payload),
  headers: { authorization: `Bearer ${endpoint.token}` },
  userAgent: 'MyApp-Webhooks/1',
});
if (!r.ok) scheduleRetry(event, r.status, r.error);
导出它会做什么
sendWebhook(send)一个POST: { ok, status, ms, id, error? }; 当结束点从未回复时, 状态 0
newWebhookSecret()一个新的 whsec_ 秘密, 32 个随机字节

端点的自有头先行,所以永远无法替换签名头. 重定向算作失败, 除非 redirect 否则, 超时为 10 s .

版本数

0.x:任何未成年人可以断裂到1.0. 每次和鲁门合并 main 发布每个 Lumen 软件包的下一个补丁;参见 释放。 。 。 .

版本与发布记录

@columenlabs/lumen-ops 共发布 187 个版本,首次发布于 2026/10/25;过去 12 个月发布了 187 个版本。

版本发布日期距今
0.1.219latest2026/11/091 天前
0.1.2182026/11/091 天前
0.1.2172026/11/091 天前
0.1.2162026/11/091 天前
0.1.2152026/11/091 天前
0.1.2142026/11/091 天前

关于 @columenlabs/lumen-ops 的常见问题

@columenlabs/lumen-ops 是什么?

Lumen的操作部分:每个请求,事件,数据查询和工具调用一个应用程序作为一个分析引擎点(只有模板,代码,形状和散列)运行,并签名出网.

如何安装 @columenlabs/lumen-ops?

在项目目录运行 npm install @columenlabs/lumen-ops,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:hono(>=4.8.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@columenlabs/lumen-ops 支持 TypeScript 吗?

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

@columenlabs/lumen-ops 支持 ESM 还是 CommonJS?

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

@columenlabs/lumen-ops 可以商用吗?

@columenlabs/lumen-ops 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@columenlabs/lumen-ops 的下载量有多少?

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

@columenlabs/lumen-ops 还在维护吗?

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