airlock-bot 0.2.36 → 0.2.38

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 (243) hide show
  1. package/README.md +34 -7
  2. package/dist/activity/stream.d.ts +29 -0
  3. package/dist/activity/stream.d.ts.map +1 -0
  4. package/dist/activity/stream.js +36 -0
  5. package/dist/activity/stream.js.map +1 -0
  6. package/dist/airlock/context.d.ts +12 -0
  7. package/dist/airlock/context.d.ts.map +1 -0
  8. package/dist/airlock/context.js +32 -0
  9. package/dist/airlock/context.js.map +1 -0
  10. package/dist/airlock/tools.d.ts +7 -0
  11. package/dist/airlock/tools.d.ts.map +1 -0
  12. package/dist/airlock/tools.js +13 -0
  13. package/dist/airlock/tools.js.map +1 -0
  14. package/dist/allowlist/engine.d.ts +12 -0
  15. package/dist/allowlist/engine.d.ts.map +1 -1
  16. package/dist/allowlist/engine.js +40 -15
  17. package/dist/allowlist/engine.js.map +1 -1
  18. package/dist/audit/api.d.ts +2 -0
  19. package/dist/audit/api.d.ts.map +1 -1
  20. package/dist/audit/api.js.map +1 -1
  21. package/dist/audit/db.d.ts +16 -0
  22. package/dist/audit/db.d.ts.map +1 -1
  23. package/dist/audit/db.js +73 -0
  24. package/dist/audit/db.js.map +1 -1
  25. package/dist/audit/logger.d.ts +8 -1
  26. package/dist/audit/logger.d.ts.map +1 -1
  27. package/dist/audit/logger.js +21 -0
  28. package/dist/audit/logger.js.map +1 -1
  29. package/dist/backend/airlock-adapter.d.ts +22 -0
  30. package/dist/backend/airlock-adapter.d.ts.map +1 -0
  31. package/dist/backend/airlock-adapter.js +136 -0
  32. package/dist/backend/airlock-adapter.js.map +1 -0
  33. package/dist/backend/factory.d.ts +5 -1
  34. package/dist/backend/factory.d.ts.map +1 -1
  35. package/dist/backend/factory.js +5 -5
  36. package/dist/backend/factory.js.map +1 -1
  37. package/dist/backend/mcp-adapter.d.ts.map +1 -1
  38. package/dist/backend/mcp-adapter.js +28 -4
  39. package/dist/backend/mcp-adapter.js.map +1 -1
  40. package/dist/backend/openapi/adapter.d.ts.map +1 -1
  41. package/dist/backend/openapi/adapter.js +33 -13
  42. package/dist/backend/openapi/adapter.js.map +1 -1
  43. package/dist/config/loader.d.ts +12 -1
  44. package/dist/config/loader.d.ts.map +1 -1
  45. package/dist/config/loader.js +799 -23
  46. package/dist/config/loader.js.map +1 -1
  47. package/dist/config/profiles.d.ts +46 -8
  48. package/dist/config/profiles.d.ts.map +1 -1
  49. package/dist/config/profiles.js +367 -23
  50. package/dist/config/profiles.js.map +1 -1
  51. package/dist/config/schema.d.ts +3542 -174
  52. package/dist/config/schema.d.ts.map +1 -1
  53. package/dist/config/schema.js +292 -63
  54. package/dist/config/schema.js.map +1 -1
  55. package/dist/configure-web/cli.d.ts +13 -0
  56. package/dist/configure-web/cli.d.ts.map +1 -1
  57. package/dist/configure-web/cli.js +570 -80
  58. package/dist/configure-web/cli.js.map +1 -1
  59. package/dist/gateway.d.ts +16 -1
  60. package/dist/gateway.d.ts.map +1 -1
  61. package/dist/gateway.js +263 -57
  62. package/dist/gateway.js.map +1 -1
  63. package/dist/hitl/api.d.ts +2 -0
  64. package/dist/hitl/api.d.ts.map +1 -1
  65. package/dist/hitl/api.js +8 -0
  66. package/dist/hitl/api.js.map +1 -1
  67. package/dist/hitl/approval-dashboard.d.ts +5 -9
  68. package/dist/hitl/approval-dashboard.d.ts.map +1 -1
  69. package/dist/hitl/approval-dashboard.js +8 -55
  70. package/dist/hitl/approval-dashboard.js.map +1 -1
  71. package/dist/hitl/approval-stream.d.ts +34 -0
  72. package/dist/hitl/approval-stream.d.ts.map +1 -0
  73. package/dist/hitl/approval-stream.js +111 -0
  74. package/dist/hitl/approval-stream.js.map +1 -0
  75. package/dist/hitl/engine.d.ts +16 -7
  76. package/dist/hitl/engine.d.ts.map +1 -1
  77. package/dist/hitl/engine.js +109 -35
  78. package/dist/hitl/engine.js.map +1 -1
  79. package/dist/hitl/formatter.d.ts.map +1 -1
  80. package/dist/hitl/formatter.js +2 -0
  81. package/dist/hitl/formatter.js.map +1 -1
  82. package/dist/hitl/provider-factory.d.ts +8 -2
  83. package/dist/hitl/provider-factory.d.ts.map +1 -1
  84. package/dist/hitl/provider-factory.js +23 -2
  85. package/dist/hitl/provider-factory.js.map +1 -1
  86. package/dist/hitl/providers/composite.d.ts +9 -0
  87. package/dist/hitl/providers/composite.d.ts.map +1 -1
  88. package/dist/hitl/providers/composite.js +14 -0
  89. package/dist/hitl/providers/composite.js.map +1 -1
  90. package/dist/hitl/providers/dashboard.d.ts +12 -2
  91. package/dist/hitl/providers/dashboard.d.ts.map +1 -1
  92. package/dist/hitl/providers/dashboard.js +11 -5
  93. package/dist/hitl/providers/dashboard.js.map +1 -1
  94. package/dist/hitl/providers/ios.d.ts +23 -0
  95. package/dist/hitl/providers/ios.d.ts.map +1 -0
  96. package/dist/hitl/providers/ios.js +183 -0
  97. package/dist/hitl/providers/ios.js.map +1 -0
  98. package/dist/hitl/providers/macos.d.ts.map +1 -1
  99. package/dist/hitl/providers/macos.js +8 -4
  100. package/dist/hitl/providers/macos.js.map +1 -1
  101. package/dist/hitl/providers/openclaw.js +2 -2
  102. package/dist/hitl/providers/openclaw.js.map +1 -1
  103. package/dist/hitl/providers/stdio.js +2 -2
  104. package/dist/hitl/providers/stdio.js.map +1 -1
  105. package/dist/hitl/providers/telegram.js +2 -2
  106. package/dist/hitl/providers/telegram.js.map +1 -1
  107. package/dist/hitl/providers/tui.d.ts.map +1 -1
  108. package/dist/hitl/providers/tui.js +8 -2
  109. package/dist/hitl/providers/tui.js.map +1 -1
  110. package/dist/hitl/providers/types.d.ts +14 -0
  111. package/dist/hitl/providers/types.d.ts.map +1 -1
  112. package/dist/hook/api.d.ts +2 -0
  113. package/dist/hook/api.d.ts.map +1 -1
  114. package/dist/hook/api.js.map +1 -1
  115. package/dist/hook/normalizer.js +2 -2
  116. package/dist/hook/normalizer.js.map +1 -1
  117. package/dist/index.js +28 -1
  118. package/dist/index.js.map +1 -1
  119. package/dist/introspect/cli.d.ts +31 -0
  120. package/dist/introspect/cli.d.ts.map +1 -0
  121. package/dist/introspect/cli.js +756 -0
  122. package/dist/introspect/cli.js.map +1 -0
  123. package/dist/middleware/chain-builder.d.ts +1 -1
  124. package/dist/middleware/chain-builder.d.ts.map +1 -1
  125. package/dist/middleware/chain-builder.js +8 -4
  126. package/dist/middleware/chain-builder.js.map +1 -1
  127. package/dist/middleware/core/allowlist.d.ts.map +1 -1
  128. package/dist/middleware/core/allowlist.js +14 -0
  129. package/dist/middleware/core/allowlist.js.map +1 -1
  130. package/dist/middleware/core/arg-policy.d.ts +13 -0
  131. package/dist/middleware/core/arg-policy.d.ts.map +1 -0
  132. package/dist/middleware/core/arg-policy.js +201 -0
  133. package/dist/middleware/core/arg-policy.js.map +1 -0
  134. package/dist/middleware/core/exec-policy.d.ts.map +1 -1
  135. package/dist/middleware/core/exec-policy.js +16 -1
  136. package/dist/middleware/core/exec-policy.js.map +1 -1
  137. package/dist/middleware/core/execute.d.ts.map +1 -1
  138. package/dist/middleware/core/execute.js +6 -2
  139. package/dist/middleware/core/execute.js.map +1 -1
  140. package/dist/middleware/core/hitl-gate.d.ts.map +1 -1
  141. package/dist/middleware/core/hitl-gate.js +15 -4
  142. package/dist/middleware/core/hitl-gate.js.map +1 -1
  143. package/dist/middleware/core/schema-validator.d.ts.map +1 -1
  144. package/dist/middleware/core/schema-validator.js +7 -3
  145. package/dist/middleware/core/schema-validator.js.map +1 -1
  146. package/dist/middleware/post/canary-token-injector.d.ts +4 -1
  147. package/dist/middleware/post/canary-token-injector.d.ts.map +1 -1
  148. package/dist/middleware/post/canary-token-injector.js +5 -1
  149. package/dist/middleware/post/canary-token-injector.js.map +1 -1
  150. package/dist/middleware/post/untrusted-envelope.d.ts.map +1 -1
  151. package/dist/middleware/post/untrusted-envelope.js +7 -1
  152. package/dist/middleware/post/untrusted-envelope.js.map +1 -1
  153. package/dist/mobile/api.d.ts +20 -0
  154. package/dist/mobile/api.d.ts.map +1 -0
  155. package/dist/mobile/api.js +255 -0
  156. package/dist/mobile/api.js.map +1 -0
  157. package/dist/mobile/apns.d.ts +68 -0
  158. package/dist/mobile/apns.d.ts.map +1 -0
  159. package/dist/mobile/apns.js +321 -0
  160. package/dist/mobile/apns.js.map +1 -0
  161. package/dist/pool/http-client.d.ts +3 -1
  162. package/dist/pool/http-client.d.ts.map +1 -1
  163. package/dist/pool/http-client.js +5 -2
  164. package/dist/pool/http-client.js.map +1 -1
  165. package/dist/pool/oauth-provider.d.ts +2 -0
  166. package/dist/pool/oauth-provider.d.ts.map +1 -1
  167. package/dist/pool/oauth-provider.js +23 -4
  168. package/dist/pool/oauth-provider.js.map +1 -1
  169. package/dist/pool/pool.d.ts +2 -1
  170. package/dist/pool/pool.d.ts.map +1 -1
  171. package/dist/pool/pool.js +2 -2
  172. package/dist/pool/pool.js.map +1 -1
  173. package/dist/pool/sse-client.d.ts +3 -1
  174. package/dist/pool/sse-client.d.ts.map +1 -1
  175. package/dist/pool/sse-client.js +5 -2
  176. package/dist/pool/sse-client.js.map +1 -1
  177. package/dist/pool/stdio-client.d.ts +3 -1
  178. package/dist/pool/stdio-client.d.ts.map +1 -1
  179. package/dist/pool/stdio-client.js +5 -2
  180. package/dist/pool/stdio-client.js.map +1 -1
  181. package/dist/registry/airlock-policy.d.ts +3 -0
  182. package/dist/registry/airlock-policy.d.ts.map +1 -0
  183. package/dist/registry/airlock-policy.js +50 -0
  184. package/dist/registry/airlock-policy.js.map +1 -0
  185. package/dist/registry/registry.d.ts +2 -0
  186. package/dist/registry/registry.d.ts.map +1 -1
  187. package/dist/registry/registry.js +19 -13
  188. package/dist/registry/registry.js.map +1 -1
  189. package/dist/security/blocked-hosts.d.ts +2 -0
  190. package/dist/security/blocked-hosts.d.ts.map +1 -1
  191. package/dist/security/blocked-hosts.js +61 -7
  192. package/dist/security/blocked-hosts.js.map +1 -1
  193. package/dist/security/request.d.ts +2 -0
  194. package/dist/security/request.d.ts.map +1 -1
  195. package/dist/security/request.js +6 -2
  196. package/dist/security/request.js.map +1 -1
  197. package/dist/security/secrets.d.ts +12 -0
  198. package/dist/security/secrets.d.ts.map +1 -0
  199. package/dist/security/secrets.js +138 -0
  200. package/dist/security/secrets.js.map +1 -0
  201. package/dist/setup-openclaw/cli.js +1 -1
  202. package/dist/stdio-mode.d.ts.map +1 -1
  203. package/dist/stdio-mode.js +125 -24
  204. package/dist/stdio-mode.js.map +1 -1
  205. package/dist/tools/api.d.ts +4 -1
  206. package/dist/tools/api.d.ts.map +1 -1
  207. package/dist/tools/api.js +58 -7
  208. package/dist/tools/api.js.map +1 -1
  209. package/dist/tools/exec.d.ts +2 -1
  210. package/dist/tools/exec.d.ts.map +1 -1
  211. package/dist/tools/exec.js +4 -3
  212. package/dist/tools/exec.js.map +1 -1
  213. package/dist/tools/http.d.ts.map +1 -1
  214. package/dist/tools/http.js +4 -7
  215. package/dist/tools/http.js.map +1 -1
  216. package/dist/transport/agent-server.d.ts +4 -0
  217. package/dist/transport/agent-server.d.ts.map +1 -1
  218. package/dist/transport/agent-server.js +23 -11
  219. package/dist/transport/agent-server.js.map +1 -1
  220. package/dist/transport/http-server.d.ts +2 -0
  221. package/dist/transport/http-server.d.ts.map +1 -1
  222. package/dist/transport/http-server.js +10 -6
  223. package/dist/transport/http-server.js.map +1 -1
  224. package/dist/transport/sse-server.d.ts +2 -0
  225. package/dist/transport/sse-server.d.ts.map +1 -1
  226. package/dist/transport/sse-server.js +10 -6
  227. package/dist/transport/sse-server.js.map +1 -1
  228. package/dist/transport/stdio-server.d.ts.map +1 -1
  229. package/dist/transport/stdio-server.js +4 -0
  230. package/dist/transport/stdio-server.js.map +1 -1
  231. package/dist/util/id.d.ts +1 -1
  232. package/dist/util/id.d.ts.map +1 -1
  233. package/dist/util/id.js +3 -3
  234. package/dist/util/id.js.map +1 -1
  235. package/examples/claude-code-setup.md +0 -2
  236. package/examples/docker-compose.yaml +4 -3
  237. package/examples/docker-gateway.yaml +8 -3
  238. package/examples/gateway.yaml +8 -5
  239. package/examples/profiles.yaml +4 -4
  240. package/extensions/openclaw/index.ts +9 -6
  241. package/extensions/openclaw/openclaw.plugin.json +5 -5
  242. package/package.json +3 -1
  243. package/schema.json +658 -8
package/README.md CHANGED
@@ -184,7 +184,7 @@ apis:
184
184
  Interactively assign allow/ask/deny to tools discovered from your live MCP servers:
185
185
 
186
186
  ```bash
187
- npm run configure-agent -- --config ./airlock.yaml --agent claude-code
187
+ airlock configure-agent --config ./airlock.yaml --agent claude-code
188
188
  ```
189
189
 
190
190
  Navigate with `j/k`, set permissions with `a`/`s`/`d` (per tool or bulk per provider), then `Enter` to edit config directly, copy to clipboard, or print YAML.
@@ -263,7 +263,6 @@ agents:
263
263
  extends: [readonly]
264
264
  exec:
265
265
  allow: ['git status', 'git diff*', 'npm test']
266
- deny: ['*']
267
266
 
268
267
  approvals:
269
268
  provider:
@@ -415,7 +414,7 @@ See [`examples/sandbox-presets.yaml`](examples/sandbox-presets.yaml) for a fulle
415
414
  | --------------- | ------------- | ------------------------------------------------------------------------------------------------- |
416
415
  | TUI | `tui` | Terminal UI on stderr — `[a]pprove` / `[d]eny` with `j/k` navigation via `/dev/tty` |
417
416
  | macOS dialog | `macos` | Native approve/deny popup via `osascript` — best for local dev on Mac |
418
- | Dashboard | `dashboard` | Localhost web UI (default port 4112) with live SSE updates |
417
+ | Dashboard | `dashboard` | Browser UI with live SSE updates; runs in-process or as a standalone admin dashboard |
419
418
  | Telegram bot | `telegram` | Long-polls for replies; reply `approve ABC123` or `deny ABC123` |
420
419
  | Slack webhook | `slack` | Incoming webhook, fire-and-forget; pair with slash commands for approvals |
421
420
  | Generic webhook | `webhook` | POSTs `{requests, text}` JSON; configurable headers |
@@ -424,17 +423,39 @@ See [`examples/sandbox-presets.yaml`](examples/sandbox-presets.yaml) for a fulle
424
423
 
425
424
  ## API
426
425
 
427
- When running in gateway mode, Airlock exposes a management API:
426
+ When running in gateway mode, Airlock can expose a separate management API
427
+ listener for operator/control-plane routes. It is disabled by default and binds
428
+ to `127.0.0.1:4113` when enabled:
429
+
430
+ ```yaml
431
+ server:
432
+ api_secret: ${AIRLOCK_API_SECRET}
433
+ management_api:
434
+ enabled: true
435
+ api_secret: ${MANAGEMENT_API_SECRET}
436
+ ```
428
437
 
429
438
  ```
430
439
  GET /health — MCP health, pending HITL count, uptime
431
440
  GET /hitl/pending — list pending approval requests
432
- POST /hitl/approve/:id — approve a request
433
- POST /hitl/deny/:id — deny a request (body: {"reason": "..."})
441
+ POST /hitl/approve/:id — approve a request by canonical approval ID
442
+ POST /hitl/deny/:id — deny by canonical approval ID (body: {"reason": "..."})
434
443
  GET /audit?agent=&tool=&since=&limit= — query audit log
444
+ GET /events — dashboard approval event stream
445
+ POST /approve?code=ABC123 — approve via manual-entry approval code
446
+ POST /deny?code=ABC123 — deny via manual-entry approval code
447
+ GET /admin/tools — dashboard tool catalog
435
448
  ```
436
449
 
437
- All management endpoints require `Authorization: Bearer <api_secret>` when `server.api_secret` is set.
450
+ All management endpoints require `Authorization: Bearer <management_api.api_secret>`.
451
+ If `management_api.api_secret` is unset, Airlock temporarily falls back to
452
+ `server.api_secret` and emits a deprecation warning so existing deployments keep
453
+ working while operators split the control-plane secret from the data-plane
454
+ fallback.
455
+ The management listener must use a different port than the agent MCP
456
+ data-plane listener (`server.port`, default `4111`). Binding the management API
457
+ beyond loopback requires the explicit `management_api.insecure_remote_bind: true`
458
+ opt-in and trusted network controls.
438
459
 
439
460
  ## Testing
440
461
 
@@ -471,15 +492,21 @@ Airlock can also run as a containerized gateway:
471
492
 
472
493
  ```bash
473
494
  docker build -t airlock-bot .
495
+ mkdir -p airlock-config
496
+ cp examples/docker-gateway.yaml airlock-config/airlock.yaml
474
497
  docker run --rm \
475
498
  --env-file .env \
476
499
  -v "$PWD/airlock-config:/config" \
477
500
  -v airlock-data:/data \
478
501
  -p 127.0.0.1:4111:4111 \
502
+ -p 127.0.0.1:4113:4113 \
479
503
  -p 127.0.0.1:4112:4112 \
480
504
  airlock-bot
481
505
  ```
482
506
 
507
+ The dashboard edits `/config/airlock.yaml` and writes `/config/airlock.bak`, so
508
+ mount a config directory when dashboard editing is enabled.
509
+
483
510
  See [`examples/docker-compose.yaml`](examples/docker-compose.yaml) and
484
511
  [`docs/guides/docker-deploy.md`](docs/guides/docker-deploy.md) for a VPS or
485
512
  reverse-proxy deployment. The compose example uses split mode: the gateway mounts
@@ -0,0 +1,29 @@
1
+ export type AirlockActivityKind = 'notification' | 'log';
2
+ export type AirlockActivitySeverity = 'info' | 'success' | 'warning' | 'error';
3
+ export interface AirlockActivityEvent {
4
+ id: string;
5
+ kind: AirlockActivityKind;
6
+ agentId: string;
7
+ title: string;
8
+ body: string;
9
+ severity: AirlockActivitySeverity;
10
+ createdAt: string;
11
+ }
12
+ type ActivityListener = (event: AirlockActivityEvent) => void;
13
+ export declare class ActivityStream {
14
+ private maxEvents;
15
+ private events;
16
+ private listeners;
17
+ constructor(maxEvents?: number);
18
+ emit(params: {
19
+ kind: AirlockActivityKind;
20
+ agentId: string;
21
+ title: string;
22
+ body: string;
23
+ severity?: AirlockActivitySeverity;
24
+ }): AirlockActivityEvent;
25
+ recent(): AirlockActivityEvent[];
26
+ subscribe(listener: ActivityListener): () => void;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/activity/stream.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,KAAK,CAAC;AACzD,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/E,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,uBAAuB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,gBAAgB,GAAG,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;AAE9D,qBAAa,cAAc;IAIb,OAAO,CAAC,SAAS;IAH7B,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,SAAS,CAA+B;gBAE5B,SAAS,SAAM;IAEnC,IAAI,CAAC,MAAM,EAAE;QACX,IAAI,EAAE,mBAAmB,CAAC;QAC1B,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,uBAAuB,CAAC;KACpC,GAAG,oBAAoB;IAqBxB,MAAM,IAAI,oBAAoB,EAAE;IAIhC,SAAS,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI;CAIlD"}
@@ -0,0 +1,36 @@
1
+ import { generateId } from '../util/id.js';
2
+ export class ActivityStream {
3
+ maxEvents;
4
+ events = [];
5
+ listeners = new Set();
6
+ constructor(maxEvents = 200) {
7
+ this.maxEvents = maxEvents;
8
+ }
9
+ emit(params) {
10
+ const event = {
11
+ id: generateId(),
12
+ kind: params.kind,
13
+ agentId: params.agentId,
14
+ title: params.title,
15
+ body: params.body,
16
+ severity: params.severity ?? 'info',
17
+ createdAt: new Date().toISOString(),
18
+ };
19
+ this.events.unshift(event);
20
+ if (this.events.length > this.maxEvents) {
21
+ this.events = this.events.slice(0, this.maxEvents);
22
+ }
23
+ for (const listener of this.listeners) {
24
+ listener(event);
25
+ }
26
+ return event;
27
+ }
28
+ recent() {
29
+ return [...this.events];
30
+ }
31
+ subscribe(listener) {
32
+ this.listeners.add(listener);
33
+ return () => this.listeners.delete(listener);
34
+ }
35
+ }
36
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/activity/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAiB3C,MAAM,OAAO,cAAc;IAIL;IAHZ,MAAM,GAA2B,EAAE,CAAC;IACpC,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEhD,YAAoB,YAAY,GAAG;QAAf,cAAS,GAAT,SAAS,CAAM;IAAG,CAAC;IAEvC,IAAI,CAAC,MAMJ;QACC,MAAM,KAAK,GAAyB;YAClC,EAAE,EAAE,UAAU,EAAE;YAChB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,MAAM;YACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,CAAC;QACD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM;QACJ,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED,SAAS,CAAC,QAA0B;QAClC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ export declare const AIRLOCK_CONTEXT_KEY = "_airlock";
2
+ export declare const AIRLOCK_REASON_MAX_LENGTH = 500;
3
+ export interface AirlockCallContext {
4
+ reason?: string;
5
+ note?: string;
6
+ }
7
+ export declare function extractAirlockContext(args: Record<string, unknown>): {
8
+ args: Record<string, unknown>;
9
+ context?: AirlockCallContext;
10
+ };
11
+ export declare function requireAirlockReason(context: AirlockCallContext | undefined): string | undefined;
12
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/airlock/context.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACpE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B,CAoBA;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGhG"}
@@ -0,0 +1,32 @@
1
+ export const AIRLOCK_CONTEXT_KEY = '_airlock';
2
+ export const AIRLOCK_REASON_MAX_LENGTH = 500;
3
+ export function extractAirlockContext(args) {
4
+ const raw = args[AIRLOCK_CONTEXT_KEY];
5
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
6
+ return { args };
7
+ }
8
+ const source = raw;
9
+ const context = {};
10
+ if (typeof source.reason === 'string') {
11
+ context.reason = clampHumanText(source.reason);
12
+ }
13
+ if (typeof source.note === 'string') {
14
+ context.note = clampHumanText(source.note);
15
+ }
16
+ const { [AIRLOCK_CONTEXT_KEY]: _ignored, ...cleanArgs } = args;
17
+ return {
18
+ args: cleanArgs,
19
+ ...(context.reason || context.note ? { context } : {}),
20
+ };
21
+ }
22
+ export function requireAirlockReason(context) {
23
+ const reason = context?.reason?.trim();
24
+ return reason ? reason : undefined;
25
+ }
26
+ function clampHumanText(value) {
27
+ const trimmed = value.trim();
28
+ return trimmed.length > AIRLOCK_REASON_MAX_LENGTH
29
+ ? trimmed.slice(0, AIRLOCK_REASON_MAX_LENGTH)
30
+ : trimmed;
31
+ }
32
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/airlock/context.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;AAC9C,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAO7C,MAAM,UAAU,qBAAqB,CAAC,IAA6B;IAIjE,MAAM,GAAG,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,GAA8B,CAAC;IAC9C,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,EAAE,CAAC,mBAAmB,CAAC,EAAE,QAAQ,EAAE,GAAG,SAAS,EAAE,GAAG,IAAI,CAAC;IAC/D,OAAO;QACL,IAAI,EAAE,SAAS;QACf,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAuC;IAC1E,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACvC,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACrC,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,OAAO,CAAC,MAAM,GAAG,yBAAyB;QAC/C,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,CAAC;QAC7C,CAAC,CAAC,OAAO,CAAC;AACd,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare const AIRLOCK_PROVIDER_ID = "airlock";
2
+ export declare const AIRLOCK_ASK_USER_TOOL = "airlock/ask_user";
3
+ export declare const AIRLOCK_NOTIFY_USER_TOOL = "airlock/notify_user";
4
+ export declare const AIRLOCK_LOG_TOOL = "airlock/log";
5
+ export declare const AIRLOCK_NON_ASK_TOOLS: readonly ["airlock/ask_user", "airlock/notify_user", "airlock/log"];
6
+ export declare function isAirlockNonAskTool(toolName: string): boolean;
7
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/airlock/tools.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C,eAAO,MAAM,qBAAqB,qEAIxB,CAAC;AAEX,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,13 @@
1
+ export const AIRLOCK_PROVIDER_ID = 'airlock';
2
+ export const AIRLOCK_ASK_USER_TOOL = 'airlock/ask_user';
3
+ export const AIRLOCK_NOTIFY_USER_TOOL = 'airlock/notify_user';
4
+ export const AIRLOCK_LOG_TOOL = 'airlock/log';
5
+ export const AIRLOCK_NON_ASK_TOOLS = [
6
+ AIRLOCK_ASK_USER_TOOL,
7
+ AIRLOCK_NOTIFY_USER_TOOL,
8
+ AIRLOCK_LOG_TOOL,
9
+ ];
10
+ export function isAirlockNonAskTool(toolName) {
11
+ return AIRLOCK_NON_ASK_TOOLS.includes(toolName);
12
+ }
13
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/airlock/tools.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AACxD,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAC9D,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,qBAAqB;IACrB,wBAAwB;IACxB,gBAAgB;CACR,CAAC;AAEX,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,OAAQ,qBAA2C,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACzE,CAAC"}
@@ -1,9 +1,21 @@
1
1
  import type { AgentConfig } from '../config/schema.js';
2
2
  export type Decision = 'allow' | 'ask' | 'deny';
3
+ export type DetailedDecision = Decision | 'default-deny';
4
+ export interface AllowlistMatch {
5
+ pattern: string;
6
+ specificity: number;
7
+ source: 'deny' | 'remember_allow' | 'ask' | 'allow';
8
+ }
9
+ export interface AllowlistEvaluation {
10
+ decision: DetailedDecision;
11
+ match?: AllowlistMatch;
12
+ candidates: AllowlistMatch[];
13
+ }
3
14
  export declare class AllowlistEngine {
4
15
  private agents;
5
16
  constructor(agents: Record<string, AgentConfig>);
6
17
  reload(agents: Record<string, AgentConfig>): void;
7
18
  evaluate(agentId: string, toolName: string): Decision;
19
+ evaluateDetailed(agentId: string, toolName: string): AllowlistEvaluation;
8
20
  }
9
21
  //# sourceMappingURL=engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/allowlist/engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,qBAAa,eAAe;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAEvD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,IAAI;IAIjD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ;CA2BtD"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/allowlist/engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAChD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,KAAK,GAAG,OAAO,CAAC;CACrD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAEvD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,IAAI;IAIjD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAKrD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,mBAAmB;CA8CzE"}
@@ -1,4 +1,4 @@
1
- import { bestSpecificity } from './pattern.js';
1
+ import { bestSpecificity, specificity } from './pattern.js';
2
2
  export class AllowlistEngine {
3
3
  agents;
4
4
  constructor(agents) {
@@ -8,30 +8,55 @@ export class AllowlistEngine {
8
8
  this.agents = agents;
9
9
  }
10
10
  evaluate(agentId, toolName) {
11
+ const result = this.evaluateDetailed(agentId, toolName);
12
+ return result.decision === 'default-deny' ? 'deny' : result.decision;
13
+ }
14
+ evaluateDetailed(agentId, toolName) {
11
15
  const agent = this.agents[agentId];
12
16
  if (!agent)
13
- return 'deny';
17
+ return { decision: 'default-deny', candidates: [] };
14
18
  // Pure specificity: most specific matching pattern wins across all tiers.
15
19
  // Ties break deny > remembered allow > ask > allow. Remembered allow is an
16
20
  // operator-approved exception that can override an exact ask rule, either
17
21
  // permanently or until it expires.
18
- const denySpec = bestSpecificity(agent.deny, toolName);
19
- const rememberedAllowSpec = bestSpecificity((agent.remember_allow ?? [])
22
+ const rememberedAllow = (agent.remember_allow ?? [])
20
23
  .filter((rule) => !rule.expires_at || Date.parse(rule.expires_at) > Date.now())
21
- .map((rule) => rule.tool), toolName);
24
+ .map((rule) => rule.tool);
25
+ const candidates = [
26
+ ...matchingPatterns(agent.deny, toolName, 'deny'),
27
+ ...matchingPatterns(rememberedAllow, toolName, 'remember_allow'),
28
+ ...matchingPatterns(agent.ask, toolName, 'ask'),
29
+ ...matchingPatterns(agent.allow, toolName, 'allow'),
30
+ ];
31
+ const denySpec = bestSpecificity(agent.deny, toolName);
32
+ const rememberedAllowSpec = bestSpecificity(rememberedAllow, toolName);
22
33
  const askSpec = bestSpecificity(agent.ask, toolName);
23
34
  const allowSpec = bestSpecificity(agent.allow, toolName);
24
35
  const best = Math.max(denySpec, rememberedAllowSpec, askSpec, allowSpec);
25
- if (best < 0)
26
- return 'deny'; // no match, fail-closed
27
- // Tiebreaker order: deny > remembered allow > ask > allow
28
- if (denySpec === best)
29
- return 'deny';
30
- if (rememberedAllowSpec === best)
31
- return 'allow';
32
- if (askSpec === best)
33
- return 'ask';
34
- return 'allow';
36
+ if (best < 0) {
37
+ return { decision: 'default-deny', candidates };
38
+ }
39
+ const winningSource = denySpec === best
40
+ ? 'deny'
41
+ : rememberedAllowSpec === best
42
+ ? 'remember_allow'
43
+ : askSpec === best
44
+ ? 'ask'
45
+ : 'allow';
46
+ const match = candidates
47
+ .filter((candidate) => candidate.source === winningSource && candidate.specificity === best)
48
+ .sort((a, b) => b.pattern.length - a.pattern.length)[0];
49
+ return {
50
+ decision: winningSource === 'remember_allow' ? 'allow' : winningSource,
51
+ match,
52
+ candidates,
53
+ };
35
54
  }
36
55
  }
56
+ function matchingPatterns(patterns, toolName, source) {
57
+ return patterns
58
+ .map((pattern) => ({ pattern, specificity: specificity(pattern, toolName), source }))
59
+ .filter((match) => match.specificity >= 0 &&
60
+ (source === 'deny' || source === 'remember_allow' || source === 'ask' || source === 'allow'));
61
+ }
37
62
  //# sourceMappingURL=engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/allowlist/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAK/C,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,MAAmC;QAAnC,WAAM,GAAN,MAAM,CAA6B;IAAG,CAAC;IAE3D,MAAM,CAAC,MAAmC;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,QAAQ,CAAC,OAAe,EAAE,QAAgB;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,MAAM,CAAC;QAE1B,0EAA0E;QAC1E,2EAA2E;QAC3E,0EAA0E;QAC1E,mCAAmC;QACnC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,mBAAmB,GAAG,eAAe,CACzC,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;aACzB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;aAC9E,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAC3B,QAAQ,CACT,CAAC;QACF,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEzD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,mBAAmB,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QACzE,IAAI,IAAI,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC,CAAC,wBAAwB;QAErD,0DAA0D;QAC1D,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;QACrC,IAAI,mBAAmB,KAAK,IAAI;YAAE,OAAO,OAAO,CAAC;QACjD,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/allowlist/engine.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,11 @@
1
1
  import type { FastifyInstance } from 'fastify';
2
2
  import type { AuditLogger } from './logger.js';
3
+ import { type RequestSecurityOptions } from '../security/request.js';
3
4
  export declare function auditApiPlugin(app: FastifyInstance, opts: {
4
5
  auditLogger: AuditLogger;
5
6
  secret?: string;
6
7
  authRequired?: boolean;
7
8
  allowedOrigins?: string[];
9
+ getRequestSecurity?: () => RequestSecurityOptions;
8
10
  }): Promise<void>;
9
11
  //# sourceMappingURL=api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/audit/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,wBAAsB,cAAc,CAClC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IACJ,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,GACA,OAAO,CAAC,IAAI,CAAC,CAmBf"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/audit/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAG3F,wBAAsB,cAAc,CAClC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE;IACJ,WAAW,EAAE,WAAW,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,sBAAsB,CAAC;CACnD,GACD,OAAO,CAAC,IAAI,CAAC,CAmBf"}
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/audit/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,4DAA4D;AAC5D,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAoB,EACpB,IAKC;IAED,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAE7B,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACjD,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO;QACT,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACzC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,KAA+B,CAAC;QAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC;YAChC,KAAK;YACL,IAAI;YACJ,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG;SACzC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/audit/api.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAA+B,MAAM,wBAAwB,CAAC;AAE3F,4DAA4D;AAC5D,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAoB,EACpB,IAME;IAEF,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAE7B,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACjD,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO;QACT,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACzC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,KAA+B,CAAC;QAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC;YAChC,KAAK;YACL,IAAI;YACJ,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG;SACzC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -20,6 +20,16 @@ export interface HitlQueueEntry {
20
20
  created_at: string;
21
21
  resolved_at?: string;
22
22
  }
23
+ export interface MobileDeviceEntry {
24
+ id: string;
25
+ name: string;
26
+ platform: 'ios';
27
+ push_token: string;
28
+ auth_token_hash: string;
29
+ created_at: string;
30
+ updated_at: string;
31
+ revoked_at?: string;
32
+ }
23
33
  export declare class AuditDb {
24
34
  private db;
25
35
  private stmts;
@@ -38,6 +48,12 @@ export declare class AuditDb {
38
48
  getHitlByCode(code: string): HitlQueueEntry | undefined;
39
49
  getHitlById(id: string): HitlQueueEntry | undefined;
40
50
  getPendingHitl(): HitlQueueEntry[];
51
+ getHitlHistory(limit?: number): HitlQueueEntry[];
52
+ upsertMobileDevice(entry: Omit<MobileDeviceEntry, 'revoked_at'>): void;
53
+ updateMobileDevicePushToken(id: string, pushToken: string): void;
54
+ getMobileDeviceByAuthTokenHash(authTokenHash: string): MobileDeviceEntry | undefined;
55
+ getActiveMobileDevices(): MobileDeviceEntry[];
56
+ revokeMobileDevice(id: string): void;
41
57
  cleanup(retentionDays: number): void;
42
58
  close(): void;
43
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/audit/db.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,KAAK,CASX;gBAEU,MAAM,EAAE,MAAM;IAM1B,OAAO,CAAC,IAAI;IAiCZ,OAAO,CAAC,iBAAiB;IAyBzB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,IAAI;IAShD,UAAU,CAAC,OAAO,EAAE;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,UAAU,EAAE;IA0BhB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAIvC,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IASrF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIvD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAInD,cAAc,IAAI,cAAc,EAAE;IAIlC,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAMpC,KAAK,IAAI,IAAI;CAGd"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/audit/db.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,KAAK,CAeX;gBAEU,MAAM,EAAE,MAAM;IAM1B,OAAO,CAAC,IAAI;IA6CZ,OAAO,CAAC,iBAAiB;IA+DzB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,IAAI;IAShD,UAAU,CAAC,OAAO,EAAE;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,UAAU,EAAE;IA0BhB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAIvC,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IASrF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIvD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAInD,cAAc,IAAI,cAAc,EAAE;IAIlC,cAAc,CAAC,KAAK,SAAK,GAAG,cAAc,EAAE;IAK5C,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,GAAG,IAAI;IAItE,2BAA2B,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAQhE,8BAA8B,CAAC,aAAa,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAMpF,sBAAsB,IAAI,iBAAiB,EAAE;IAI7C,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIpC,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAMpC,KAAK,IAAI,IAAI;CAGd"}
package/dist/audit/db.js CHANGED
@@ -37,6 +37,18 @@ export class AuditDb {
37
37
  );
38
38
  CREATE INDEX IF NOT EXISTS idx_hitl_status ON hitl_queue(status);
39
39
  CREATE INDEX IF NOT EXISTS idx_hitl_code ON hitl_queue(code);
40
+
41
+ CREATE TABLE IF NOT EXISTS mobile_devices (
42
+ id TEXT PRIMARY KEY,
43
+ name TEXT NOT NULL,
44
+ platform TEXT NOT NULL,
45
+ push_token TEXT NOT NULL,
46
+ auth_token_hash TEXT NOT NULL UNIQUE,
47
+ created_at TEXT NOT NULL,
48
+ updated_at TEXT NOT NULL,
49
+ revoked_at TEXT
50
+ );
51
+ CREATE INDEX IF NOT EXISTS idx_mobile_devices_revoked ON mobile_devices(revoked_at);
40
52
  `);
41
53
  }
42
54
  prepareStatements() {
@@ -55,6 +67,44 @@ export class AuditDb {
55
67
  getHitlByCode: this.db.prepare('SELECT * FROM hitl_queue WHERE code = ?'),
56
68
  getHitlById: this.db.prepare('SELECT * FROM hitl_queue WHERE id = ?'),
57
69
  getPendingHitl: this.db.prepare("SELECT * FROM hitl_queue WHERE status = 'pending' ORDER BY created_at ASC"),
70
+ getHitlHistory: this.db.prepare(`
71
+ SELECT * FROM hitl_queue
72
+ WHERE status != 'pending'
73
+ ORDER BY COALESCE(resolved_at, created_at) DESC
74
+ LIMIT ?
75
+ `),
76
+ insertMobileDevice: this.db.prepare(`
77
+ INSERT INTO mobile_devices (
78
+ id, name, platform, push_token, auth_token_hash, created_at, updated_at, revoked_at
79
+ )
80
+ VALUES (
81
+ @id, @name, @platform, @push_token, @auth_token_hash, @created_at, @updated_at, NULL
82
+ )
83
+ ON CONFLICT(auth_token_hash) DO UPDATE SET
84
+ name = excluded.name,
85
+ push_token = excluded.push_token,
86
+ updated_at = excluded.updated_at,
87
+ revoked_at = NULL
88
+ `),
89
+ updateMobileDevicePushToken: this.db.prepare(`
90
+ UPDATE mobile_devices
91
+ SET push_token = @push_token, updated_at = @updated_at
92
+ WHERE id = @id AND revoked_at IS NULL
93
+ `),
94
+ getMobileDeviceByAuthTokenHash: this.db.prepare(`
95
+ SELECT * FROM mobile_devices
96
+ WHERE auth_token_hash = ? AND revoked_at IS NULL
97
+ `),
98
+ getActiveMobileDevices: this.db.prepare(`
99
+ SELECT * FROM mobile_devices
100
+ WHERE revoked_at IS NULL
101
+ ORDER BY created_at ASC
102
+ `),
103
+ revokeMobileDevice: this.db.prepare(`
104
+ UPDATE mobile_devices
105
+ SET revoked_at = @revoked_at, updated_at = @revoked_at
106
+ WHERE id = @id AND revoked_at IS NULL
107
+ `),
58
108
  cleanupAudit: this.db.prepare('DELETE FROM audit_log WHERE ts < ?'),
59
109
  cleanupHitl: this.db.prepare("DELETE FROM hitl_queue WHERE status != 'pending' AND resolved_at < ?"),
60
110
  };
@@ -109,6 +159,29 @@ export class AuditDb {
109
159
  getPendingHitl() {
110
160
  return this.stmts.getPendingHitl.all();
111
161
  }
162
+ getHitlHistory(limit = 50) {
163
+ const boundedLimit = Math.max(1, Math.min(limit, 500));
164
+ return this.stmts.getHitlHistory.all(boundedLimit);
165
+ }
166
+ upsertMobileDevice(entry) {
167
+ this.stmts.insertMobileDevice.run(entry);
168
+ }
169
+ updateMobileDevicePushToken(id, pushToken) {
170
+ this.stmts.updateMobileDevicePushToken.run({
171
+ id,
172
+ push_token: pushToken,
173
+ updated_at: new Date().toISOString(),
174
+ });
175
+ }
176
+ getMobileDeviceByAuthTokenHash(authTokenHash) {
177
+ return this.stmts.getMobileDeviceByAuthTokenHash.get(authTokenHash);
178
+ }
179
+ getActiveMobileDevices() {
180
+ return this.stmts.getActiveMobileDevices.all();
181
+ }
182
+ revokeMobileDevice(id) {
183
+ this.stmts.revokeMobileDevice.run({ id, revoked_at: new Date().toISOString() });
184
+ }
112
185
  cleanup(retentionDays) {
113
186
  const cutoff = new Date(Date.now() - retentionDays * 86400_000).toISOString();
114
187
  this.stmts.cleanupAudit.run(cutoff);
@@ -1 +1 @@
1
- {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/audit/db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/audit/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAqCtC,MAAM,OAAO,OAAO;IACV,EAAE,CAAoB;IACtB,KAAK,CAeX;IAEF,YAAY,MAAc;QACxB,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyCZ,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB;QACvB,IAAI,CAAC,KAAK,GAAG;YACX,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;OAG5B,CAAC;YACF,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;OAG3B,CAAC;YACF,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;OAEjC,CAAC;YACF,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC;YACzE,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC;YACrE,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAC7B,2EAA2E,CAC5E;YACD,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;OAK/B,CAAC;YACF,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;OAYnC,CAAC;YACF,2BAA2B,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAI5C,CAAC;YACF,8BAA8B,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;OAG/C,CAAC;YACF,sBAAsB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAIvC,CAAC;YACF,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAInC,CAAC;YACF,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,oCAAoC,CAAC;YACnE,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAC1B,sEAAsE,CACvE;SACF,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,KAA6B;QACvC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC;YACzB,KAAK,EAAE,IAAI;YACX,WAAW,EAAE,IAAI;YACjB,SAAS,EAAE,IAAI;YACf,GAAG,KAAK;SACT,CAAC,CAAC;IACL,CAAC;IAED,UAAU,CAAC,OAKV;QACC,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,MAAM,MAAM,GAA4B,EAAE,CAAC;QAE3C,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC/B,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAChC,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAC7B,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAChC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC/B,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QACjE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAErB,OAAO,IAAI,CAAC,EAAE;aACX,OAAO,CAAC,2BAA2B,KAAK,gCAAgC,CAAC;aACzE,GAAG,CAAC,MAAM,CAAiB,CAAC;IACjC,CAAC;IAED,UAAU,CAAC,KAAqB;QAC9B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,gBAAgB,CAAC,EAAU,EAAE,MAAgC,EAAE,MAAe;QAC5E,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC;YAC9B,EAAE;YACF,MAAM;YACN,MAAM,EAAE,MAAM,IAAI,IAAI;YACtB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC,CAAC;IACL,CAAC;IAED,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAA+B,CAAC;IAC1E,CAAC;IAED,WAAW,CAAC,EAAU;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAA+B,CAAC;IACtE,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,EAAsB,CAAC;IAC7D,CAAC;IAED,cAAc,CAAC,KAAK,GAAG,EAAE;QACvB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,YAAY,CAAqB,CAAC;IACzE,CAAC;IAED,kBAAkB,CAAC,KAA4C;QAC7D,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,2BAA2B,CAAC,EAAU,EAAE,SAAiB;QACvD,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC,GAAG,CAAC;YACzC,EAAE;YACF,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,CAAC,CAAC;IACL,CAAC;IAED,8BAA8B,CAAC,aAAqB;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,GAAG,CAAC,aAAa,CAErD,CAAC;IAChB,CAAC;IAED,sBAAsB;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,GAAG,EAAyB,CAAC;IACxE,CAAC;IAED,kBAAkB,CAAC,EAAU;QAC3B,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,CAAC,aAAqB;QAC3B,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,GAAG,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9E,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF"}
@@ -1,4 +1,4 @@
1
- import type { AuditEntry, HitlQueueEntry } from './db.js';
1
+ import type { AuditEntry, HitlQueueEntry, MobileDeviceEntry } from './db.js';
2
2
  import type { AuditConfig } from '../config/schema.js';
3
3
  export declare class AuditLogger {
4
4
  private db;
@@ -7,6 +7,7 @@ export declare class AuditLogger {
7
7
  private cleanupTimer?;
8
8
  constructor(config: AuditConfig);
9
9
  log(entry: Omit<AuditEntry, 'id' | 'ts'>): void;
10
+ redactArgs(args: Record<string, unknown>): Record<string, unknown>;
10
11
  recent(n: number): AuditEntry[];
11
12
  query(filters: {
12
13
  agent?: string;
@@ -19,6 +20,12 @@ export declare class AuditLogger {
19
20
  getHitlByCode(code: string): HitlQueueEntry | undefined;
20
21
  getHitlById(id: string): HitlQueueEntry | undefined;
21
22
  getPendingHitl(): HitlQueueEntry[];
23
+ getHitlHistory(limit?: number): HitlQueueEntry[];
24
+ upsertMobileDevice(entry: Omit<MobileDeviceEntry, 'revoked_at'>): void;
25
+ updateMobileDevicePushToken(id: string, pushToken: string): void;
26
+ getMobileDeviceByAuthTokenHash(authTokenHash: string): MobileDeviceEntry | undefined;
27
+ getActiveMobileDevices(): MobileDeviceEntry[];
28
+ revokeMobileDevice(id: string): void;
22
29
  startDailyCleanup(): void;
23
30
  stop(): void;
24
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/audit/logger.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAC,CAAiB;gBAE1B,MAAM,EAAE,WAAW;IAM/B,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI;IAY/C,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAI/B,KAAK,CAAC,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,EAAE;IAK/F,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAGvC,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAGrF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAGvD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAGnD,cAAc,IAAI,cAAc,EAAE;IAIlC,iBAAiB,IAAI,IAAI;IAOzB,IAAI,IAAI,IAAI;CAIb"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/audit/logger.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAC,CAAiB;gBAE1B,MAAM,EAAE,WAAW;IAM/B,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI;IAY/C,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIlE,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAI/B,KAAK,CAAC,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,EAAE;IAK/F,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAGvC,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAGrF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAGvD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAGnD,cAAc,IAAI,cAAc,EAAE;IAGlC,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE;IAGhD,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,GAAG,IAAI;IAGtE,2BAA2B,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAGhE,8BAA8B,CAAC,aAAa,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAGpF,sBAAsB,IAAI,iBAAiB,EAAE;IAG7C,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIpC,iBAAiB,IAAI,IAAI;IAOzB,IAAI,IAAI,IAAI;CAIb"}
@@ -22,6 +22,9 @@ export class AuditLogger {
22
22
  }
23
23
  this.db.insertAudit({ ...entry, args, ts: new Date().toISOString() });
24
24
  }
25
+ redactArgs(args) {
26
+ return redactFields(args, this.redactPatterns);
27
+ }
25
28
  recent(n) {
26
29
  return this.db.queryAudit({ limit: n });
27
30
  }
@@ -44,6 +47,24 @@ export class AuditLogger {
44
47
  getPendingHitl() {
45
48
  return this.db.getPendingHitl();
46
49
  }
50
+ getHitlHistory(limit) {
51
+ return this.db.getHitlHistory(limit);
52
+ }
53
+ upsertMobileDevice(entry) {
54
+ this.db.upsertMobileDevice(entry);
55
+ }
56
+ updateMobileDevicePushToken(id, pushToken) {
57
+ this.db.updateMobileDevicePushToken(id, pushToken);
58
+ }
59
+ getMobileDeviceByAuthTokenHash(authTokenHash) {
60
+ return this.db.getMobileDeviceByAuthTokenHash(authTokenHash);
61
+ }
62
+ getActiveMobileDevices() {
63
+ return this.db.getActiveMobileDevices();
64
+ }
65
+ revokeMobileDevice(id) {
66
+ this.db.revokeMobileDevice(id);
67
+ }
47
68
  startDailyCleanup() {
48
69
  this.cleanupTimer = setInterval(() => {
49
70
  this.db.cleanup(this.retentionDays);