@acquiredintelligence/attend 0.0.0-stage → 0.2.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.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -2
  3. package/dist/attend.d.ts +30 -0
  4. package/dist/attend.d.ts.map +1 -0
  5. package/dist/attend.js +464 -0
  6. package/dist/attend.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +4 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/core/ids.d.ts +12 -0
  12. package/dist/core/ids.d.ts.map +1 -0
  13. package/dist/core/ids.js +97 -0
  14. package/dist/core/ids.js.map +1 -0
  15. package/dist/core/reducer.d.ts +26 -0
  16. package/dist/core/reducer.d.ts.map +1 -0
  17. package/dist/core/reducer.js +437 -0
  18. package/dist/core/reducer.js.map +1 -0
  19. package/dist/core/seen.d.ts +22 -0
  20. package/dist/core/seen.d.ts.map +1 -0
  21. package/dist/core/seen.js +61 -0
  22. package/dist/core/seen.js.map +1 -0
  23. package/dist/core/state.d.ts +12 -0
  24. package/dist/core/state.d.ts.map +1 -0
  25. package/dist/core/state.js +90 -0
  26. package/dist/core/state.js.map +1 -0
  27. package/dist/core/step.d.ts +14 -0
  28. package/dist/core/step.d.ts.map +1 -0
  29. package/dist/core/step.js +17 -0
  30. package/dist/core/step.js.map +1 -0
  31. package/dist/core/threshold.d.ts +40 -0
  32. package/dist/core/threshold.d.ts.map +1 -0
  33. package/dist/core/threshold.js +72 -0
  34. package/dist/core/threshold.js.map +1 -0
  35. package/dist/core/types.d.ts +704 -0
  36. package/dist/core/types.d.ts.map +1 -0
  37. package/dist/core/types.js +24 -0
  38. package/dist/core/types.js.map +1 -0
  39. package/dist/core/window.d.ts +38 -0
  40. package/dist/core/window.d.ts.map +1 -0
  41. package/dist/core/window.js +322 -0
  42. package/dist/core/window.js.map +1 -0
  43. package/dist/decisions.d.ts +53 -0
  44. package/dist/decisions.d.ts.map +1 -0
  45. package/dist/decisions.js +115 -0
  46. package/dist/decisions.js.map +1 -0
  47. package/dist/errors.d.ts +36 -0
  48. package/dist/errors.d.ts.map +1 -0
  49. package/dist/errors.js +53 -0
  50. package/dist/errors.js.map +1 -0
  51. package/dist/index.d.ts +10 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +4 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/internal/adapter.d.ts +21 -0
  56. package/dist/internal/adapter.d.ts.map +1 -0
  57. package/dist/internal/adapter.js +62 -0
  58. package/dist/internal/adapter.js.map +1 -0
  59. package/dist/internal/assert.d.ts +5 -0
  60. package/dist/internal/assert.d.ts.map +1 -0
  61. package/dist/internal/assert.js +14 -0
  62. package/dist/internal/assert.js.map +1 -0
  63. package/dist/internal/clock.d.ts +8 -0
  64. package/dist/internal/clock.d.ts.map +1 -0
  65. package/dist/internal/clock.js +38 -0
  66. package/dist/internal/clock.js.map +1 -0
  67. package/dist/internal/http.d.ts +42 -0
  68. package/dist/internal/http.d.ts.map +1 -0
  69. package/dist/internal/http.js +122 -0
  70. package/dist/internal/http.js.map +1 -0
  71. package/dist/internal/images.d.ts +18 -0
  72. package/dist/internal/images.d.ts.map +1 -0
  73. package/dist/internal/images.js +75 -0
  74. package/dist/internal/images.js.map +1 -0
  75. package/dist/internal/json.d.ts +3 -0
  76. package/dist/internal/json.d.ts.map +1 -0
  77. package/dist/internal/json.js +5 -0
  78. package/dist/internal/json.js.map +1 -0
  79. package/dist/internal/prompt.d.ts +31 -0
  80. package/dist/internal/prompt.d.ts.map +1 -0
  81. package/dist/internal/prompt.js +149 -0
  82. package/dist/internal/prompt.js.map +1 -0
  83. package/dist/internal/shared.d.ts +12 -0
  84. package/dist/internal/shared.d.ts.map +1 -0
  85. package/dist/internal/shared.js +138 -0
  86. package/dist/internal/shared.js.map +1 -0
  87. package/dist/jev.d.ts +74 -0
  88. package/dist/jev.d.ts.map +1 -0
  89. package/dist/jev.js +156 -0
  90. package/dist/jev.js.map +1 -0
  91. package/dist/llm.d.ts +164 -0
  92. package/dist/llm.d.ts.map +1 -0
  93. package/dist/llm.js +79 -0
  94. package/dist/llm.js.map +1 -0
  95. package/dist/mcp.d.ts +130 -0
  96. package/dist/mcp.d.ts.map +1 -0
  97. package/dist/mcp.js +550 -0
  98. package/dist/mcp.js.map +1 -0
  99. package/dist/memory.d.ts +10 -0
  100. package/dist/memory.d.ts.map +1 -0
  101. package/dist/memory.js +50 -0
  102. package/dist/memory.js.map +1 -0
  103. package/dist/postgres.d.ts +25 -0
  104. package/dist/postgres.d.ts.map +1 -0
  105. package/dist/postgres.js +56 -0
  106. package/dist/postgres.js.map +1 -0
  107. package/dist/redis.d.ts +20 -0
  108. package/dist/redis.d.ts.map +1 -0
  109. package/dist/redis.js +83 -0
  110. package/dist/redis.js.map +1 -0
  111. package/dist/server/compat.d.ts +13 -0
  112. package/dist/server/compat.d.ts.map +1 -0
  113. package/dist/server/compat.js +5 -0
  114. package/dist/server/compat.js.map +1 -0
  115. package/dist/server/cursor.d.ts +15 -0
  116. package/dist/server/cursor.d.ts.map +1 -0
  117. package/dist/server/cursor.js +50 -0
  118. package/dist/server/cursor.js.map +1 -0
  119. package/dist/server/events.d.ts +42 -0
  120. package/dist/server/events.d.ts.map +1 -0
  121. package/dist/server/events.js +189 -0
  122. package/dist/server/events.js.map +1 -0
  123. package/dist/server/fanout.d.ts +28 -0
  124. package/dist/server/fanout.d.ts.map +1 -0
  125. package/dist/server/fanout.js +184 -0
  126. package/dist/server/fanout.js.map +1 -0
  127. package/dist/server/guard.d.ts +19 -0
  128. package/dist/server/guard.d.ts.map +1 -0
  129. package/dist/server/guard.js +27 -0
  130. package/dist/server/guard.js.map +1 -0
  131. package/dist/server/http.d.ts +4 -0
  132. package/dist/server/http.d.ts.map +1 -0
  133. package/dist/server/http.js +323 -0
  134. package/dist/server/http.js.map +1 -0
  135. package/dist/server/ingest.d.ts +4 -0
  136. package/dist/server/ingest.d.ts.map +1 -0
  137. package/dist/server/ingest.js +400 -0
  138. package/dist/server/ingest.js.map +1 -0
  139. package/dist/server/install.d.ts +5 -0
  140. package/dist/server/install.d.ts.map +1 -0
  141. package/dist/server/install.js +91 -0
  142. package/dist/server/install.js.map +1 -0
  143. package/dist/server/poll.d.ts +4 -0
  144. package/dist/server/poll.d.ts.map +1 -0
  145. package/dist/server/poll.js +45 -0
  146. package/dist/server/poll.js.map +1 -0
  147. package/dist/server/serve.d.ts +19 -0
  148. package/dist/server/serve.d.ts.map +1 -0
  149. package/dist/server/serve.js +238 -0
  150. package/dist/server/serve.js.map +1 -0
  151. package/dist/server/sessions.d.ts +14 -0
  152. package/dist/server/sessions.d.ts.map +1 -0
  153. package/dist/server/sessions.js +54 -0
  154. package/dist/server/sessions.js.map +1 -0
  155. package/dist/server/stream.d.ts +11 -0
  156. package/dist/server/stream.d.ts.map +1 -0
  157. package/dist/server/stream.js +216 -0
  158. package/dist/server/stream.js.map +1 -0
  159. package/dist/server/tools.d.ts +22 -0
  160. package/dist/server/tools.d.ts.map +1 -0
  161. package/dist/server/tools.js +55 -0
  162. package/dist/server/tools.js.map +1 -0
  163. package/dist/server/types.d.ts +351 -0
  164. package/dist/server/types.d.ts.map +1 -0
  165. package/dist/server/types.js +5 -0
  166. package/dist/server/types.js.map +1 -0
  167. package/dist/server.d.ts +11 -0
  168. package/dist/server.d.ts.map +1 -0
  169. package/dist/server.js +10 -0
  170. package/dist/server.js.map +1 -0
  171. package/dist/shell/budget.d.ts +4 -0
  172. package/dist/shell/budget.d.ts.map +1 -0
  173. package/dist/shell/budget.js +5 -0
  174. package/dist/shell/budget.js.map +1 -0
  175. package/dist/shell/copy.d.ts +20 -0
  176. package/dist/shell/copy.d.ts.map +1 -0
  177. package/dist/shell/copy.js +73 -0
  178. package/dist/shell/copy.js.map +1 -0
  179. package/dist/shell/decisions.d.ts +6 -0
  180. package/dist/shell/decisions.d.ts.map +1 -0
  181. package/dist/shell/decisions.js +42 -0
  182. package/dist/shell/decisions.js.map +1 -0
  183. package/dist/shell/read.d.ts +7 -0
  184. package/dist/shell/read.d.ts.map +1 -0
  185. package/dist/shell/read.js +21 -0
  186. package/dist/shell/read.js.map +1 -0
  187. package/dist/shell/scheduler.d.ts +4 -0
  188. package/dist/shell/scheduler.d.ts.map +1 -0
  189. package/dist/shell/scheduler.js +90 -0
  190. package/dist/shell/scheduler.js.map +1 -0
  191. package/dist/shell/scope.d.ts +27 -0
  192. package/dist/shell/scope.d.ts.map +1 -0
  193. package/dist/shell/scope.js +343 -0
  194. package/dist/shell/scope.js.map +1 -0
  195. package/dist/shell/types.d.ts +168 -0
  196. package/dist/shell/types.d.ts.map +1 -0
  197. package/dist/shell/types.js +2 -0
  198. package/dist/shell/types.js.map +1 -0
  199. package/dist/sqlite.d.ts +14 -0
  200. package/dist/sqlite.d.ts.map +1 -0
  201. package/dist/sqlite.js +39 -0
  202. package/dist/sqlite.js.map +1 -0
  203. package/dist/step.d.ts +18 -0
  204. package/dist/step.d.ts.map +1 -0
  205. package/dist/step.js +14 -0
  206. package/dist/step.js.map +1 -0
  207. package/dist/store/memory.d.ts +12 -0
  208. package/dist/store/memory.d.ts.map +1 -0
  209. package/dist/store/memory.js +264 -0
  210. package/dist/store/memory.js.map +1 -0
  211. package/dist/store/postgres.d.ts +24 -0
  212. package/dist/store/postgres.d.ts.map +1 -0
  213. package/dist/store/postgres.js +364 -0
  214. package/dist/store/postgres.js.map +1 -0
  215. package/dist/store/redis.d.ts +12 -0
  216. package/dist/store/redis.d.ts.map +1 -0
  217. package/dist/store/redis.js +540 -0
  218. package/dist/store/redis.js.map +1 -0
  219. package/dist/store/sqlite-worker.d.ts +91 -0
  220. package/dist/store/sqlite-worker.d.ts.map +1 -0
  221. package/dist/store/sqlite-worker.js +322 -0
  222. package/dist/store/sqlite-worker.js.map +1 -0
  223. package/dist/store/sqlite.d.ts +34 -0
  224. package/dist/store/sqlite.d.ts.map +1 -0
  225. package/dist/store/sqlite.js +238 -0
  226. package/dist/store/sqlite.js.map +1 -0
  227. package/dist/store/types.d.ts +137 -0
  228. package/dist/store/types.d.ts.map +1 -0
  229. package/dist/store/types.js +2 -0
  230. package/dist/store/types.js.map +1 -0
  231. package/dist/testing/conformance.d.ts +13 -0
  232. package/dist/testing/conformance.d.ts.map +1 -0
  233. package/dist/testing/conformance.js +542 -0
  234. package/dist/testing/conformance.js.map +1 -0
  235. package/dist/testing/wire.d.ts +16 -0
  236. package/dist/testing/wire.d.ts.map +1 -0
  237. package/dist/testing/wire.js +304 -0
  238. package/dist/testing/wire.js.map +1 -0
  239. package/dist/testing.d.ts +113 -0
  240. package/dist/testing.d.ts.map +1 -0
  241. package/dist/testing.js +655 -0
  242. package/dist/testing.js.map +1 -0
  243. package/dist/types.d.ts +5 -0
  244. package/dist/types.d.ts.map +1 -0
  245. package/dist/types.js +5 -0
  246. package/dist/types.js.map +1 -0
  247. package/package.json +130 -4
  248. package/skills/attend/SKILL.md +231 -0
  249. package/skills/attend/references/judges.md +283 -0
  250. package/skills/attend/references/kinds.md +62 -0
  251. package/skills/attend/references/mcp.md +132 -0
  252. package/skills/attend/references/sinks.md +73 -0
  253. package/skills/attend/references/stores.md +90 -0
  254. package/skills/attend/references/testing.md +120 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { EventLog } from './types.js';
2
+ import type { PostgresClient } from './store/postgres.js';
3
+ export { postgresStore } from './store/postgres.js';
4
+ export type { PostgresClient, PostgresListener, PostgresStoreOptions } from './store/postgres.js';
5
+ export interface PostgresOptions {
6
+ /**
7
+ * Prepended to the table names. Lowercase letters, digits and underscores, since Postgres
8
+ * folds unquoted names to lowercase and the append lock is keyed by the name as written.
9
+ * Default 'attend_'. To put the tables in another schema, set the connection's `search_path`.
10
+ */
11
+ prefix?: string;
12
+ }
13
+ export declare function migrate(client: PostgresClient, options?: PostgresOptions): Promise<void>;
14
+ /**
15
+ * Positions come from one bigserial, so a reader could see position 11 commit before 10 and
16
+ * skip 10 for good. Each append therefore takes a transaction-scoped advisory lock on its
17
+ * scope before drawing any position, in the same statement: appends to one scope draw and
18
+ * commit one at a time, and the lock is released only after the commit is visible.
19
+ *
20
+ * `read` with `blockMs` polls every `pollMs` (default 100) until an entry arrives or the time is up.
21
+ */
22
+ export declare function postgresLog(client: PostgresClient, options?: PostgresOptions & {
23
+ pollMs?: number;
24
+ }): EventLog;
25
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,YAAY,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAIlG,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9F;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,QAAQ,CA+B7G"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `attend/postgres`: a ScopeStore and an EventLog over a client with `query(text, values)`.
3
+ * Run `migrate()` before either adapter. It calls the store migration, then creates the
4
+ * separate EventLog table and index that `postgresLog` still needs.
5
+ */
6
+ import { boundary } from './internal/adapter.js';
7
+ import { migrate as migrateStore } from './store/postgres.js';
8
+ export { postgresStore } from './store/postgres.js';
9
+ const { column, formatPosition, parseEvent, parsePosition, tablePrefix } = boundary('attend/postgres');
10
+ export async function migrate(client, options) {
11
+ await migrateStore(client, options);
12
+ const log = `${tablePrefix(options?.prefix, { lowercase: true })}log`;
13
+ await client.query(`SELECT pg_advisory_xact_lock(hashtext('attend.migrate'));
14
+ CREATE TABLE IF NOT EXISTS ${log} (position bigserial PRIMARY KEY, scope text NOT NULL, event json NOT NULL);
15
+ CREATE INDEX IF NOT EXISTS ${log}_scope ON ${log} (scope, position);`);
16
+ }
17
+ /**
18
+ * Positions come from one bigserial, so a reader could see position 11 commit before 10 and
19
+ * skip 10 for good. Each append therefore takes a transaction-scoped advisory lock on its
20
+ * scope before drawing any position, in the same statement: appends to one scope draw and
21
+ * commit one at a time, and the lock is released only after the commit is visible.
22
+ *
23
+ * `read` with `blockMs` polls every `pollMs` (default 100) until an entry arrives or the time is up.
24
+ */
25
+ export function postgresLog(client, options) {
26
+ const log = `${tablePrefix(options?.prefix, { lowercase: true })}log`;
27
+ const pollMs = options?.pollMs ?? 100;
28
+ const page = async (scope, after, limit) => {
29
+ const { rows } = await client.query(`SELECT position, event FROM ${log} WHERE scope = $1 AND position > $2 ORDER BY position LIMIT $3`, [
30
+ scope,
31
+ after === null ? '0' : parsePosition(after),
32
+ limit,
33
+ ]);
34
+ return rows.map((row) => ({ position: formatPosition(column(row, 'position')), event: parseEvent(column(row, 'event')) }));
35
+ };
36
+ return {
37
+ async append(scope, events) {
38
+ if (events.length === 0)
39
+ return;
40
+ await client.query(`WITH turn AS (SELECT pg_advisory_xact_lock(hashtext($1), hashtext($2)))
41
+ INSERT INTO ${log} (scope, event)
42
+ SELECT $2, e.event::json FROM turn, unnest($3::text[]) WITH ORDINALITY AS e(event, n) ORDER BY e.n`, [log, scope, events.map((event) => JSON.stringify(event))]);
43
+ },
44
+ async read(scope, after, { limit, blockMs }) {
45
+ const deadline = Date.now() + (blockMs ?? 0);
46
+ for (;;) {
47
+ const entries = await page(scope, after, limit);
48
+ const left = deadline - Date.now();
49
+ if (entries.length > 0 || left <= 0)
50
+ return entries;
51
+ await new Promise((resolve) => setTimeout(resolve, Math.min(pollMs, left)));
52
+ }
53
+ },
54
+ };
55
+ }
56
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { EventLog } from './types.js';
2
+ import type { RedisSend } from './store/redis.js';
3
+ export { redisStore } from './store/redis.js';
4
+ export type { RedisSend, RedisStoreOptions } from './store/redis.js';
5
+ export interface RedisOptions {
6
+ /** Prepended to every key. Default 'attend:'. */
7
+ prefix?: string;
8
+ }
9
+ /**
10
+ * One stream per scope. Positions are stream ids with both parts padded to twenty digits, so
11
+ * they compare as strings in read order; a raw id puts `…-10` before `…-9`.
12
+ *
13
+ * `read` waits with XREAD BLOCK only when `blockingSend` is given, because a blocked command
14
+ * holds its connection. Give each blocking reader a connection of its own. Without it, `read`
15
+ * returns at once and `logSource` paces the loop.
16
+ */
17
+ export declare function redisLog(send: RedisSend, options?: RedisOptions & {
18
+ blockingSend?: RedisSend;
19
+ }): EventLog;
20
+ //# sourceMappingURL=redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../src/redis.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrE,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG;IAAE,YAAY,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,QAAQ,CAiBzG"}
package/dist/redis.js ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * `attend/redis`: a ScopeStore and an EventLog over Redis 6.2 or later. Takes a function
3
+ * that sends one command and resolves with its reply, so importing this module loads no client:
4
+ *
5
+ * node-redis: (args) => client.sendCommand(args)
6
+ * ioredis: ([command, ...args]) => client.call(command, ...args)
7
+ *
8
+ * Replies are parsed whether the client hands back strings or Buffers, over RESP2 or RESP3.
9
+ * On Redis Cluster, put a hash tag in the prefix, such as 'attend:{app}:', so that every key a
10
+ * script touches lands in one slot.
11
+ */
12
+ import { boundary } from './internal/adapter.js';
13
+ export { redisStore } from './store/redis.js';
14
+ const { parseEvent, text } = boundary('attend/redis');
15
+ /** KEYS: stream. ARGV: event JSON, in order. */
16
+ const APPEND = `
17
+ for i = 1, #ARGV do redis.call('XADD', KEYS[1], '*', 'event', ARGV[i]) end
18
+ return #ARGV`;
19
+ /**
20
+ * One stream per scope. Positions are stream ids with both parts padded to twenty digits, so
21
+ * they compare as strings in read order; a raw id puts `…-10` before `…-9`.
22
+ *
23
+ * `read` waits with XREAD BLOCK only when `blockingSend` is given, because a blocked command
24
+ * holds its connection. Give each blocking reader a connection of its own. Without it, `read`
25
+ * returns at once and `logSource` paces the loop.
26
+ */
27
+ export function redisLog(send, options) {
28
+ const prefix = options?.prefix ?? 'attend:';
29
+ const blockingSend = options?.blockingSend;
30
+ const key = (scope) => `${prefix}log:${scope}`;
31
+ return {
32
+ async append(scope, events) {
33
+ if (events.length === 0)
34
+ return;
35
+ await send(['EVAL', APPEND, '1', key(scope), ...events.map((event) => JSON.stringify(event))]);
36
+ },
37
+ async read(scope, after, { limit, blockMs }) {
38
+ const stream = key(scope);
39
+ const entries = parseEntries(await send(['XRANGE', stream, after === null ? '-' : `(${streamId(after)}`, '+', 'COUNT', String(limit)]));
40
+ if (entries.length > 0 || blockingSend === undefined || blockMs === undefined || blockMs <= 0)
41
+ return entries;
42
+ const reply = await blockingSend(['XREAD', 'COUNT', String(limit), 'BLOCK', String(Math.ceil(blockMs)), 'STREAMS', stream, after === null ? '0-0' : streamId(after)]);
43
+ return reply === null || reply === undefined ? [] : parseEntries(onlyStream(reply));
44
+ },
45
+ };
46
+ }
47
+ function list(reply) {
48
+ if (!Array.isArray(reply))
49
+ throw new Error(`attend/redis: expected an array reply, got ${typeof reply}`);
50
+ return reply;
51
+ }
52
+ /** XREAD answers per stream: `[[key, entries]]` over RESP2, a map over RESP3, which clients decode as an object, a Map or a flat array. */
53
+ function onlyStream(reply) {
54
+ if (reply instanceof Map)
55
+ return [...reply.values()][0];
56
+ if (Array.isArray(reply))
57
+ return Array.isArray(reply[0]) ? list(reply[0])[1] : reply[1];
58
+ if (typeof reply === 'object' && reply !== null)
59
+ return Object.values(reply)[0];
60
+ throw new Error(`attend/redis: unexpected XREAD reply, got ${typeof reply}`);
61
+ }
62
+ function parseEntries(reply) {
63
+ return list(reply).map((item) => {
64
+ const [id, fields] = list(item);
65
+ const [name, value] = list(fields);
66
+ if (text(name) !== 'event')
67
+ throw new Error('attend/redis: corrupt log entry');
68
+ return { position: toPosition(text(id)), event: parseEvent(value) };
69
+ });
70
+ }
71
+ function toPosition(id) {
72
+ const [, ms, seq] = /^(\d{1,20})-(\d{1,20})$/.exec(id) ?? [];
73
+ if (ms === undefined || seq === undefined)
74
+ throw new Error(`attend/redis: expected a stream id, got "${id}"`);
75
+ return `${ms.padStart(20, '0')}-${seq.padStart(20, '0')}`;
76
+ }
77
+ function streamId(position) {
78
+ const [, ms, seq] = /^(\d{20})-(\d{20})$/.exec(position) ?? [];
79
+ if (ms === undefined || seq === undefined)
80
+ throw new Error(`attend/redis: not a position from this log: "${position}"`);
81
+ return `${BigInt(ms)}-${BigInt(seq)}`;
82
+ }
83
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../src/redis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { JsonObject } from '../core/types.js';
2
+ import type { EventsErrorObject } from './types.js';
3
+ export declare const ERROR_CODES: {
4
+ readonly InvalidParams: -32602;
5
+ readonly NotFound: -32023;
6
+ readonly Forbidden: -32024;
7
+ readonly ResourceExhausted: -32025;
8
+ readonly Unsupported: -32026;
9
+ readonly Transient: -32603;
10
+ };
11
+ export type EventsErrorName = keyof typeof ERROR_CODES;
12
+ export declare function eventsError(name: EventsErrorName, message: string, data?: JsonObject): EventsErrorObject;
13
+ //# sourceMappingURL=compat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.d.ts","sourceRoot":"","sources":["../../src/server/compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,eAAO,MAAM,WAAW;aAAK,aAAa,EAAE,CAAC,KAAK;aAAE,QAAQ,EAAE,CAAC,KAAK;aAAE,SAAS,EAAE,CAAC,KAAK;aAAE,iBAAiB,EAAE,CAAC,KAAK;aAAE,WAAW,EAAE,CAAC,KAAK;aAAE,SAAS,EAAE,CAAC,KAAK;CAAW,CAAC;AACtK,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,WAAW,CAAC;AAEvD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,iBAAiB,CAExG"}
@@ -0,0 +1,5 @@
1
+ export const ERROR_CODES = { InvalidParams: -32602, NotFound: -32023, Forbidden: -32024, ResourceExhausted: -32025, Unsupported: -32026, Transient: -32603 };
2
+ export function eventsError(name, message, data) {
3
+ throw new Error('attend: eventsError is not implemented');
4
+ }
5
+ //# sourceMappingURL=compat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.js","sourceRoot":"","sources":["../../src/server/compat.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,aAAa,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,KAAK,EAAW,CAAC;AAGtK,MAAM,UAAU,WAAW,CAAC,IAAqB,EAAE,OAAe,EAAE,IAAiB;IACnF,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { DecisionLog, DecisionPage, Position } from '../store/types.js';
2
+ import type { CursorParts } from './types.js';
3
+ /** Encodes a store position without interpreting it. */
4
+ export declare function encodeCursor(parts: CursorParts): string;
5
+ /** Null for a malformed cursor or one with another version prefix. */
6
+ export declare function decodeCursor(cursor: string): CursorParts | null;
7
+ /** Where a read starts: the head for a null cursor, the floor for another epoch or an empty position, else the cursor's own position. */
8
+ export declare function resolveStart(log: DecisionLog, epoch: string, cursor: string | null | undefined): Promise<{
9
+ after: Position | null;
10
+ truncated: boolean;
11
+ fromNow: boolean;
12
+ }>;
13
+ /** Whether rows past `after` were gone when `page` was read from it: below the retention floor, or decided before `sinceAt`. A page that found nothing past `after` needs no store call, since retention never drops the head. */
14
+ export declare function lostBefore(log: DecisionLog, after: Position | null, page: DecisionPage, sinceAt: number | undefined): Promise<boolean>;
15
+ //# sourceMappingURL=cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/server/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAGvD;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAI/D;AAED,yIAAyI;AACzI,wBAAsB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAShL;AAED,kOAAkO;AAClO,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAW5I"}
@@ -0,0 +1,50 @@
1
+ import { eventsError } from './events.js';
2
+ /** Encodes a store position without interpreting it. */
3
+ export function encodeCursor(parts) {
4
+ if (!parts.epoch || parts.epoch.includes('.'))
5
+ throw new TypeError('Invalid cursor epoch');
6
+ return `v1.${parts.epoch}.${parts.position}`;
7
+ }
8
+ /** Null for a malformed cursor or one with another version prefix. */
9
+ export function decodeCursor(cursor) {
10
+ if (!cursor.startsWith('v1.'))
11
+ return null;
12
+ const dot = cursor.indexOf('.', 3);
13
+ return dot > 3 ? { epoch: cursor.slice(3, dot), position: cursor.slice(dot + 1) } : null;
14
+ }
15
+ /** Where a read starts: the head for a null cursor, the floor for another epoch or an empty position, else the cursor's own position. */
16
+ export async function resolveStart(log, epoch, cursor) {
17
+ if (cursor == null)
18
+ return { after: (await log.bounds()).last, truncated: false, fromNow: true };
19
+ const invalid = () => eventsError('InvalidParams', 'Invalid cursor', { field: 'cursor', reason: 'malformed' });
20
+ const parts = decodeCursor(cursor);
21
+ if (!parts)
22
+ throw invalid();
23
+ if (parts.epoch !== epoch)
24
+ return { after: null, truncated: true, fromNow: false };
25
+ if (parts.position === '')
26
+ return { after: null, truncated: false, fromNow: false };
27
+ try {
28
+ log.compare(parts.position, parts.position);
29
+ }
30
+ catch {
31
+ throw invalid();
32
+ }
33
+ return { after: parts.position, truncated: false, fromNow: false };
34
+ }
35
+ /** Whether rows past `after` were gone when `page` was read from it: below the retention floor, or decided before `sinceAt`. A page that found nothing past `after` needs no store call, since retention never drops the head. */
36
+ export async function lostBefore(log, after, page, sinceAt) {
37
+ if (page.checked === null || (after !== null && log.compare(page.checked, after) === 0))
38
+ return false;
39
+ if (after !== null) {
40
+ const first = (await log.bounds()).first;
41
+ if (first !== null && log.compare(after, first) < 0)
42
+ return true;
43
+ }
44
+ if (sinceAt !== undefined) {
45
+ const row = (await log.read({ after, limit: 1 })).rows[0];
46
+ return row !== undefined && row.at < sinceAt;
47
+ }
48
+ return false;
49
+ }
50
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/server/cursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { JsonObject } from '../core/types.js';
2
+ import type { DecisionQuery, DecisionRow } from '../store/types.js';
3
+ import type { AttentionDeadLetterData, AttentionDecisionData, EventDescriptor, EventOccurrence, EventsErrorObject, Principal, SubscriptionFilter } from './types.js';
4
+ /** SEP-3415 error codes. */
5
+ export declare const ERROR_CODES: {
6
+ readonly InvalidParams: -32602;
7
+ readonly NotFound: -32023;
8
+ readonly Forbidden: -32024;
9
+ readonly ResourceExhausted: -32025;
10
+ readonly Unsupported: -32026;
11
+ readonly Transient: -32603;
12
+ };
13
+ /** A named SEP-3415 error. */
14
+ export type EventsErrorName = keyof typeof ERROR_CODES;
15
+ /** A JSON-RPC error the SDK sends verbatim: the SEP code, a message and typed data. */
16
+ export declare class EventsError extends Error implements EventsErrorObject {
17
+ readonly code: number;
18
+ readonly data?: JsonObject;
19
+ constructor(name: EventsErrorName, message: string, data?: JsonObject);
20
+ toJSON(): EventsErrorObject;
21
+ }
22
+ /** Makes an error the SDK can send without translation. */
23
+ export declare function eventsError(name: EventsErrorName, message: string, data?: JsonObject): EventsError;
24
+ /** Describes settled decisions delivered to an agent. */
25
+ export declare function decisionDescriptor(): EventDescriptor;
26
+ /** Describes windows whose judge or sink gave up. */
27
+ export declare function deadLetterDescriptor(): EventDescriptor;
28
+ /** Validates the event arguments and applies the principal's granted prefixes. */
29
+ export declare function compileFilter(name: string, args: unknown, principal: Principal): SubscriptionFilter;
30
+ /** Checks the row against every subscription constraint. */
31
+ export declare function matches(filter: SubscriptionFilter, row: DecisionRow): boolean;
32
+ /** The store-side part of a filter, for `DecisionLog.read`. */
33
+ export declare function queryFor(filter: SubscriptionFilter): Pick<DecisionQuery, 'scope' | 'scopePrefix' | 'kinds' | 'routes'>;
34
+ /** Parses an events/poll or events/stream request's subscription part; throws an EventsError. */
35
+ export declare function parseSubscription(params: unknown, principal: Principal): {
36
+ filter: SubscriptionFilter;
37
+ cursor: string | null;
38
+ maxAgeMs: number | undefined;
39
+ };
40
+ /** Builds a detached payload; large windows carry an omission marker. */
41
+ export declare function occurrenceFor(row: DecisionRow, include: 'notice' | 'events', maxEventsBytes?: number): EventOccurrence<AttentionDecisionData | AttentionDeadLetterData>;
42
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/server/events.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEpE,OAAO,KAAK,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErK,4BAA4B;AAC5B,eAAO,MAAM,WAAW;aAAK,aAAa,EAAE,CAAC,KAAK;aAAE,QAAQ,EAAE,CAAC,KAAK;aAAE,SAAS,EAAE,CAAC,KAAK;aAAE,iBAAiB,EAAE,CAAC,KAAK;aAAE,WAAW,EAAE,CAAC,KAAK;aAAE,SAAS,EAAE,CAAC,KAAK;CAAW,CAAC;AACtK,8BAA8B;AAC9B,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,WAAW,CAAC;AAEvD,uFAAuF;AACvF,qBAAa,WAAY,SAAQ,KAAM,YAAW,iBAAiB;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAE3B,YAAY,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,EAKpE;IAED,MAAM,IAAI,iBAAiB,CAE1B;CACF;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,WAAW,CAElG;AAUD,yDAAyD;AACzD,wBAAgB,kBAAkB,IAAI,eAAe,CAsBpD;AAED,qDAAqD;AACrD,wBAAgB,oBAAoB,IAAI,eAAe,CAatD;AAcD,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,kBAAkB,CA6BnG;AAED,4DAA4D;AAC5D,wBAAgB,OAAO,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAO7E;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC,aAAa,EAAE,OAAO,GAAG,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAC,CAOtH;AAED,iGAAiG;AACjG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAO5J;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,GAAG,QAAQ,EAAE,cAAc,SAAY,GAAG,eAAe,CAAC,qBAAqB,GAAG,uBAAuB,CAAC,CAuB1K"}
@@ -0,0 +1,189 @@
1
+ import { defaultNotice } from '../attend.js';
2
+ import { DECISION_EVENT, DEAD_LETTER_EVENT } from './types.js';
3
+ /** SEP-3415 error codes. */
4
+ export const ERROR_CODES = { InvalidParams: -32602, NotFound: -32023, Forbidden: -32024, ResourceExhausted: -32025, Unsupported: -32026, Transient: -32603 };
5
+ /** A JSON-RPC error the SDK sends verbatim: the SEP code, a message and typed data. */
6
+ export class EventsError extends Error {
7
+ code;
8
+ data;
9
+ constructor(name, message, data) {
10
+ super(message);
11
+ this.name = 'EventsError';
12
+ this.code = ERROR_CODES[name];
13
+ if (data !== undefined)
14
+ this.data = data;
15
+ }
16
+ toJSON() {
17
+ return { code: this.code, message: this.message, ...(this.data === undefined ? {} : { data: this.data }) };
18
+ }
19
+ }
20
+ /** Makes an error the SDK can send without translation. */
21
+ export function eventsError(name, message, data) {
22
+ return new EventsError(name, message, data);
23
+ }
24
+ const routes = ['interrupt', 'queue', 'note', 'ask'];
25
+ const bits = { interrupt: 1, queue: 2, note: 4, ask: 8 };
26
+ const reasons = ['closing', 'flush', 'stream_quiet', 'passive_quiet', 'overflow', 'age', 'forced', 'size'];
27
+ const scopeProperties = {
28
+ scope: { type: 'string', description: 'Exactly this scope.' },
29
+ scopePrefix: { type: 'string', description: 'Every scope that starts with this. Omit both scope and scopePrefix for every scope the principal may read.' },
30
+ };
31
+ /** Describes settled decisions delivered to an agent. */
32
+ export function decisionDescriptor() {
33
+ return {
34
+ name: DECISION_EVENT,
35
+ description: 'A settled window of events that a judge routed to the agent: interrupt, queue, note or ask. One occurrence per decision; skip is never emitted.',
36
+ delivery: ['poll', 'push'],
37
+ inputSchema: {
38
+ type: 'object', additionalProperties: false,
39
+ properties: { ...scopeProperties, routes: { type: 'array', items: { enum: [...routes] }, uniqueItems: true }, minProbability: { type: 'number', minimum: 0, maximum: 1 }, include: { enum: ['notice', 'events'], default: 'notice' } },
40
+ not: { required: ['scope', 'scopePrefix'] },
41
+ },
42
+ payloadSchema: {
43
+ type: 'object',
44
+ required: ['decisionId', 'scope', 'route', 'probabilities', 'predicates', 'confidence', 'reason', 'settledAt', 'decidedAt', 'eventCount', 'eventIds', 'dropped', 'gap', 'waits', 'notice'],
45
+ properties: {
46
+ decisionId: { type: 'string' }, scope: { type: 'string' }, route: { enum: [...routes] },
47
+ probabilities: { type: 'object', additionalProperties: { type: 'number' } }, predicates: { type: 'object', additionalProperties: { type: 'number' } },
48
+ confidence: { type: ['number', 'null'] }, reason: { enum: [...reasons] },
49
+ settledAt: { type: 'string', format: 'date-time' }, decidedAt: { type: 'string', format: 'date-time' },
50
+ eventCount: { type: 'integer' }, eventIds: { type: 'array', items: { type: 'string' } }, dropped: { type: 'integer' }, gap: { type: 'boolean' }, waits: { type: 'integer' }, notice: { type: 'string' }, events: { type: 'array', items: { type: 'object' } },
51
+ },
52
+ },
53
+ };
54
+ }
55
+ /** Describes windows whose judge or sink gave up. */
56
+ export function deadLetterDescriptor() {
57
+ return {
58
+ name: DEAD_LETTER_EVENT,
59
+ description: 'A window no judge or sink could take: the judge gave up (stage judge) or the sink did (stage sink).',
60
+ delivery: ['poll', 'push'],
61
+ inputSchema: { type: 'object', additionalProperties: false, properties: { ...scopeProperties, stage: { enum: ['judge', 'sink'] } }, not: { required: ['scope', 'scopePrefix'] } },
62
+ payloadSchema: {
63
+ type: 'object', required: ['letterId', 'scope', 'stage', 'message', 'permanent', 'attempts', 'decisionId', 'route', 'reason', 'eventCount', 'eventIds', 'at'],
64
+ properties: {
65
+ letterId: { type: 'string' }, scope: { type: 'string' }, stage: { enum: ['judge', 'sink'] }, message: { type: 'string' }, permanent: { type: 'boolean' }, attempts: { type: 'integer' }, decisionId: { type: ['string', 'null'] }, route: { enum: [...routes, null] }, reason: { enum: [...reasons] }, eventCount: { type: 'integer' }, eventIds: { type: 'array', items: { type: 'string' } }, at: { type: 'string', format: 'date-time' },
66
+ },
67
+ },
68
+ };
69
+ }
70
+ function object(value) {
71
+ return typeof value === 'object' && value !== null && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
72
+ }
73
+ function invalid(field, reason) {
74
+ throw eventsError('InvalidParams', `Invalid ${field}: ${reason}`, { field, reason });
75
+ }
76
+ function delivered(value) {
77
+ return value === 'interrupt' || value === 'queue' || value === 'note' || value === 'ask';
78
+ }
79
+ /** Validates the event arguments and applies the principal's granted prefixes. */
80
+ export function compileFilter(name, args, principal) {
81
+ if (name !== DECISION_EVENT && name !== DEAD_LETTER_EVENT)
82
+ throw eventsError('NotFound', 'Unknown event', { kind: 'event' });
83
+ const value = args === undefined ? {} : args;
84
+ if (!object(value))
85
+ invalid('arguments', 'must be an object');
86
+ const allowed = name === DECISION_EVENT ? ['scope', 'scopePrefix', 'routes', 'minProbability', 'include'] : ['scope', 'scopePrefix', 'stage'];
87
+ for (const key of Object.keys(value))
88
+ if (!allowed.includes(key))
89
+ invalid(`arguments.${key}`, 'unknown');
90
+ for (const key of ['scope', 'scopePrefix'])
91
+ if (key in value && typeof value[key] !== 'string')
92
+ invalid(`arguments.${key}`, 'must be a string');
93
+ if ('scope' in value && 'scopePrefix' in value)
94
+ invalid('arguments', 'scope and scopePrefix are exclusive');
95
+ let mask = 15;
96
+ if ('routes' in value) {
97
+ if (!Array.isArray(value.routes) || !value.routes.every(delivered) || new Set(value.routes).size !== value.routes.length)
98
+ invalid('arguments.routes', 'must be unique delivered routes');
99
+ mask = value.routes.reduce((sum, route) => sum | bits[route], 0);
100
+ }
101
+ if ('minProbability' in value && (typeof value.minProbability !== 'number' || !Number.isFinite(value.minProbability) || value.minProbability < 0 || value.minProbability > 1))
102
+ invalid('arguments.minProbability', 'must be a finite number between 0 and 1');
103
+ if ('include' in value && value.include !== 'notice' && value.include !== 'events')
104
+ invalid('arguments.include', 'must be notice or events');
105
+ if ('stage' in value && value.stage !== 'judge' && value.stage !== 'sink')
106
+ invalid('arguments.stage', 'must be judge or sink');
107
+ const filter = { name, routes: mask, minProbability: typeof value.minProbability === 'number' ? value.minProbability : 0, include: value.include === 'events' ? 'events' : 'notice' };
108
+ if (typeof value.scope === 'string')
109
+ filter.scope = value.scope;
110
+ if (typeof value.scopePrefix === 'string')
111
+ filter.scopePrefix = value.scopePrefix;
112
+ if (value.stage === 'judge' || value.stage === 'sink')
113
+ filter.stage = value.stage;
114
+ const requested = filter.scope ?? filter.scopePrefix;
115
+ if (principal.scopes.length === 0 || (requested !== undefined && !principal.scopes.some((grant) => requested.startsWith(grant)))) {
116
+ throw eventsError('Forbidden', 'Scope is outside the principal grants', { reason: 'scope is outside granted prefixes' });
117
+ }
118
+ if (requested === undefined && !principal.scopes.includes('')) {
119
+ if (principal.scopes.length === 1)
120
+ filter.scopePrefix = principal.scopes[0];
121
+ else
122
+ filter.grants = [...principal.scopes];
123
+ }
124
+ return filter;
125
+ }
126
+ /** Checks the row against every subscription constraint. */
127
+ export function matches(filter, row) {
128
+ if ((row.kind === 'decision' ? DECISION_EVENT : DEAD_LETTER_EVENT) !== filter.name)
129
+ return false;
130
+ if (filter.scope !== undefined && row.scope !== filter.scope)
131
+ return false;
132
+ if (filter.scopePrefix !== undefined && !row.scope.startsWith(filter.scopePrefix))
133
+ return false;
134
+ if (filter.grants && !filter.grants.some((grant) => row.scope.startsWith(grant)))
135
+ return false;
136
+ if (row.kind === 'deadLetter')
137
+ return filter.stage === undefined || row.body.stage === filter.stage;
138
+ return row.route !== null && (filter.routes & bits[row.body.route]) !== 0 && row.body.probabilities[row.body.route] >= filter.minProbability;
139
+ }
140
+ /** The store-side part of a filter, for `DecisionLog.read`. */
141
+ export function queryFor(filter) {
142
+ return {
143
+ kinds: [filter.name === DECISION_EVENT ? 'decision' : 'deadLetter'],
144
+ ...(filter.scope === undefined ? {} : { scope: filter.scope }),
145
+ ...(filter.scopePrefix === undefined ? {} : { scopePrefix: filter.scopePrefix }),
146
+ ...(filter.routes === 15 ? {} : { routes: routes.filter((route) => (filter.routes & bits[route]) !== 0) }),
147
+ };
148
+ }
149
+ /** Parses an events/poll or events/stream request's subscription part; throws an EventsError. */
150
+ export function parseSubscription(params, principal) {
151
+ if (!object(params))
152
+ invalid('params', 'must be an object');
153
+ if (typeof params.name !== 'string')
154
+ invalid('name', 'required');
155
+ const filter = compileFilter(params.name, params.arguments, principal);
156
+ if (params.cursor !== undefined && params.cursor !== null && typeof params.cursor !== 'string')
157
+ invalid('cursor', 'must be a string or null');
158
+ if (params.maxAgeMs !== undefined && (typeof params.maxAgeMs !== 'number' || !Number.isSafeInteger(params.maxAgeMs) || params.maxAgeMs < 0))
159
+ invalid('maxAgeMs', 'must be a non-negative safe integer');
160
+ return { filter, cursor: params.cursor ?? null, maxAgeMs: params.maxAgeMs };
161
+ }
162
+ /** Builds a detached payload; large windows carry an omission marker. */
163
+ export function occurrenceFor(row, include, maxEventsBytes = 1_048_576) {
164
+ const body = row.body;
165
+ const w = body.window;
166
+ if (row.kind === 'deadLetter') {
167
+ const letter = row.body;
168
+ return { eventId: row.id, name: DEAD_LETTER_EVENT, timestamp: new Date(letter.at).toISOString(), data: {
169
+ letterId: letter.id, scope: letter.scope, stage: letter.stage, message: letter.message, permanent: letter.permanent, attempts: letter.attempts,
170
+ decisionId: letter.decision?.id ?? null, route: letter.decision?.route ?? null, reason: w.reason, eventCount: w.events.length, eventIds: w.events.map((e) => e.id), at: new Date(letter.at).toISOString(),
171
+ } };
172
+ }
173
+ const decision = row.body;
174
+ const data = {
175
+ decisionId: decision.id, scope: decision.scope, route: decision.route, probabilities: { ...decision.probabilities }, predicates: { ...decision.predicates }, confidence: decision.confidence,
176
+ reason: w.reason, settledAt: new Date(w.settledAt).toISOString(), decidedAt: new Date(decision.at).toISOString(), eventCount: w.events.length, eventIds: w.events.map((e) => e.id), dropped: w.dropped, gap: w.gap, waits: w.waits,
177
+ notice: defaultNotice(decision),
178
+ };
179
+ const occurrence = { eventId: row.id, name: DECISION_EVENT, timestamp: new Date(decision.at).toISOString(), data };
180
+ if (include === 'events') {
181
+ const json = JSON.stringify(w.events);
182
+ if (new TextEncoder().encode(json).length <= maxEventsBytes)
183
+ data.events = JSON.parse(json);
184
+ else
185
+ occurrence._meta = { 'attend/eventsOmitted': true };
186
+ }
187
+ return occurrence;
188
+ }
189
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/server/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { DecisionLog, DecisionPage, DecisionRow, Position } from '../store/types.js';
2
+ import { type StreamNotification, type SubscriptionFilter } from './types.js';
3
+ interface Subscriber {
4
+ filter: SubscriptionFilter;
5
+ row: (row: DecisionRow) => void;
6
+ change?: () => void;
7
+ error?: (error: unknown) => void;
8
+ gap?: () => void;
9
+ }
10
+ export interface Fanout {
11
+ subscribe(filter: SubscriptionFilter, onRow: (row: DecisionRow) => void, hooks?: Pick<Subscriber, 'change' | 'error' | 'gap'>): () => void;
12
+ checked(): Position | null;
13
+ /** Resolves once the reader knows where it starts, so a stream can tell which rows it missed. */
14
+ readonly ready: Promise<void>;
15
+ cached(after: Position | null): DecisionPage | null;
16
+ readonly size: number;
17
+ close(): void;
18
+ }
19
+ /** Encodes notifications once; event payload bytes are shared across subscribers. */
20
+ export declare function notificationJSON(notification: StreamNotification): string;
21
+ /** Splices a subscription's envelope around the shared row payload. */
22
+ export declare function eventNotification(row: DecisionRow, filter: SubscriptionFilter, maxBytes: number | undefined, epoch: string, id: string | number): Extract<StreamNotification, {
23
+ method: 'notifications/events/event';
24
+ }>;
25
+ /** The process's tail cache and indexed, nonblocking subscription reader. */
26
+ export declare function createFanout(log: DecisionLog): Fanout;
27
+ export {};
28
+ //# sourceMappingURL=fanout.d.ts.map