@advicenxt/sbp-server 0.1.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/benchmarks/bench.ts +272 -0
- package/dist/auth.d.ts +20 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +69 -0
- package/dist/auth.js.map +1 -0
- package/dist/blackboard.d.ts +84 -0
- package/dist/blackboard.d.ts.map +1 -0
- package/dist/blackboard.js +502 -0
- package/dist/blackboard.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +102 -0
- package/dist/cli.js.map +1 -0
- package/dist/conditions.d.ts +27 -0
- package/dist/conditions.d.ts.map +1 -0
- package/dist/conditions.js +240 -0
- package/dist/conditions.js.map +1 -0
- package/dist/decay.d.ts +21 -0
- package/dist/decay.d.ts.map +1 -0
- package/dist/decay.js +88 -0
- package/dist/decay.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/rate-limiter.d.ts +21 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +75 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/server.d.ts +63 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +401 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +54 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +55 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +247 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +26 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +296 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +205 -0
- package/dist/validation.js.map +1 -0
- package/eslint.config.js +26 -0
- package/package.json +66 -0
- package/src/auth.ts +89 -0
- package/src/blackboard.test.ts +287 -0
- package/src/blackboard.ts +651 -0
- package/src/cli.ts +116 -0
- package/src/conditions.ts +305 -0
- package/src/conformance.test.ts +686 -0
- package/src/decay.ts +103 -0
- package/src/index.ts +24 -0
- package/src/rate-limiter.ts +104 -0
- package/src/server.integration.test.ts +436 -0
- package/src/server.ts +500 -0
- package/src/store.ts +108 -0
- package/src/types.ts +314 -0
- package/src/validation.ts +251 -0
- package/tsconfig.eslint.json +5 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["../src/conditions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EACjB,cAAc,EAMf,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,cAAc,EACzB,GAAG,EAAE,iBAAiB,GACrB,gBAAgB,CAalB;AAoPD;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAUnF"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scent condition evaluation
|
|
3
|
+
*/
|
|
4
|
+
import { computeIntensity, isEvaporated } from "./decay.js";
|
|
5
|
+
/**
|
|
6
|
+
* Evaluate a scent condition against the current environment
|
|
7
|
+
*/
|
|
8
|
+
export function evaluateCondition(condition, ctx) {
|
|
9
|
+
switch (condition.type) {
|
|
10
|
+
case "threshold":
|
|
11
|
+
return evaluateThreshold(condition, ctx);
|
|
12
|
+
case "composite":
|
|
13
|
+
return evaluateComposite(condition, ctx);
|
|
14
|
+
case "rate":
|
|
15
|
+
return evaluateRate(condition, ctx);
|
|
16
|
+
case "pattern":
|
|
17
|
+
return evaluatePattern(condition, ctx);
|
|
18
|
+
default:
|
|
19
|
+
return { met: false, value: 0, matchingPheromoneIds: [] };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Evaluate a threshold condition
|
|
24
|
+
*/
|
|
25
|
+
function evaluateThreshold(condition, ctx) {
|
|
26
|
+
const { pheromones, now } = ctx;
|
|
27
|
+
// Filter matching pheromones
|
|
28
|
+
const matching = pheromones.filter((p) => {
|
|
29
|
+
// Trail must match
|
|
30
|
+
if (p.trail !== condition.trail)
|
|
31
|
+
return false;
|
|
32
|
+
// Type must match (or wildcard)
|
|
33
|
+
if (condition.signal_type !== "*" && p.type !== condition.signal_type)
|
|
34
|
+
return false;
|
|
35
|
+
// Must not be evaporated
|
|
36
|
+
if (isEvaporated(p, now))
|
|
37
|
+
return false;
|
|
38
|
+
// Tag filter
|
|
39
|
+
if (condition.tags && !matchTags(p.tags, condition.tags))
|
|
40
|
+
return false;
|
|
41
|
+
return true;
|
|
42
|
+
});
|
|
43
|
+
// Compute aggregate value
|
|
44
|
+
let aggValue;
|
|
45
|
+
const intensities = matching.map((p) => computeIntensity(p, now));
|
|
46
|
+
switch (condition.aggregation) {
|
|
47
|
+
case "sum":
|
|
48
|
+
aggValue = intensities.reduce((a, b) => a + b, 0);
|
|
49
|
+
break;
|
|
50
|
+
case "max":
|
|
51
|
+
aggValue = intensities.length > 0 ? Math.max(...intensities) : 0;
|
|
52
|
+
break;
|
|
53
|
+
case "avg":
|
|
54
|
+
aggValue = intensities.length > 0
|
|
55
|
+
? intensities.reduce((a, b) => a + b, 0) / intensities.length
|
|
56
|
+
: 0;
|
|
57
|
+
break;
|
|
58
|
+
case "count":
|
|
59
|
+
aggValue = matching.length;
|
|
60
|
+
break;
|
|
61
|
+
case "any":
|
|
62
|
+
aggValue = matching.length > 0 ? 1 : 0;
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
aggValue = 0;
|
|
66
|
+
}
|
|
67
|
+
// Compare
|
|
68
|
+
const met = compare(aggValue, condition.operator, condition.value);
|
|
69
|
+
return {
|
|
70
|
+
met,
|
|
71
|
+
value: aggValue,
|
|
72
|
+
matchingPheromoneIds: matching.map((p) => p.id),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Evaluate a composite condition (AND, OR, NOT)
|
|
77
|
+
*/
|
|
78
|
+
function evaluateComposite(condition, ctx) {
|
|
79
|
+
if (condition.conditions.length === 0) {
|
|
80
|
+
return { met: false, value: 0, matchingPheromoneIds: [] };
|
|
81
|
+
}
|
|
82
|
+
const results = condition.conditions.map((c) => evaluateCondition(c, ctx));
|
|
83
|
+
const allPheromoneIds = [...new Set(results.flatMap((r) => r.matchingPheromoneIds))];
|
|
84
|
+
let met;
|
|
85
|
+
switch (condition.operator) {
|
|
86
|
+
case "and":
|
|
87
|
+
met = results.every((r) => r.met);
|
|
88
|
+
break;
|
|
89
|
+
case "or":
|
|
90
|
+
met = results.some((r) => r.met);
|
|
91
|
+
break;
|
|
92
|
+
case "not":
|
|
93
|
+
met = !results[0].met;
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
met = false;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
met,
|
|
100
|
+
value: results.filter((r) => r.met).length,
|
|
101
|
+
matchingPheromoneIds: allPheromoneIds,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Evaluate a rate condition
|
|
106
|
+
*/
|
|
107
|
+
function evaluateRate(condition, ctx) {
|
|
108
|
+
const { emissionHistory = [], now } = ctx;
|
|
109
|
+
// Filter emissions in the window
|
|
110
|
+
const windowStart = now - condition.window_ms;
|
|
111
|
+
const relevantEmissions = emissionHistory.filter((e) => e.trail === condition.trail &&
|
|
112
|
+
(condition.signal_type === "*" || e.type === condition.signal_type) &&
|
|
113
|
+
e.timestamp >= windowStart);
|
|
114
|
+
let value;
|
|
115
|
+
if (condition.metric === "emissions_per_second") {
|
|
116
|
+
const windowSeconds = condition.window_ms / 1000;
|
|
117
|
+
value = relevantEmissions.length / windowSeconds;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// intensity_delta would require tracking intensity over time
|
|
121
|
+
// For now, approximate with emission count
|
|
122
|
+
value = relevantEmissions.length;
|
|
123
|
+
}
|
|
124
|
+
const met = compare(value, condition.operator, condition.value);
|
|
125
|
+
return {
|
|
126
|
+
met,
|
|
127
|
+
value,
|
|
128
|
+
matchingPheromoneIds: [],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Evaluate a pattern condition
|
|
133
|
+
* Checks if a sequence of pheromone emissions occurred within a time window
|
|
134
|
+
*/
|
|
135
|
+
function evaluatePattern(condition, ctx) {
|
|
136
|
+
const { emissionHistory = [], now } = ctx;
|
|
137
|
+
const { sequence, window_ms, ordered = true } = condition;
|
|
138
|
+
// Filter emissions within the window
|
|
139
|
+
const windowStart = now - window_ms;
|
|
140
|
+
const relevant = emissionHistory.filter((e) => e.timestamp >= windowStart);
|
|
141
|
+
if (relevant.length === 0 || sequence.length === 0) {
|
|
142
|
+
return { met: false, value: 0, matchingPheromoneIds: [] };
|
|
143
|
+
}
|
|
144
|
+
if (ordered) {
|
|
145
|
+
// Ordered: each step must appear after the previous one
|
|
146
|
+
let searchFrom = 0;
|
|
147
|
+
let matchCount = 0;
|
|
148
|
+
for (const step of sequence) {
|
|
149
|
+
let found = false;
|
|
150
|
+
for (let i = searchFrom; i < relevant.length; i++) {
|
|
151
|
+
const emission = relevant[i];
|
|
152
|
+
if (emission.trail === step.trail &&
|
|
153
|
+
emission.type === step.signal_type) {
|
|
154
|
+
found = true;
|
|
155
|
+
searchFrom = i + 1;
|
|
156
|
+
matchCount++;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!found)
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
met: matchCount === sequence.length,
|
|
165
|
+
value: matchCount / sequence.length,
|
|
166
|
+
matchingPheromoneIds: [],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Unordered: all steps must appear in any order
|
|
171
|
+
const remaining = [...relevant];
|
|
172
|
+
let matchCount = 0;
|
|
173
|
+
for (const step of sequence) {
|
|
174
|
+
const idx = remaining.findIndex((e) => e.trail === step.trail && e.type === step.signal_type);
|
|
175
|
+
if (idx >= 0) {
|
|
176
|
+
remaining.splice(idx, 1);
|
|
177
|
+
matchCount++;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
met: matchCount === sequence.length,
|
|
182
|
+
value: matchCount / sequence.length,
|
|
183
|
+
matchingPheromoneIds: [],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Match tags against a filter
|
|
189
|
+
*/
|
|
190
|
+
function matchTags(tags, filter) {
|
|
191
|
+
if (filter.any && filter.any.length > 0) {
|
|
192
|
+
if (!filter.any.some((t) => tags.includes(t)))
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (filter.all && filter.all.length > 0) {
|
|
196
|
+
if (!filter.all.every((t) => tags.includes(t)))
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
if (filter.none && filter.none.length > 0) {
|
|
200
|
+
if (filter.none.some((t) => tags.includes(t)))
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Compare two values with an operator
|
|
207
|
+
*/
|
|
208
|
+
function compare(a, op, b) {
|
|
209
|
+
switch (op) {
|
|
210
|
+
case ">=":
|
|
211
|
+
return a >= b;
|
|
212
|
+
case ">":
|
|
213
|
+
return a > b;
|
|
214
|
+
case "<=":
|
|
215
|
+
return a <= b;
|
|
216
|
+
case "<":
|
|
217
|
+
return a < b;
|
|
218
|
+
case "==":
|
|
219
|
+
return a === b;
|
|
220
|
+
case "!=":
|
|
221
|
+
return a !== b;
|
|
222
|
+
default:
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Create a snapshot of a pheromone for trigger payloads
|
|
228
|
+
*/
|
|
229
|
+
export function createSnapshot(pheromone, now) {
|
|
230
|
+
return {
|
|
231
|
+
id: pheromone.id,
|
|
232
|
+
trail: pheromone.trail,
|
|
233
|
+
type: pheromone.type,
|
|
234
|
+
current_intensity: computeIntensity(pheromone, now),
|
|
235
|
+
payload: pheromone.payload,
|
|
236
|
+
age_ms: now - pheromone.emitted_at,
|
|
237
|
+
tags: pheromone.tags,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=conditions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditions.js","sourceRoot":"","sources":["../src/conditions.ts"],"names":[],"mappings":"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"}
|
package/dist/decay.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decay computation utilities
|
|
3
|
+
*/
|
|
4
|
+
import type { DecayModel, Pheromone } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Compute the current intensity of a pheromone after decay
|
|
7
|
+
*/
|
|
8
|
+
export declare function computeIntensity(pheromone: Pheromone, now: number): number;
|
|
9
|
+
/**
|
|
10
|
+
* Check if a pheromone has evaporated below its floor
|
|
11
|
+
*/
|
|
12
|
+
export declare function isEvaporated(pheromone: Pheromone, now: number): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Get the default decay model
|
|
15
|
+
*/
|
|
16
|
+
export declare function defaultDecay(): DecayModel;
|
|
17
|
+
/**
|
|
18
|
+
* Estimate time until pheromone evaporates
|
|
19
|
+
*/
|
|
20
|
+
export declare function timeToEvaporation(pheromone: Pheromone, now: number): number | null;
|
|
21
|
+
//# sourceMappingURL=decay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decay.d.ts","sourceRoot":"","sources":["../src/decay.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAmC1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,UAAU,CAEzC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuClF"}
|
package/dist/decay.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decay computation utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Compute the current intensity of a pheromone after decay
|
|
6
|
+
*/
|
|
7
|
+
export function computeIntensity(pheromone, now) {
|
|
8
|
+
const elapsed = now - pheromone.last_reinforced_at;
|
|
9
|
+
if (elapsed <= 0) {
|
|
10
|
+
return pheromone.initial_intensity;
|
|
11
|
+
}
|
|
12
|
+
switch (pheromone.decay_model.type) {
|
|
13
|
+
case "exponential": {
|
|
14
|
+
const halfLife = pheromone.decay_model.half_life_ms;
|
|
15
|
+
return pheromone.initial_intensity * Math.pow(0.5, elapsed / halfLife);
|
|
16
|
+
}
|
|
17
|
+
case "linear": {
|
|
18
|
+
const rate = pheromone.decay_model.rate_per_ms;
|
|
19
|
+
return Math.max(0, pheromone.initial_intensity - rate * elapsed);
|
|
20
|
+
}
|
|
21
|
+
case "step": {
|
|
22
|
+
const steps = pheromone.decay_model.steps;
|
|
23
|
+
// Find the applicable step (steps should be sorted by at_ms)
|
|
24
|
+
for (let i = steps.length - 1; i >= 0; i--) {
|
|
25
|
+
if (elapsed >= steps[i].at_ms) {
|
|
26
|
+
return steps[i].intensity;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return pheromone.initial_intensity;
|
|
30
|
+
}
|
|
31
|
+
case "immortal":
|
|
32
|
+
return pheromone.initial_intensity;
|
|
33
|
+
default:
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if a pheromone has evaporated below its floor
|
|
39
|
+
*/
|
|
40
|
+
export function isEvaporated(pheromone, now) {
|
|
41
|
+
return computeIntensity(pheromone, now) < pheromone.ttl_floor;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the default decay model
|
|
45
|
+
*/
|
|
46
|
+
export function defaultDecay() {
|
|
47
|
+
return { type: "exponential", half_life_ms: 300000 }; // 5 minutes
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Estimate time until pheromone evaporates
|
|
51
|
+
*/
|
|
52
|
+
export function timeToEvaporation(pheromone, now) {
|
|
53
|
+
const currentIntensity = computeIntensity(pheromone, now);
|
|
54
|
+
if (currentIntensity <= pheromone.ttl_floor) {
|
|
55
|
+
return 0; // Already evaporated
|
|
56
|
+
}
|
|
57
|
+
switch (pheromone.decay_model.type) {
|
|
58
|
+
case "exponential": {
|
|
59
|
+
// Solve: ttl_floor = current * 0.5^(t/halfLife)
|
|
60
|
+
// t = halfLife * log2(current / ttl_floor)
|
|
61
|
+
const halfLife = pheromone.decay_model.half_life_ms;
|
|
62
|
+
const ratio = currentIntensity / pheromone.ttl_floor;
|
|
63
|
+
return halfLife * Math.log2(ratio);
|
|
64
|
+
}
|
|
65
|
+
case "linear": {
|
|
66
|
+
// Solve: ttl_floor = current - rate * t
|
|
67
|
+
// t = (current - ttl_floor) / rate
|
|
68
|
+
const rate = pheromone.decay_model.rate_per_ms;
|
|
69
|
+
if (rate <= 0)
|
|
70
|
+
return null;
|
|
71
|
+
return (currentIntensity - pheromone.ttl_floor) / rate;
|
|
72
|
+
}
|
|
73
|
+
case "step": {
|
|
74
|
+
// Find next step below threshold
|
|
75
|
+
const steps = pheromone.decay_model.steps;
|
|
76
|
+
const elapsed = now - pheromone.last_reinforced_at;
|
|
77
|
+
for (const step of steps) {
|
|
78
|
+
if (step.at_ms > elapsed && step.intensity < pheromone.ttl_floor) {
|
|
79
|
+
return step.at_ms - elapsed;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null; // May never evaporate with given steps
|
|
83
|
+
}
|
|
84
|
+
case "immortal":
|
|
85
|
+
return null; // Never evaporates
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=decay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decay.js","sourceRoot":"","sources":["../src/decay.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SBP Server - Public API
|
|
3
|
+
*/
|
|
4
|
+
export { Blackboard, type BlackboardOptions, type TriggerHandler } from "./blackboard.js";
|
|
5
|
+
export { SbpServer, type ServerOptions } from "./server.js";
|
|
6
|
+
export { type PheromoneStore, MemoryStore, createStore, type StoreType } from "./store.js";
|
|
7
|
+
export * from "./types.js";
|
|
8
|
+
export { computeIntensity, isEvaporated, defaultDecay, timeToEvaporation } from "./decay.js";
|
|
9
|
+
export { evaluateCondition, createSnapshot } from "./conditions.js";
|
|
10
|
+
export { createAuthHook, type AuthOptions } from "./auth.js";
|
|
11
|
+
export { createRateLimitHook, type RateLimitOptions } from "./rate-limiter.js";
|
|
12
|
+
export { validateEnvelope, validateParams, EmitParamsSchema, SniffParamsSchema, RegisterScentParamsSchema, DeregisterScentParamsSchema, EvaporateParamsSchema, InspectParamsSchema, JsonRpcRequestSchema, } from "./validation.js";
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,KAAK,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC3F,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EACH,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,GACvB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SBP Server - Public API
|
|
3
|
+
*/
|
|
4
|
+
export { Blackboard } from "./blackboard.js";
|
|
5
|
+
export { SbpServer } from "./server.js";
|
|
6
|
+
export { MemoryStore, createStore } from "./store.js";
|
|
7
|
+
export * from "./types.js";
|
|
8
|
+
export { computeIntensity, isEvaporated, defaultDecay, timeToEvaporation } from "./decay.js";
|
|
9
|
+
export { evaluateCondition, createSnapshot } from "./conditions.js";
|
|
10
|
+
export { createAuthHook } from "./auth.js";
|
|
11
|
+
export { createRateLimitHook } from "./rate-limiter.js";
|
|
12
|
+
export { validateEnvelope, validateParams, EmitParamsSchema, SniffParamsSchema, RegisterScentParamsSchema, DeregisterScentParamsSchema, EvaporateParamsSchema, InspectParamsSchema, JsonRpcRequestSchema, } from "./validation.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAA+C,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAsB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAuB,WAAW,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAC3F,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAoB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAyB,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EACH,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,GACvB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SBP Rate Limiting Middleware
|
|
3
|
+
* Token bucket rate limiter per agent ID
|
|
4
|
+
*/
|
|
5
|
+
import type { FastifyRequest, FastifyReply, HookHandlerDoneFunction } from "fastify";
|
|
6
|
+
export interface RateLimitOptions {
|
|
7
|
+
/** Maximum requests per window (default: 1000) */
|
|
8
|
+
maxRequests?: number;
|
|
9
|
+
/** Window duration in milliseconds (default: 60000 = 1 minute) */
|
|
10
|
+
windowMs?: number;
|
|
11
|
+
/** Maximum scent registrations per agent (default: 100) */
|
|
12
|
+
maxScentRegistrations?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create a Fastify onRequest hook for rate limiting.
|
|
16
|
+
*
|
|
17
|
+
* Uses a token bucket algorithm per agent ID (from `Sbp-Agent-Id` header).
|
|
18
|
+
* Returns JSON-RPC error code -32004 (RATE_LIMITED) when the limit is exceeded.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createRateLimitHook(options?: RateLimitOptions): (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => void;
|
|
21
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAErF,MAAM,WAAW,gBAAgB;IAC7B,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAClC;AAOD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,gBAAqB,IAqB1D,SAAS,cAAc,EACvB,OAAO,YAAY,EACnB,MAAM,uBAAuB,KAC9B,IAAI,CAoDV"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SBP Rate Limiting Middleware
|
|
3
|
+
* Token bucket rate limiter per agent ID
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Create a Fastify onRequest hook for rate limiting.
|
|
7
|
+
*
|
|
8
|
+
* Uses a token bucket algorithm per agent ID (from `Sbp-Agent-Id` header).
|
|
9
|
+
* Returns JSON-RPC error code -32004 (RATE_LIMITED) when the limit is exceeded.
|
|
10
|
+
*/
|
|
11
|
+
export function createRateLimitHook(options = {}) {
|
|
12
|
+
const maxRequests = options.maxRequests ?? 1000;
|
|
13
|
+
const windowMs = options.windowMs ?? 60000;
|
|
14
|
+
const buckets = new Map();
|
|
15
|
+
// Periodic cleanup of stale buckets (every 5 minutes)
|
|
16
|
+
const cleanupInterval = setInterval(() => {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
for (const [key, bucket] of buckets.entries()) {
|
|
19
|
+
if (now - bucket.lastRefill > windowMs * 5) {
|
|
20
|
+
buckets.delete(key);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}, 300000);
|
|
24
|
+
// Allow GC to clean up the interval if the server is stopped
|
|
25
|
+
if (cleanupInterval.unref) {
|
|
26
|
+
cleanupInterval.unref();
|
|
27
|
+
}
|
|
28
|
+
return function rateLimitHook(request, reply, done) {
|
|
29
|
+
// Skip rate limiting for health checks and OPTIONS
|
|
30
|
+
const url = request.url.split("?")[0];
|
|
31
|
+
if (url === "/health" || request.method === "OPTIONS") {
|
|
32
|
+
done();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Identify the agent
|
|
36
|
+
const agentId = request.headers["sbp-agent-id"] || request.ip || "anonymous";
|
|
37
|
+
// Get or create token bucket
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
let bucket = buckets.get(agentId);
|
|
40
|
+
if (!bucket) {
|
|
41
|
+
bucket = { tokens: maxRequests, lastRefill: now };
|
|
42
|
+
buckets.set(agentId, bucket);
|
|
43
|
+
}
|
|
44
|
+
// Refill tokens based on elapsed time
|
|
45
|
+
const elapsed = now - bucket.lastRefill;
|
|
46
|
+
const refillRate = maxRequests / windowMs;
|
|
47
|
+
bucket.tokens = Math.min(maxRequests, bucket.tokens + elapsed * refillRate);
|
|
48
|
+
bucket.lastRefill = now;
|
|
49
|
+
// Check if request is allowed
|
|
50
|
+
if (bucket.tokens < 1) {
|
|
51
|
+
const retryAfterMs = Math.ceil((1 - bucket.tokens) / refillRate);
|
|
52
|
+
reply
|
|
53
|
+
.status(429)
|
|
54
|
+
.header("Retry-After", Math.ceil(retryAfterMs / 1000).toString())
|
|
55
|
+
.send({
|
|
56
|
+
jsonrpc: "2.0",
|
|
57
|
+
id: null,
|
|
58
|
+
error: {
|
|
59
|
+
code: -32004,
|
|
60
|
+
message: "Rate limited: Too many requests",
|
|
61
|
+
data: {
|
|
62
|
+
retry_after_ms: retryAfterMs,
|
|
63
|
+
limit: maxRequests,
|
|
64
|
+
window_ms: windowMs,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Consume a token
|
|
71
|
+
bucket.tokens -= 1;
|
|
72
|
+
done();
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SBP HTTP Server
|
|
3
|
+
* Streamable HTTP with SSE (following MCP transport patterns)
|
|
4
|
+
*/
|
|
5
|
+
import { Blackboard, BlackboardOptions } from "./blackboard.js";
|
|
6
|
+
import { type AuthOptions } from "./auth.js";
|
|
7
|
+
import { type RateLimitOptions } from "./rate-limiter.js";
|
|
8
|
+
export interface ServerOptions extends BlackboardOptions {
|
|
9
|
+
/** HTTP port (default: 3000) */
|
|
10
|
+
port?: number;
|
|
11
|
+
/** Host to bind to (default: localhost) */
|
|
12
|
+
host?: string;
|
|
13
|
+
/** Enable CORS (default: true) */
|
|
14
|
+
cors?: boolean;
|
|
15
|
+
/** Request logging (default: false) */
|
|
16
|
+
logging?: boolean;
|
|
17
|
+
/** Authentication options */
|
|
18
|
+
auth?: AuthOptions;
|
|
19
|
+
/** Rate limiting options */
|
|
20
|
+
rateLimit?: RateLimitOptions;
|
|
21
|
+
}
|
|
22
|
+
export declare class SbpServer {
|
|
23
|
+
private app;
|
|
24
|
+
readonly blackboard: Blackboard;
|
|
25
|
+
private options;
|
|
26
|
+
private sseClients;
|
|
27
|
+
private sessions;
|
|
28
|
+
private eventCounter;
|
|
29
|
+
constructor(options?: ServerOptions);
|
|
30
|
+
private setupRoutes;
|
|
31
|
+
/**
|
|
32
|
+
* Handle POST requests (client -> server messages)
|
|
33
|
+
*/
|
|
34
|
+
private handlePost;
|
|
35
|
+
/**
|
|
36
|
+
* Handle GET requests - open SSE stream for triggers
|
|
37
|
+
*/
|
|
38
|
+
private handleSSE;
|
|
39
|
+
/**
|
|
40
|
+
* Send an SSE event to a client
|
|
41
|
+
*/
|
|
42
|
+
private sendSSEEvent;
|
|
43
|
+
/**
|
|
44
|
+
* Send a JSON-RPC notification via SSE
|
|
45
|
+
*/
|
|
46
|
+
private sendSSENotification;
|
|
47
|
+
/**
|
|
48
|
+
* Handle JSON-RPC requests
|
|
49
|
+
*/
|
|
50
|
+
private handleRpc;
|
|
51
|
+
/**
|
|
52
|
+
* Set up trigger forwarding to SSE clients
|
|
53
|
+
*/
|
|
54
|
+
private setupSSETrigger;
|
|
55
|
+
/**
|
|
56
|
+
* Set up webhook trigger delivery to an agent endpoint
|
|
57
|
+
*/
|
|
58
|
+
private setupWebhookTrigger;
|
|
59
|
+
start(): Promise<void>;
|
|
60
|
+
stop(): Promise<void>;
|
|
61
|
+
get address(): string;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAchE,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE/E,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAUD,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAAkB;IAC7B,SAAgB,UAAU,EAAE,UAAU,CAAC;IACvC,OAAO,CAAC,OAAO,CAGb;IACF,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,QAAQ,CAA6D;IAC7E,OAAO,CAAC,YAAY,CAAK;gBAEb,OAAO,GAAE,aAAkB;IAsBvC,OAAO,CAAC,WAAW;IAoFnB;;OAEG;YACW,UAAU;IAmDxB;;OAEG;YACW,SAAS;IAuDvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;YACW,SAAS;IAuGvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqCrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAe3B,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF"}
|