@vellumai/vellum-gateway 0.7.0 → 0.7.2

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 (162) hide show
  1. package/AGENTS.md +4 -0
  2. package/ARCHITECTURE.md +67 -25
  3. package/Dockerfile +2 -0
  4. package/README.md +50 -13
  5. package/bun.lock +16 -2
  6. package/knip.json +3 -1
  7. package/package.json +3 -1
  8. package/src/__tests__/auto-approve-thresholds.test.ts +49 -22
  9. package/src/__tests__/channel-verification-session-proxy.test.ts +0 -1
  10. package/src/__tests__/config-file-watcher.test.ts +181 -0
  11. package/src/__tests__/config.test.ts +0 -1
  12. package/src/__tests__/contacts-control-plane-proxy.test.ts +0 -1
  13. package/src/__tests__/credential-watcher-managed-bootstrap.test.ts +10 -2
  14. package/src/__tests__/credential-watcher.test.ts +30 -2
  15. package/src/__tests__/db-connection-isolation.test.ts +157 -0
  16. package/src/__tests__/fake-assistant-ipc.ts +39 -0
  17. package/src/__tests__/feature-flags-route.test.ts +8 -8
  18. package/src/__tests__/guardian-init-lockfile.test.ts +30 -4
  19. package/src/__tests__/ipc-feature-flag-routes.test.ts +1 -1
  20. package/src/__tests__/live-voice-websocket.test.ts +0 -1
  21. package/src/__tests__/load-guards.test.ts +0 -1
  22. package/src/__tests__/migration-teleport-gcs-proxy.test.ts +0 -1
  23. package/src/__tests__/oauth-callback.test.ts +0 -1
  24. package/src/__tests__/pair-origin-allowlist.test.ts +155 -0
  25. package/src/__tests__/rate-limit-loopback.test.ts +1 -1
  26. package/src/__tests__/remote-feature-flag-sync.test.ts +47 -7
  27. package/src/__tests__/resolve-assistant.test.ts +0 -1
  28. package/src/__tests__/route-schema-guard.test.ts +42 -6
  29. package/src/__tests__/runtime-client.test.ts +0 -1
  30. package/src/__tests__/runtime-health-proxy.test.ts +0 -1
  31. package/src/__tests__/runtime-proxy-auth.test.ts +0 -1
  32. package/src/__tests__/runtime-proxy.test.ts +0 -1
  33. package/src/__tests__/slack-control-plane-proxy.test.ts +0 -1
  34. package/src/__tests__/slack-display-name.test.ts +66 -1
  35. package/src/__tests__/slack-normalize.test.ts +158 -4
  36. package/src/__tests__/slack-reaction-normalize.test.ts +0 -1
  37. package/src/__tests__/slack-socket-mode-catchup.test.ts +857 -0
  38. package/src/__tests__/slack-socket-mode-scopes.test.ts +52 -0
  39. package/src/__tests__/slack-socket-mode-thread-tracking.test.ts +654 -0
  40. package/src/__tests__/stt-stream-websocket.test.ts +0 -1
  41. package/src/__tests__/telegram-control-plane-proxy.test.ts +0 -1
  42. package/src/__tests__/telegram-send-attachments.test.ts +0 -1
  43. package/src/__tests__/telegram-webhook-handler.test.ts +0 -1
  44. package/src/__tests__/text-verification-helpers.test.ts +136 -0
  45. package/src/__tests__/twilio-media-websocket.test.ts +0 -1
  46. package/src/__tests__/twilio-relay-websocket.test.ts +0 -1
  47. package/src/__tests__/twilio-webhooks.test.ts +220 -3
  48. package/src/__tests__/upstream-transport.test.ts +0 -36
  49. package/src/__tests__/whatsapp-download.test.ts +0 -1
  50. package/src/__tests__/whatsapp-webhook.test.ts +0 -1
  51. package/src/auth/guardian-refresh.ts +4 -18
  52. package/src/auth/ipc-route-policy.ts +217 -0
  53. package/src/backup/backup-key.ts +138 -0
  54. package/src/backup/backup-routes.ts +159 -0
  55. package/src/backup/backup-worker.ts +374 -0
  56. package/src/backup/list-snapshots.ts +97 -0
  57. package/src/backup/local-writer.ts +87 -0
  58. package/src/backup/offsite-writer.ts +182 -0
  59. package/src/backup/paths.ts +123 -0
  60. package/src/backup/stream-crypt.ts +258 -0
  61. package/src/chrome-extension-origins.ts +28 -0
  62. package/src/cli/enable-proxy.ts +0 -1
  63. package/src/config-file-cache.ts +3 -19
  64. package/src/config-file-utils.ts +124 -0
  65. package/src/config-file-watcher.ts +57 -25
  66. package/src/config.ts +4 -7
  67. package/src/db/connection.ts +65 -3
  68. package/src/db/contact-store.ts +30 -1
  69. package/src/db/data-migrations/index.ts +2 -0
  70. package/src/db/data-migrations/m0003-recover-backup-key.ts +71 -0
  71. package/src/db/schema.ts +92 -0
  72. package/src/db/slack-store.ts +144 -11
  73. package/src/feature-flag-registry.json +40 -152
  74. package/src/handlers/handle-inbound.ts +123 -0
  75. package/src/http/middleware/auth.ts +44 -1
  76. package/src/http/middleware/cors.ts +84 -0
  77. package/src/http/middleware/rate-limit.ts +6 -8
  78. package/src/http/routes/auto-approve-thresholds.ts +17 -1
  79. package/src/http/routes/brain-graph-proxy.ts +1 -1
  80. package/src/http/routes/channel-readiness-proxy.ts +2 -2
  81. package/src/http/routes/channel-verification-session-proxy.ts +19 -37
  82. package/src/http/routes/contact-prompt.ts +149 -0
  83. package/src/http/routes/contacts-control-plane-proxy.ts +2 -2
  84. package/src/http/routes/email-webhook.test.ts +0 -1
  85. package/src/http/routes/ipc-runtime-proxy.test.ts +197 -1
  86. package/src/http/routes/ipc-runtime-proxy.ts +95 -0
  87. package/src/http/routes/log-export.test.ts +0 -1
  88. package/src/http/routes/log-tail.test.ts +336 -0
  89. package/src/http/routes/log-tail.ts +87 -0
  90. package/src/http/routes/migration-proxy.ts +1 -2
  91. package/src/http/routes/oauth-apps-proxy.ts +2 -2
  92. package/src/http/routes/oauth-providers-proxy.ts +2 -2
  93. package/src/http/routes/pair.ts +322 -0
  94. package/src/http/routes/privacy-config.ts +65 -79
  95. package/src/http/routes/runtime-health-proxy.ts +2 -2
  96. package/src/http/routes/runtime-proxy.ts +3 -1
  97. package/src/http/routes/slack-control-plane-proxy.ts +3 -20
  98. package/src/http/routes/stt-stream-websocket.ts +2 -3
  99. package/src/http/routes/telegram-control-plane-proxy.ts +2 -2
  100. package/src/http/routes/telegram-webhook.test.ts +0 -1
  101. package/src/http/routes/telegram-webhook.ts +6 -0
  102. package/src/http/routes/trust-rules.suggest.test.ts +25 -0
  103. package/src/http/routes/trust-rules.ts +7 -0
  104. package/src/http/routes/twilio-control-plane-proxy.ts +2 -2
  105. package/src/http/routes/twilio-media-websocket.ts +5 -5
  106. package/src/http/routes/twilio-voice-verify-callback.ts +310 -0
  107. package/src/http/routes/twilio-voice-webhook.test.ts +65 -1
  108. package/src/http/routes/twilio-voice-webhook.ts +45 -1
  109. package/src/http/routes/whatsapp-webhook.test.ts +0 -1
  110. package/src/index.ts +357 -278
  111. package/src/ipc/assistant-client.ts +8 -4
  112. package/src/ipc/contact-handlers.ts +88 -3
  113. package/src/ipc/threshold-handlers.ts +2 -0
  114. package/src/post-assistant-ready.ts +5 -3
  115. package/src/risk/bash-risk-classifier.test.ts +35 -27
  116. package/src/risk/bash-risk-classifier.ts +44 -14
  117. package/src/risk/command-registry/commands/assistant.ts +8 -19
  118. package/src/risk/command-registry.test.ts +0 -15
  119. package/src/risk/risk-classifier-parity.test.ts +1 -3
  120. package/src/runtime/client.ts +58 -3
  121. package/src/schema.ts +277 -104
  122. package/src/slack/normalize.test.ts +98 -0
  123. package/src/slack/normalize.ts +107 -32
  124. package/src/slack/slack-web.ts +213 -0
  125. package/src/slack/socket-mode.ts +701 -39
  126. package/src/telegram/send.test.ts +0 -1
  127. package/src/twilio/validate-webhook.ts +53 -14
  128. package/src/twilio/webhook-sync-trigger.ts +58 -0
  129. package/src/twilio/webhook-sync.test.ts +286 -0
  130. package/src/twilio/webhook-sync.ts +84 -0
  131. package/src/util/is-loopback-address.ts +27 -0
  132. package/src/velay/bridge-utils.ts +228 -0
  133. package/src/velay/client.test.ts +939 -0
  134. package/src/velay/client.ts +555 -0
  135. package/src/velay/http-bridge.test.ts +217 -0
  136. package/src/velay/http-bridge.ts +83 -0
  137. package/src/velay/protocol.ts +178 -0
  138. package/src/velay/test-fake-websocket.ts +69 -0
  139. package/src/velay/websocket-bridge.test.ts +367 -0
  140. package/src/velay/websocket-bridge.ts +324 -0
  141. package/src/verification/binding-helpers.ts +107 -0
  142. package/src/verification/code-parsing.ts +44 -0
  143. package/src/verification/contact-helpers.ts +342 -0
  144. package/src/verification/identity-match.ts +68 -0
  145. package/src/verification/identity.ts +61 -0
  146. package/src/verification/rate-limit-helpers.ts +205 -0
  147. package/src/verification/reply-delivery.ts +109 -0
  148. package/src/verification/session-helpers.ts +164 -0
  149. package/src/verification/text-verification.ts +372 -0
  150. package/src/version.ts +35 -0
  151. package/src/voice/verification.ts +456 -0
  152. package/src/webhook-pipeline.ts +4 -0
  153. package/src/__tests__/browser-relay-websocket.test.ts +0 -698
  154. package/src/__tests__/telegram-only-default.test.ts +0 -133
  155. package/src/auth/capability-tokens.ts +0 -248
  156. package/src/http/routes/browser-extension-pair.ts +0 -455
  157. package/src/http/routes/browser-relay-websocket.ts +0 -381
  158. package/src/http/routes/config-file-utils.ts +0 -73
  159. package/src/ipc/capability-token-handlers.ts +0 -30
  160. package/src/pairing/approved-devices-store.ts +0 -110
  161. package/src/pairing/pairing-routes.ts +0 -379
  162. package/src/pairing/pairing-store.ts +0 -218
@@ -1,133 +0,0 @@
1
- import { describe, test, expect, afterAll } from "bun:test";
2
-
3
- /**
4
- * Proves that runtime proxy passthrough routes stay disabled by default while
5
- * dedicated gateway routes still work. Uses the same routing logic as
6
- * src/index.ts so that changes to production defaults are caught here.
7
- */
8
-
9
- // Minimal env for loadConfig
10
- const env: Record<string, string> = {
11
- TELEGRAM_BOT_TOKEN: "test-tok",
12
- TELEGRAM_WEBHOOK_SECRET: "wh-sec",
13
- GATEWAY_PORT: "7830",
14
- };
15
-
16
- // Save and set env
17
- const saved: Record<string, string | undefined> = {};
18
- for (const [k, v] of Object.entries(env)) {
19
- saved[k] = process.env[k];
20
- process.env[k] = v;
21
- }
22
-
23
- // Dynamically import to pick up env
24
- const { loadConfig } = await import("../config.js");
25
- const { createTelegramWebhookHandler } =
26
- await import("../http/routes/telegram-webhook.js");
27
- const { createRuntimeProxyHandler } =
28
- await import("../http/routes/runtime-proxy.js");
29
- const { createRuntimeHealthProxyHandler } =
30
- await import("../http/routes/runtime-health-proxy.js");
31
-
32
- const config = await loadConfig();
33
-
34
- const { handler: handleTelegramWebhook } = createTelegramWebhookHandler(config);
35
- const runtimeHealthProxy = createRuntimeHealthProxyHandler(config);
36
-
37
- // Mirror production routing from src/index.ts: only create proxy when enabled
38
- const handleRuntimeProxy = config.runtimeProxyEnabled
39
- ? createRuntimeProxyHandler(config)
40
- : null;
41
-
42
- async function handleRequest(req: Request): Promise<Response> {
43
- const url = new URL(req.url);
44
-
45
- if (url.pathname === "/healthz") {
46
- return Response.json({ status: "ok" });
47
- }
48
-
49
- if (url.pathname === "/readyz") {
50
- return Response.json({ status: "ok" });
51
- }
52
-
53
- if (url.pathname === "/webhooks/telegram") {
54
- return handleTelegramWebhook(req);
55
- }
56
-
57
- if (url.pathname === "/v1/health" && req.method === "GET") {
58
- const authHeader = req.headers.get("authorization");
59
- if (!authHeader || !authHeader.toLowerCase().startsWith("bearer ")) {
60
- return Response.json({ error: "Unauthorized" }, { status: 401 });
61
- }
62
- return runtimeHealthProxy.handleRuntimeHealth(req);
63
- }
64
-
65
- if (handleRuntimeProxy) {
66
- return handleRuntimeProxy(req);
67
- }
68
-
69
- return Response.json({ error: "Not found" }, { status: 404 });
70
- }
71
-
72
- afterAll(() => {
73
- for (const [k, v] of Object.entries(saved)) {
74
- if (v === undefined) delete process.env[k];
75
- else process.env[k] = v;
76
- }
77
- });
78
-
79
- describe("Telegram-only default: runtime proxy is disabled by default", () => {
80
- test("GET / returns 404", async () => {
81
- const res = await handleRequest(new Request("http://gateway.test/"));
82
- expect(res.status).toBe(404);
83
- const body = await res.json();
84
- expect(body.error).toBe("Not found");
85
- });
86
-
87
- test("GET /v1/health returns 401 without bearer auth", async () => {
88
- const res = await handleRequest(
89
- new Request("http://gateway.test/v1/health"),
90
- );
91
- expect(res.status).toBe(401);
92
- });
93
-
94
- test("POST /v1/assistants/foo/chat returns 404", async () => {
95
- const res = await handleRequest(
96
- new Request("http://gateway.test/v1/assistants/foo/chat", {
97
- method: "POST",
98
- body: "{}",
99
- headers: { "content-type": "application/json" },
100
- }),
101
- );
102
- expect(res.status).toBe(404);
103
- });
104
-
105
- test("GET /random-path returns 404", async () => {
106
- const res = await handleRequest(
107
- new Request("http://gateway.test/random-path"),
108
- );
109
- expect(res.status).toBe(404);
110
- });
111
-
112
- test("config.runtimeProxyEnabled is false by default", () => {
113
- expect(config.runtimeProxyEnabled).toBe(false);
114
- });
115
-
116
- test("runtime proxy handler is not created when proxy is disabled", () => {
117
- expect(handleRuntimeProxy).toBeNull();
118
- });
119
-
120
- test("GET /healthz returns 200 (infrastructure routes still work)", async () => {
121
- const res = await handleRequest(new Request("http://gateway.test/healthz"));
122
- expect(res.status).toBe(200);
123
- const body = await res.json();
124
- expect(body.status).toBe("ok");
125
- });
126
-
127
- test("GET /readyz returns 200 (infrastructure routes still work)", async () => {
128
- const res = await handleRequest(new Request("http://gateway.test/readyz"));
129
- expect(res.status).toBe(200);
130
- const body = await res.json();
131
- expect(body.status).toBe("ok");
132
- });
133
- });
@@ -1,248 +0,0 @@
1
- /**
2
- * Capability token minting and verification for scoped, short-lived tokens
3
- * issued to the chrome extension (and other thin clients) so they can submit
4
- * results back to the runtime without a full guardian-bound JWT.
5
- *
6
- * Design:
7
- * - Tokens are HMAC-SHA256 signed over a JSON claims payload.
8
- * - Claims include a bound capability, guardian id, nonce, and expiry.
9
- * - Signing uses a long-lived random secret persisted to
10
- * GATEWAY_SECURITY_DIR with 0600 permissions.
11
- * - The secret is generated once on first launch and reused across
12
- * subsequent restarts so previously-minted tokens still verify.
13
- *
14
- * The encoded token format is `<base64url(payload)>.<base64url(sig)>`.
15
- */
16
-
17
- import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
18
- import {
19
- chmodSync,
20
- existsSync,
21
- mkdirSync,
22
- readFileSync,
23
- renameSync,
24
- writeFileSync,
25
- } from "node:fs";
26
- import { dirname, join } from "node:path";
27
-
28
- import { getLogger } from "../logger.js";
29
- import { getGatewaySecurityDir } from "../paths.js";
30
-
31
- const log = getLogger("capability-tokens");
32
-
33
- // ---------------------------------------------------------------------------
34
- // Types
35
- // ---------------------------------------------------------------------------
36
-
37
- /** Capability identifiers that can be bound to a capability token. */
38
- export type Capability = "host_browser_command";
39
-
40
- /** Claims encoded in the signed payload. */
41
- export interface CapabilityClaims {
42
- capability: Capability;
43
- guardianId: string;
44
- /** 16-byte random nonce, hex-encoded. Prevents replay across fresh mints. */
45
- nonce: string;
46
- /** ms-since-epoch expiry. */
47
- expiresAt: number;
48
- }
49
-
50
- /** A freshly-minted capability token and its absolute expiry. */
51
- export interface CapabilityToken {
52
- token: string;
53
- expiresAt: number;
54
- }
55
-
56
- // ---------------------------------------------------------------------------
57
- // Secret lifecycle
58
- // ---------------------------------------------------------------------------
59
-
60
- let _secret: Buffer | undefined;
61
-
62
- const CAPABILITY_TOKEN_SECRET_FILENAME = "capability-token-secret";
63
-
64
- function getSecretPath(): string {
65
- return join(getGatewaySecurityDir(), CAPABILITY_TOKEN_SECRET_FILENAME);
66
- }
67
-
68
- /**
69
- * Write `secret` to `keyPath` atomically with mode 0o600.
70
- */
71
- function writeSecretAtomic(keyPath: string, secret: Buffer): void {
72
- const dir = dirname(keyPath);
73
- if (!existsSync(dir)) {
74
- mkdirSync(dir, { recursive: true });
75
- }
76
- const tmpPath = `${keyPath}.tmp.${process.pid}`;
77
- writeFileSync(tmpPath, secret, { mode: 0o600 });
78
- renameSync(tmpPath, keyPath);
79
- try {
80
- chmodSync(keyPath, 0o600);
81
- } catch (err) {
82
- log.warn(
83
- { err, keyPath },
84
- "Failed to chmod capability token secret after write",
85
- );
86
- }
87
- }
88
-
89
- /**
90
- * Load the capability-token secret from disk or generate and persist a new
91
- * one. Atomically writes with mode 0o600 so the secret is not readable by
92
- * other users on the same host.
93
- */
94
- export function loadOrCreateCapabilityTokenSecret(): Buffer {
95
- const keyPath = getSecretPath();
96
- if (existsSync(keyPath)) {
97
- try {
98
- const raw = readFileSync(keyPath);
99
- if (raw.length === 32) {
100
- return raw;
101
- }
102
- log.warn(
103
- { keyPath, length: raw.length },
104
- "capability token secret has unexpected length — regenerating",
105
- );
106
- } catch (err) {
107
- log.warn(
108
- { err, keyPath },
109
- "Failed to read capability token secret — regenerating",
110
- );
111
- }
112
- }
113
-
114
- const fresh = randomBytes(32);
115
- writeSecretAtomic(keyPath, fresh);
116
- log.info("Capability token secret generated and persisted");
117
- return fresh;
118
- }
119
-
120
- /**
121
- * Initialize the module-level secret. Called once at gateway startup.
122
- */
123
- export function initCapabilityTokenSecret(secret: Buffer): void {
124
- if (secret.length !== 32) {
125
- throw new Error(
126
- `capability token secret must be 32 bytes, got ${secret.length}`,
127
- );
128
- }
129
- _secret = secret;
130
- }
131
-
132
- /**
133
- * Test-only helper to inject a deterministic secret.
134
- */
135
- export function setCapabilityTokenSecretForTests(secret: Buffer): void {
136
- _secret = secret;
137
- }
138
-
139
- /**
140
- * Reset the cached secret. Test-only.
141
- */
142
- export function resetCapabilityTokenSecretForTests(): void {
143
- _secret = undefined;
144
- }
145
-
146
- function getSecret(): Buffer {
147
- if (_secret) return _secret;
148
- if (process.env.NODE_ENV === "test") {
149
- _secret = randomBytes(32);
150
- return _secret;
151
- }
152
- _secret = loadOrCreateCapabilityTokenSecret();
153
- return _secret;
154
- }
155
-
156
- // ---------------------------------------------------------------------------
157
- // Mint / verify
158
- // ---------------------------------------------------------------------------
159
-
160
- const CAPABILITY_TOKEN_DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 minutes
161
-
162
- function base64urlEncode(buf: Buffer): string {
163
- return buf
164
- .toString("base64")
165
- .replace(/\+/g, "-")
166
- .replace(/\//g, "_")
167
- .replace(/=+$/, "");
168
- }
169
-
170
- function base64urlDecode(s: string): Buffer {
171
- const pad = s.length % 4 === 0 ? 0 : 4 - (s.length % 4);
172
- const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat(pad);
173
- return Buffer.from(b64, "base64");
174
- }
175
-
176
- function sign(payload: string, secret: Buffer): string {
177
- return base64urlEncode(createHmac("sha256", secret).update(payload).digest());
178
- }
179
-
180
- /**
181
- * Mint a capability token bound to the `host_browser_command` capability
182
- * for the given guardian id. Default TTL is 30 minutes.
183
- */
184
- export function mintHostBrowserCapability(
185
- guardianId: string,
186
- ttlMs: number = CAPABILITY_TOKEN_DEFAULT_TTL_MS,
187
- ): CapabilityToken {
188
- const expiresAt = Date.now() + ttlMs;
189
- const nonce = randomBytes(16).toString("hex");
190
- const claims: CapabilityClaims = {
191
- capability: "host_browser_command",
192
- guardianId,
193
- nonce,
194
- expiresAt,
195
- };
196
- const payload = base64urlEncode(Buffer.from(JSON.stringify(claims), "utf8"));
197
- const sig = sign(payload, getSecret());
198
- return { token: `${payload}.${sig}`, expiresAt };
199
- }
200
-
201
- /**
202
- * Verify a capability token minted by `mintHostBrowserCapability`.
203
- *
204
- * Returns the decoded claims on success or null if the signature is
205
- * invalid, the payload is malformed, the token has expired, or the bound
206
- * capability is not `host_browser_command`.
207
- *
208
- * Signature comparison uses `timingSafeEqual` to avoid leaking the secret
209
- * through timing side channels.
210
- */
211
- export function verifyHostBrowserCapability(
212
- token: string,
213
- ): CapabilityClaims | null {
214
- if (typeof token !== "string") return null;
215
- const dot = token.indexOf(".");
216
- if (dot < 0) return null;
217
- const payload = token.slice(0, dot);
218
- const sig = token.slice(dot + 1);
219
- if (!payload || !sig) return null;
220
-
221
- const expected = sign(payload, getSecret());
222
- const a = Buffer.from(sig, "utf8");
223
- const b = Buffer.from(expected, "utf8");
224
- if (a.length !== b.length) return null;
225
- if (!timingSafeEqual(a, b)) return null;
226
-
227
- let claims: CapabilityClaims;
228
- try {
229
- claims = JSON.parse(
230
- base64urlDecode(payload).toString("utf8"),
231
- ) as CapabilityClaims;
232
- } catch {
233
- return null;
234
- }
235
-
236
- if (!claims || typeof claims !== "object") return null;
237
- if (claims.capability !== "host_browser_command") return null;
238
- if (typeof claims.guardianId !== "string" || claims.guardianId.length === 0) {
239
- return null;
240
- }
241
- if (typeof claims.nonce !== "string" || claims.nonce.length === 0) {
242
- return null;
243
- }
244
- if (typeof claims.expiresAt !== "number" || claims.expiresAt <= Date.now()) {
245
- return null;
246
- }
247
- return claims;
248
- }