@triggerlink/sdk 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/function.d.ts +38 -0
- package/dist/index.d.ts +1 -1
- package/dist/serve.js +32 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,28 @@ client.register("http://localhost:3000/api/triggerlink"); // requires eventKey
|
|
|
57
57
|
|
|
58
58
|
Note: for local development, point the serve URL at `http://localhost:3000/api/triggerlink`; after changing functions in the app, call `POST /api/v1/apps/sync {"url":"..."}` to sync — no platform restart needed.
|
|
59
59
|
|
|
60
|
+
## Flow control (debounce / throttle / batch)
|
|
61
|
+
|
|
62
|
+
Three optional knobs on `createFunction`; durations accept a Go duration string (`"5m"`) or a millisecond number.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// Collapse a burst of edits into one run, keeping the last event
|
|
66
|
+
createFunction({ id: "index-doc", event: "doc/changed",
|
|
67
|
+
debounce: { period: "5m", key: "data.doc_id", timeout: "1h" } }, handler);
|
|
68
|
+
|
|
69
|
+
// At most 10 runs start per minute per tenant; over-limit runs are delayed, not dropped
|
|
70
|
+
createFunction({ id: "call-api", event: "api/call",
|
|
71
|
+
throttle: { limit: 10, period: "1m", key: "data.tenant" } }, handler);
|
|
72
|
+
|
|
73
|
+
// Trigger once per 100 events (or every 30s), receiving the whole batch
|
|
74
|
+
createFunction({ id: "bulk-index", event: "doc/changed",
|
|
75
|
+
batch: { maxSize: 100, timeout: "30s" } }, async (ctx) => {
|
|
76
|
+
for (const e of ctx.events ?? []) { /* arrival order; ctx.event is the first */ }
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`key` is an expr-lang expression over `data` that groups events into independent windows/quotas. Debounce and batch both act at the routing layer — configuring both makes debounce win. See the User Guide section 5.3.8 for the full semantics.
|
|
81
|
+
|
|
60
82
|
## Constraints (same as the Go SDK; see protocol section 6)
|
|
61
83
|
|
|
62
84
|
- Side effects must go inside `step.run`; the function is re-invoked from the start on every callback, so code outside steps runs repeatedly;
|
package/dist/function.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ export interface CancelOnRule {
|
|
|
18
18
|
/** 传给用户 handler 的上下文。 */
|
|
19
19
|
export interface HandlerContext<T = unknown> {
|
|
20
20
|
event: EventPayload<T>;
|
|
21
|
+
/**
|
|
22
|
+
* 批触发(FR-4.7,函数配了 batch)时给出整批事件,按到达顺序;此时 event 是其首条。
|
|
23
|
+
* 普通触发下不存在该字段。
|
|
24
|
+
*/
|
|
25
|
+
events?: EventPayload<T>[];
|
|
21
26
|
step: StepTool;
|
|
22
27
|
runId: string;
|
|
23
28
|
attempt: number;
|
|
@@ -30,6 +35,33 @@ export interface RunFailedEventData {
|
|
|
30
35
|
/** 触发该 run 的原始事件 */
|
|
31
36
|
event: EventPayload;
|
|
32
37
|
}
|
|
38
|
+
/** 防抖配置(FR-4.5)。时长可写 Go duration 字符串("5m")或毫秒数(300000)。 */
|
|
39
|
+
export interface DebounceOpts {
|
|
40
|
+
/** 合并窗口:窗口内每来一个新事件就把触发时间推后一个 period */
|
|
41
|
+
period: string | number;
|
|
42
|
+
/** 可选 expr 表达式(环境只含 data),按其求值结果分组;留空 = 整个函数共用一个窗口 */
|
|
43
|
+
key?: string;
|
|
44
|
+
/** 距首个事件的最长延迟,给持续刷新的窗口封顶;缺省 = 不封顶 */
|
|
45
|
+
timeout?: string | number;
|
|
46
|
+
}
|
|
47
|
+
/** 限流配置(FR-4.4)。超限的 run 不丢弃,延迟到下一窗口。 */
|
|
48
|
+
export interface ThrottleOpts {
|
|
49
|
+
/** 每个窗口内允许启动的 run 数 */
|
|
50
|
+
limit: number;
|
|
51
|
+
/** 窗口长度 */
|
|
52
|
+
period: string | number;
|
|
53
|
+
/** 可选 expr 表达式(环境只含 data),按其求值结果分组 */
|
|
54
|
+
key?: string;
|
|
55
|
+
}
|
|
56
|
+
/** 批处理配置(FR-4.7)。攒够 maxSize 或距首条超过 timeout 即以事件数组触发一个 run。 */
|
|
57
|
+
export interface BatchOpts {
|
|
58
|
+
/** 单批最大事件数,随 manifest 上报为 max_size */
|
|
59
|
+
maxSize: number;
|
|
60
|
+
/** 距首条事件的最长等待;攒不满时由它兜底 flush */
|
|
61
|
+
timeout: string | number;
|
|
62
|
+
/** 可选 expr 表达式(环境只含 data),按其求值结果分组 */
|
|
63
|
+
key?: string;
|
|
64
|
+
}
|
|
33
65
|
export interface FunctionOpts {
|
|
34
66
|
/** 稳定标识,改名会丢历史 memo 关联 */
|
|
35
67
|
id: string;
|
|
@@ -49,6 +81,12 @@ export interface FunctionOpts {
|
|
|
49
81
|
* 并发 triggerlink/run.failed 事件——配置了 onFailure 的函数会因此触发。缺省 = 不限时。
|
|
50
82
|
*/
|
|
51
83
|
timeout?: string | number;
|
|
84
|
+
/** 防抖(FR-4.5),随 manifest 上报为 debounce。与 batch 同为路由层流控,同时配置时以 debounce 为准 */
|
|
85
|
+
debounce?: DebounceOpts;
|
|
86
|
+
/** 限流(FR-4.4),随 manifest 上报为 throttle */
|
|
87
|
+
throttle?: ThrottleOpts;
|
|
88
|
+
/** 批处理(FR-4.7),随 manifest 上报为 batch */
|
|
89
|
+
batch?: BatchOpts;
|
|
52
90
|
/**
|
|
53
91
|
* run 进入 Failed 终态时的处理器(FR-2.11)。serve 时注册隐式函数 <id>/on-failure,
|
|
54
92
|
* 订阅内部事件 triggerlink/run.failed(match 按 function_id 过滤),handler 内可用全部 step 原语。
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createClient, type Client, type ClientOptions, type SendEventInput, type SendResult, type RegisterOptions, } from "./client.js";
|
|
2
|
-
export { createFunction, type TriggerFunction, type FunctionOpts, type HandlerContext, type EventPayload, type TriggerLinkEvent, type CancelOnRule, type RunFailedEventData, } from "./function.js";
|
|
2
|
+
export { createFunction, type TriggerFunction, type FunctionOpts, type HandlerContext, type EventPayload, type TriggerLinkEvent, type CancelOnRule, type RunFailedEventData, type DebounceOpts, type ThrottleOpts, type BatchOpts, } from "./function.js";
|
|
3
3
|
export { serve, sdkVersion, type ServeOptions } from "./serve.js";
|
|
4
4
|
export { StepInterrupt, type Opcode, type StepState, type OutgoingEvent } from "./execx.js";
|
|
5
5
|
export type { StepTool, WaitForEventOpts } from "./step.js";
|
package/dist/serve.js
CHANGED
|
@@ -24,6 +24,10 @@ export function serve(opts) {
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
/** 流控配置的时长字段:毫秒数转 Go duration 字符串,字符串原样透传(协议要求 Go duration)。 */
|
|
28
|
+
function goDuration(v) {
|
|
29
|
+
return typeof v === "number" ? msToGoDuration(v, "createFunction") : v;
|
|
30
|
+
}
|
|
27
31
|
async function GET(req) {
|
|
28
32
|
if (!verifySignature(opts.client.signingKey, req.headers.get(SIGNATURE_HEADER), new Uint8Array(0))) {
|
|
29
33
|
return json({ error: "unauthorized" }, 401);
|
|
@@ -47,6 +51,33 @@ export function serve(opts) {
|
|
|
47
51
|
: f.opts.timeout,
|
|
48
52
|
}
|
|
49
53
|
: {}),
|
|
54
|
+
...(f.opts.debounce
|
|
55
|
+
? {
|
|
56
|
+
debounce: {
|
|
57
|
+
period: goDuration(f.opts.debounce.period),
|
|
58
|
+
...(f.opts.debounce.key ? { key: f.opts.debounce.key } : {}),
|
|
59
|
+
...(f.opts.debounce.timeout ? { timeout: goDuration(f.opts.debounce.timeout) } : {}),
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
: {}),
|
|
63
|
+
...(f.opts.throttle
|
|
64
|
+
? {
|
|
65
|
+
throttle: {
|
|
66
|
+
limit: f.opts.throttle.limit,
|
|
67
|
+
period: goDuration(f.opts.throttle.period),
|
|
68
|
+
...(f.opts.throttle.key ? { key: f.opts.throttle.key } : {}),
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
: {}),
|
|
72
|
+
...(f.opts.batch
|
|
73
|
+
? {
|
|
74
|
+
batch: {
|
|
75
|
+
max_size: f.opts.batch.maxSize,
|
|
76
|
+
timeout: goDuration(f.opts.batch.timeout),
|
|
77
|
+
...(f.opts.batch.key ? { key: f.opts.batch.key } : {}),
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
: {}),
|
|
50
81
|
})),
|
|
51
82
|
});
|
|
52
83
|
}
|
|
@@ -73,6 +104,7 @@ export function serve(opts) {
|
|
|
73
104
|
try {
|
|
74
105
|
const output = await fn.handler({
|
|
75
106
|
event: cbReq.ctx.event,
|
|
107
|
+
...(cbReq.ctx.events ? { events: cbReq.ctx.events } : {}),
|
|
76
108
|
step,
|
|
77
109
|
runId: cbReq.ctx.run_id,
|
|
78
110
|
attempt: cbReq.ctx.attempt,
|