gitlab-mcp 1.1.0 → 1.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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/dist/config/env.d.ts +56 -0
  3. package/dist/config/env.js +163 -0
  4. package/dist/config/env.js.map +1 -0
  5. package/dist/http-app.d.ts +45 -0
  6. package/dist/http-app.js +550 -0
  7. package/dist/http-app.js.map +1 -0
  8. package/dist/http.d.ts +2 -0
  9. package/dist/http.js +65 -0
  10. package/dist/http.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +65 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/lib/auth-context.d.ts +9 -0
  15. package/dist/lib/auth-context.js +9 -0
  16. package/dist/lib/auth-context.js.map +1 -0
  17. package/dist/lib/gitlab-client.d.ts +331 -0
  18. package/dist/lib/gitlab-client.js +1025 -0
  19. package/dist/lib/gitlab-client.js.map +1 -0
  20. package/dist/lib/logger.d.ts +2 -0
  21. package/dist/lib/logger.js +13 -0
  22. package/dist/lib/logger.js.map +1 -0
  23. package/dist/lib/network.d.ts +3 -0
  24. package/dist/lib/network.js +38 -0
  25. package/dist/lib/network.js.map +1 -0
  26. package/dist/lib/oauth.d.ts +29 -0
  27. package/dist/lib/oauth.js +220 -0
  28. package/dist/lib/oauth.js.map +1 -0
  29. package/dist/lib/output.d.ts +14 -0
  30. package/dist/lib/output.js +38 -0
  31. package/dist/lib/output.js.map +1 -0
  32. package/dist/lib/policy.d.ts +25 -0
  33. package/dist/lib/policy.js +48 -0
  34. package/dist/lib/policy.js.map +1 -0
  35. package/dist/lib/request-runtime.d.ts +26 -0
  36. package/dist/lib/request-runtime.js +323 -0
  37. package/dist/lib/request-runtime.js.map +1 -0
  38. package/dist/lib/sanitize.d.ts +1 -0
  39. package/dist/lib/sanitize.js +21 -0
  40. package/dist/lib/sanitize.js.map +1 -0
  41. package/dist/lib/session-capacity.d.ts +8 -0
  42. package/dist/lib/session-capacity.js +7 -0
  43. package/dist/lib/session-capacity.js.map +1 -0
  44. package/dist/server/build-server.d.ts +3 -0
  45. package/dist/server/build-server.js +13 -0
  46. package/dist/server/build-server.js.map +1 -0
  47. package/dist/tools/gitlab.d.ts +9 -0
  48. package/dist/tools/gitlab.js +2576 -0
  49. package/dist/tools/gitlab.js.map +1 -0
  50. package/dist/tools/health.d.ts +2 -0
  51. package/dist/tools/health.js +21 -0
  52. package/dist/tools/health.js.map +1 -0
  53. package/dist/tools/mr-code-context.d.ts +38 -0
  54. package/dist/tools/mr-code-context.js +330 -0
  55. package/dist/tools/mr-code-context.js.map +1 -0
  56. package/{src/types/context.ts → dist/types/context.d.ts} +5 -6
  57. package/dist/types/context.js +2 -0
  58. package/dist/types/context.js.map +1 -0
  59. package/docs/configuration.md +6 -6
  60. package/docs/mcp-integration-testing-best-practices.md +981 -0
  61. package/package.json +13 -1
  62. package/.dockerignore +0 -7
  63. package/.editorconfig +0 -9
  64. package/.env.example +0 -75
  65. package/.github/workflows/nodejs.yml +0 -31
  66. package/.github/workflows/npm-publish.yml +0 -31
  67. package/.husky/pre-commit +0 -1
  68. package/.nvmrc +0 -1
  69. package/.prettierrc.json +0 -6
  70. package/Dockerfile +0 -20
  71. package/docker-compose.yml +0 -10
  72. package/eslint.config.js +0 -23
  73. package/scripts/get-oauth-token.example.sh +0 -15
  74. package/src/config/env.ts +0 -171
  75. package/src/http.ts +0 -620
  76. package/src/index.ts +0 -77
  77. package/src/lib/auth-context.ts +0 -19
  78. package/src/lib/gitlab-client.ts +0 -1810
  79. package/src/lib/logger.ts +0 -17
  80. package/src/lib/network.ts +0 -45
  81. package/src/lib/oauth.ts +0 -287
  82. package/src/lib/output.ts +0 -51
  83. package/src/lib/policy.ts +0 -78
  84. package/src/lib/request-runtime.ts +0 -376
  85. package/src/lib/sanitize.ts +0 -25
  86. package/src/lib/session-capacity.ts +0 -14
  87. package/src/server/build-server.ts +0 -17
  88. package/src/tools/gitlab.ts +0 -3135
  89. package/src/tools/health.ts +0 -27
  90. package/src/tools/mr-code-context.ts +0 -473
  91. package/tests/auth-context.test.ts +0 -102
  92. package/tests/gitlab-client.test.ts +0 -672
  93. package/tests/graphql-guard.test.ts +0 -121
  94. package/tests/integration/agent-loop.integration.test.ts +0 -558
  95. package/tests/integration/server.integration.test.ts +0 -543
  96. package/tests/mr-code-context.test.ts +0 -600
  97. package/tests/oauth.test.ts +0 -43
  98. package/tests/output.test.ts +0 -186
  99. package/tests/policy.test.ts +0 -324
  100. package/tests/request-runtime.test.ts +0 -252
  101. package/tests/sanitize.test.ts +0 -123
  102. package/tests/session-capacity.test.ts +0 -49
  103. package/tests/upload-reference.test.ts +0 -88
  104. package/tsconfig.build.json +0 -11
  105. package/tsconfig.json +0 -21
  106. package/vitest.config.ts +0 -12
@@ -1,27 +0,0 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
-
3
- export function registerHealthTool(server: McpServer): void {
4
- server.registerTool(
5
- "health_check",
6
- {
7
- title: "Health Check",
8
- description: "Return server liveness and current timestamp."
9
- },
10
- async () => {
11
- const now = new Date().toISOString();
12
-
13
- return {
14
- content: [
15
- {
16
- type: "text" as const,
17
- text: `ok (${now})`
18
- }
19
- ],
20
- structuredContent: {
21
- status: "ok",
22
- timestamp: now
23
- }
24
- };
25
- }
26
- );
27
- }
@@ -1,473 +0,0 @@
1
- import picomatch from "picomatch";
2
- import { z } from "zod";
3
-
4
- import type { AppContext } from "../types/context.js";
5
-
6
- export const mergeRequestCodeContextSchema = {
7
- project_id: z.string().optional(),
8
- merge_request_iid: z.string().min(1),
9
- include_paths: z.array(z.string()).optional(),
10
- exclude_paths: z.array(z.string()).optional(),
11
- extensions: z.array(z.string()).optional(),
12
- languages: z.array(z.string()).optional(),
13
- max_files: z.number().int().min(1).max(500).default(30),
14
- max_total_chars: z.number().int().min(500).max(2_000_000).default(120_000),
15
- context_lines: z.number().int().min(0).max(200).default(20),
16
- mode: z.enum(["patch", "surrounding", "fullfile"]).default("patch"),
17
- sort: z.enum(["changed_lines", "path", "file_size"]).default("changed_lines"),
18
- list_only: z.boolean().default(false)
19
- } as const;
20
-
21
- interface MergeRequestInfo {
22
- source_branch?: string;
23
- target_branch?: string;
24
- }
25
-
26
- interface DiffFile {
27
- old_path: string;
28
- new_path: string;
29
- new_file: boolean;
30
- renamed_file: boolean;
31
- deleted_file: boolean;
32
- diff: string;
33
- }
34
-
35
- interface Budget {
36
- maxChars: number;
37
- usedChars: number;
38
- }
39
-
40
- export async function getMergeRequestCodeContext(
41
- args: {
42
- projectId: string;
43
- mergeRequestIid: string;
44
- includePaths?: string[];
45
- excludePaths?: string[];
46
- extensions?: string[];
47
- languages?: string[];
48
- maxFiles: number;
49
- maxTotalChars: number;
50
- contextLines: number;
51
- mode: "patch" | "surrounding" | "fullfile";
52
- sort: "changed_lines" | "path" | "file_size";
53
- listOnly: boolean;
54
- },
55
- context: AppContext
56
- ): Promise<Record<string, unknown>> {
57
- const mergeRequest = (await context.gitlab.getMergeRequest(
58
- args.projectId,
59
- args.mergeRequestIid
60
- )) as MergeRequestInfo;
61
- const diffResponse = await context.gitlab.getMergeRequestDiffs(
62
- args.projectId,
63
- args.mergeRequestIid
64
- );
65
- const diffFiles = extractDiffFiles(diffResponse);
66
-
67
- const filtered = filterDiffFiles(diffFiles, {
68
- includePaths: args.includePaths,
69
- excludePaths: args.excludePaths,
70
- extensions: args.extensions,
71
- languages: args.languages
72
- });
73
-
74
- const sorted = sortDiffFiles(filtered, args.sort);
75
- const selected = sorted.slice(0, args.maxFiles);
76
-
77
- if (args.listOnly) {
78
- return {
79
- project_id: args.projectId,
80
- merge_request_iid: args.mergeRequestIid,
81
- mode: args.mode,
82
- list_only: true,
83
- total_files: diffFiles.length,
84
- selected_files: selected.length,
85
- files: selected.map((file) => summarizeFile(file))
86
- };
87
- }
88
-
89
- const ref = mergeRequest.source_branch ?? "main";
90
- const budget: Budget = {
91
- maxChars: args.maxTotalChars,
92
- usedChars: 0
93
- };
94
-
95
- const files: Array<Record<string, unknown>> = [];
96
-
97
- for (const file of selected) {
98
- const item = await buildFilePayload(file, {
99
- mode: args.mode,
100
- contextLines: args.contextLines,
101
- projectId: args.projectId,
102
- ref,
103
- gitlab: context.gitlab,
104
- budget
105
- });
106
-
107
- if (item) {
108
- files.push(item);
109
- }
110
-
111
- if (budget.usedChars >= budget.maxChars) {
112
- break;
113
- }
114
- }
115
-
116
- return {
117
- project_id: args.projectId,
118
- merge_request_iid: args.mergeRequestIid,
119
- source_branch: mergeRequest.source_branch,
120
- target_branch: mergeRequest.target_branch,
121
- mode: args.mode,
122
- total_files: diffFiles.length,
123
- filtered_files: filtered.length,
124
- selected_files: selected.length,
125
- returned_files: files.length,
126
- budget: {
127
- max_total_chars: budget.maxChars,
128
- used_chars: budget.usedChars,
129
- remaining_chars: Math.max(0, budget.maxChars - budget.usedChars)
130
- },
131
- files
132
- };
133
- }
134
-
135
- function extractDiffFiles(response: unknown): DiffFile[] {
136
- if (Array.isArray(response)) {
137
- return response as DiffFile[];
138
- }
139
-
140
- if (typeof response === "object" && response !== null) {
141
- const record = response as Record<string, unknown>;
142
- if (Array.isArray(record.changes)) {
143
- return record.changes as DiffFile[];
144
- }
145
- if (Array.isArray(record.diffs)) {
146
- return record.diffs as DiffFile[];
147
- }
148
- }
149
-
150
- return [];
151
- }
152
-
153
- function filterDiffFiles(
154
- files: DiffFile[],
155
- options: {
156
- includePaths?: string[];
157
- excludePaths?: string[];
158
- extensions?: string[];
159
- languages?: string[];
160
- }
161
- ): DiffFile[] {
162
- const includeMatchers = (options.includePaths ?? []).map((pattern) => picomatch(pattern));
163
- const excludeMatchers = (options.excludePaths ?? []).map((pattern) => picomatch(pattern));
164
- const extensionSet = new Set((options.extensions ?? []).map((item) => normalizeExtension(item)));
165
- const languageExtSet = new Set(
166
- (options.languages ?? []).flatMap((language) => languageToExtensions(language.toLowerCase()))
167
- );
168
-
169
- return files.filter((file) => {
170
- const path = file.new_path || file.old_path;
171
-
172
- if (includeMatchers.length > 0 && !includeMatchers.some((matcher) => matcher(path))) {
173
- return false;
174
- }
175
-
176
- if (excludeMatchers.some((matcher) => matcher(path))) {
177
- return false;
178
- }
179
-
180
- const extension = extractExtension(path);
181
-
182
- if (extensionSet.size > 0 && !extensionSet.has(extension)) {
183
- return false;
184
- }
185
-
186
- if (languageExtSet.size > 0 && !languageExtSet.has(extension)) {
187
- return false;
188
- }
189
-
190
- return true;
191
- });
192
- }
193
-
194
- function sortDiffFiles(
195
- files: DiffFile[],
196
- sortMode: "changed_lines" | "path" | "file_size"
197
- ): DiffFile[] {
198
- const cloned = [...files];
199
-
200
- switch (sortMode) {
201
- case "path":
202
- cloned.sort((a, b) => (a.new_path || a.old_path).localeCompare(b.new_path || b.old_path));
203
- return cloned;
204
- case "file_size":
205
- cloned.sort((a, b) => (b.diff?.length ?? 0) - (a.diff?.length ?? 0));
206
- return cloned;
207
- case "changed_lines":
208
- default:
209
- cloned.sort((a, b) => countChangedLines(b.diff) - countChangedLines(a.diff));
210
- return cloned;
211
- }
212
- }
213
-
214
- async function buildFilePayload(
215
- file: DiffFile,
216
- options: {
217
- mode: "patch" | "surrounding" | "fullfile";
218
- contextLines: number;
219
- projectId: string;
220
- ref: string;
221
- gitlab: AppContext["gitlab"];
222
- budget: Budget;
223
- }
224
- ): Promise<Record<string, unknown> | undefined> {
225
- const summary = summarizeFile(file);
226
-
227
- if (options.mode === "patch" || file.deleted_file) {
228
- const taken = takeWithinBudget(file.diff ?? "", options.budget);
229
- return {
230
- ...summary,
231
- content: taken.value,
232
- content_mode: "patch",
233
- truncated: taken.truncated
234
- };
235
- }
236
-
237
- const rawFile = (await options.gitlab.getFileContents(
238
- options.projectId,
239
- file.new_path,
240
- options.ref
241
- )) as Record<string, unknown>;
242
- const decoded = decodeGitLabFileContent(rawFile);
243
-
244
- if (options.mode === "fullfile") {
245
- const taken = takeWithinBudget(decoded, options.budget);
246
- return {
247
- ...summary,
248
- content: taken.value,
249
- content_mode: "fullfile",
250
- truncated: taken.truncated
251
- };
252
- }
253
-
254
- const changedLines = extractChangedNewLines(file.diff ?? "");
255
- const snippets = extractSurroundingSnippets(decoded, changedLines, options.contextLines);
256
- const payload = snippets
257
- .map((snippet) => `@@ ${snippet.start}-${snippet.end} @@\n${snippet.content}`)
258
- .join("\n\n");
259
- const taken = takeWithinBudget(payload, options.budget);
260
-
261
- return {
262
- ...summary,
263
- content: taken.value,
264
- content_mode: "surrounding",
265
- snippet_windows: snippets.map((item) => ({ start: item.start, end: item.end })),
266
- truncated: taken.truncated
267
- };
268
- }
269
-
270
- function summarizeFile(file: DiffFile): Record<string, unknown> {
271
- return {
272
- old_path: file.old_path,
273
- new_path: file.new_path,
274
- new_file: file.new_file,
275
- renamed_file: file.renamed_file,
276
- deleted_file: file.deleted_file,
277
- changed_lines: countChangedLines(file.diff)
278
- };
279
- }
280
-
281
- function countChangedLines(diff: string | undefined): number {
282
- if (!diff) {
283
- return 0;
284
- }
285
-
286
- let count = 0;
287
-
288
- for (const line of diff.split("\n")) {
289
- if (line.startsWith("+") && !line.startsWith("+++")) {
290
- count += 1;
291
- continue;
292
- }
293
-
294
- if (line.startsWith("-") && !line.startsWith("---")) {
295
- count += 1;
296
- }
297
- }
298
-
299
- return count;
300
- }
301
-
302
- function extractChangedNewLines(diff: string): number[] {
303
- const lines = diff.split("\n");
304
- const changed = new Set<number>();
305
- let currentNewLine = 0;
306
-
307
- for (const line of lines) {
308
- if (line.startsWith("@@")) {
309
- const match = /\+([0-9]+)(?:,([0-9]+))?/.exec(line);
310
- if (match?.[1]) {
311
- currentNewLine = Number.parseInt(match[1], 10);
312
- }
313
- continue;
314
- }
315
-
316
- if (line.startsWith("+") && !line.startsWith("+++")) {
317
- changed.add(currentNewLine);
318
- currentNewLine += 1;
319
- continue;
320
- }
321
-
322
- if (line.startsWith("-") && !line.startsWith("---")) {
323
- continue;
324
- }
325
-
326
- currentNewLine += 1;
327
- }
328
-
329
- return [...changed].sort((a, b) => a - b);
330
- }
331
-
332
- function extractSurroundingSnippets(
333
- source: string,
334
- changedLines: number[],
335
- contextLines: number
336
- ): Array<{ start: number; end: number; content: string }> {
337
- const sourceLines = source.split("\n");
338
-
339
- if (changedLines.length === 0) {
340
- return [
341
- {
342
- start: 1,
343
- end: Math.min(sourceLines.length, contextLines * 2 + 1),
344
- content: sourceLines.slice(0, Math.min(sourceLines.length, contextLines * 2 + 1)).join("\n")
345
- }
346
- ];
347
- }
348
-
349
- const windows = mergeWindows(
350
- changedLines.map((lineNumber) => ({
351
- start: Math.max(1, lineNumber - contextLines),
352
- end: Math.min(sourceLines.length, lineNumber + contextLines)
353
- }))
354
- );
355
-
356
- return windows.map((window) => ({
357
- start: window.start,
358
- end: window.end,
359
- content: sourceLines.slice(window.start - 1, window.end).join("\n")
360
- }));
361
- }
362
-
363
- function mergeWindows(
364
- windows: Array<{ start: number; end: number }>
365
- ): Array<{ start: number; end: number }> {
366
- if (windows.length === 0) {
367
- return [];
368
- }
369
-
370
- const sorted = [...windows].sort((a, b) => a.start - b.start);
371
- const first = sorted[0];
372
- if (!first) {
373
- return [];
374
- }
375
-
376
- const merged: Array<{ start: number; end: number }> = [first];
377
-
378
- for (const window of sorted.slice(1)) {
379
- const last = merged[merged.length - 1];
380
- if (!last) {
381
- merged.push(window);
382
- continue;
383
- }
384
-
385
- if (window.start <= last.end + 1) {
386
- last.end = Math.max(last.end, window.end);
387
- continue;
388
- }
389
-
390
- merged.push(window);
391
- }
392
-
393
- return merged;
394
- }
395
-
396
- function decodeGitLabFileContent(raw: Record<string, unknown>): string {
397
- const content = typeof raw.content === "string" ? raw.content : "";
398
- const encoding = typeof raw.encoding === "string" ? raw.encoding.toLowerCase() : "";
399
-
400
- if (encoding === "base64") {
401
- return Buffer.from(content, "base64").toString("utf8");
402
- }
403
-
404
- return content;
405
- }
406
-
407
- function takeWithinBudget(value: string, budget: Budget): { value: string; truncated: boolean } {
408
- const remaining = Math.max(0, budget.maxChars - budget.usedChars);
409
-
410
- if (remaining <= 0) {
411
- return {
412
- value: "",
413
- truncated: true
414
- };
415
- }
416
-
417
- if (value.length <= remaining) {
418
- budget.usedChars += value.length;
419
- return {
420
- value,
421
- truncated: false
422
- };
423
- }
424
-
425
- budget.usedChars = budget.maxChars;
426
- return {
427
- value: `${value.slice(0, remaining)}\n... [truncated]`,
428
- truncated: true
429
- };
430
- }
431
-
432
- function normalizeExtension(extension: string): string {
433
- const cleaned = extension.trim().toLowerCase();
434
- if (cleaned.length === 0) {
435
- return "";
436
- }
437
-
438
- return cleaned.startsWith(".") ? cleaned : `.${cleaned}`;
439
- }
440
-
441
- function extractExtension(path: string): string {
442
- const match = /\.([^./]+)$/.exec(path.toLowerCase());
443
- if (!match?.[1]) {
444
- return "";
445
- }
446
-
447
- return `.${match[1]}`;
448
- }
449
-
450
- function languageToExtensions(language: string): string[] {
451
- const map: Record<string, string[]> = {
452
- typescript: [".ts", ".tsx", ".mts", ".cts"],
453
- javascript: [".js", ".jsx", ".mjs", ".cjs"],
454
- python: [".py"],
455
- go: [".go"],
456
- rust: [".rs"],
457
- java: [".java"],
458
- kotlin: [".kt", ".kts"],
459
- csharp: [".cs"],
460
- cpp: [".cpp", ".cc", ".cxx", ".hpp", ".hh", ".hxx"],
461
- c: [".c", ".h"],
462
- ruby: [".rb"],
463
- php: [".php"],
464
- swift: [".swift"],
465
- scala: [".scala"],
466
- shell: [".sh", ".bash", ".zsh"],
467
- yaml: [".yaml", ".yml"],
468
- json: [".json"],
469
- markdown: [".md", ".markdown"]
470
- };
471
-
472
- return map[language] ?? [];
473
- }
@@ -1,102 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { getSessionAuth, runWithSessionAuth, type SessionAuth } from "../src/lib/auth-context.js";
4
-
5
- describe("auth-context", () => {
6
- describe("runWithSessionAuth", () => {
7
- it("provides auth data within callback", () => {
8
- const auth: SessionAuth = {
9
- sessionId: "sess-1",
10
- token: "my-token",
11
- apiUrl: "https://gitlab.example.com/api/v4",
12
- header: "private-token",
13
- updatedAt: Date.now()
14
- };
15
-
16
- runWithSessionAuth(auth, () => {
17
- const retrieved = getSessionAuth();
18
- expect(retrieved).toEqual(auth);
19
- });
20
- });
21
-
22
- it("returns undefined outside of context", () => {
23
- expect(getSessionAuth()).toBeUndefined();
24
- });
25
-
26
- it("supports undefined auth", () => {
27
- runWithSessionAuth(undefined, () => {
28
- expect(getSessionAuth()).toBeUndefined();
29
- });
30
- });
31
-
32
- it("returns the callback result", () => {
33
- const result = runWithSessionAuth(undefined, () => "hello");
34
- expect(result).toBe("hello");
35
- });
36
-
37
- it("supports nested contexts", () => {
38
- const outerAuth: SessionAuth = {
39
- token: "outer-token",
40
- updatedAt: Date.now()
41
- };
42
-
43
- const innerAuth: SessionAuth = {
44
- token: "inner-token",
45
- updatedAt: Date.now()
46
- };
47
-
48
- runWithSessionAuth(outerAuth, () => {
49
- expect(getSessionAuth()?.token).toBe("outer-token");
50
-
51
- runWithSessionAuth(innerAuth, () => {
52
- expect(getSessionAuth()?.token).toBe("inner-token");
53
- });
54
-
55
- // Outer context is restored
56
- expect(getSessionAuth()?.token).toBe("outer-token");
57
- });
58
- });
59
-
60
- it("isolates context between concurrent async operations", async () => {
61
- const results: string[] = [];
62
-
63
- const task1 = new Promise<void>((resolve) => {
64
- runWithSessionAuth({ token: "token-a", updatedAt: 1 }, () => {
65
- setTimeout(() => {
66
- runWithSessionAuth({ token: "token-a", updatedAt: 1 }, () => {
67
- results.push(getSessionAuth()?.token ?? "none");
68
- resolve();
69
- });
70
- }, 10);
71
- });
72
- });
73
-
74
- const task2 = new Promise<void>((resolve) => {
75
- runWithSessionAuth({ token: "token-b", updatedAt: 2 }, () => {
76
- results.push(getSessionAuth()?.token ?? "none");
77
- resolve();
78
- });
79
- });
80
-
81
- await Promise.all([task1, task2]);
82
-
83
- expect(results).toContain("token-a");
84
- expect(results).toContain("token-b");
85
- });
86
-
87
- it("handles auth with minimal fields", () => {
88
- const auth: SessionAuth = {
89
- updatedAt: Date.now()
90
- };
91
-
92
- runWithSessionAuth(auth, () => {
93
- const retrieved = getSessionAuth();
94
- expect(retrieved?.token).toBeUndefined();
95
- expect(retrieved?.apiUrl).toBeUndefined();
96
- expect(retrieved?.header).toBeUndefined();
97
- expect(retrieved?.sessionId).toBeUndefined();
98
- expect(retrieved?.updatedAt).toBeDefined();
99
- });
100
- });
101
- });
102
- });