brightspace-mcp-server 1.5.1 → 1.5.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 (55) hide show
  1. package/README.md +2 -2
  2. package/build/api/cache.d.ts.map +1 -1
  3. package/build/api/cache.js +6 -0
  4. package/build/api/cache.js.map +1 -1
  5. package/build/api/client.d.ts +5 -0
  6. package/build/api/client.d.ts.map +1 -1
  7. package/build/api/client.js +57 -14
  8. package/build/api/client.js.map +1 -1
  9. package/build/api/paginate.d.ts +23 -0
  10. package/build/api/paginate.d.ts.map +1 -0
  11. package/build/api/paginate.js +89 -0
  12. package/build/api/paginate.js.map +1 -0
  13. package/build/api/retry.d.ts +42 -0
  14. package/build/api/retry.d.ts.map +1 -0
  15. package/build/api/retry.js +50 -0
  16. package/build/api/retry.js.map +1 -0
  17. package/build/api/types.d.ts +3 -0
  18. package/build/api/types.d.ts.map +1 -1
  19. package/build/api/types.js.map +1 -1
  20. package/build/auth/browser-auth.d.ts.map +1 -1
  21. package/build/auth/browser-auth.js +2 -1
  22. package/build/auth/browser-auth.js.map +1 -1
  23. package/build/auth/session-store.d.ts.map +1 -1
  24. package/build/auth/session-store.js +4 -4
  25. package/build/auth/session-store.js.map +1 -1
  26. package/build/tools/get-assignments.d.ts.map +1 -1
  27. package/build/tools/get-assignments.js +58 -27
  28. package/build/tools/get-assignments.js.map +1 -1
  29. package/build/tools/get-classlist-emails.d.ts.map +1 -1
  30. package/build/tools/get-classlist-emails.js +4 -6
  31. package/build/tools/get-classlist-emails.js.map +1 -1
  32. package/build/tools/get-course-content.d.ts.map +1 -1
  33. package/build/tools/get-course-content.js +12 -2
  34. package/build/tools/get-course-content.js.map +1 -1
  35. package/build/tools/get-my-courses.d.ts.map +1 -1
  36. package/build/tools/get-my-courses.js +4 -7
  37. package/build/tools/get-my-courses.js.map +1 -1
  38. package/build/tools/get-roster.d.ts.map +1 -1
  39. package/build/tools/get-roster.js +7 -10
  40. package/build/tools/get-roster.js.map +1 -1
  41. package/build/utils/atomic-write.d.ts +18 -0
  42. package/build/utils/atomic-write.d.ts.map +1 -0
  43. package/build/utils/atomic-write.js +84 -0
  44. package/build/utils/atomic-write.js.map +1 -0
  45. package/build/utils/config-store.d.ts.map +1 -1
  46. package/build/utils/config-store.js +2 -3
  47. package/build/utils/config-store.js.map +1 -1
  48. package/build/utils/logger.d.ts.map +1 -1
  49. package/build/utils/logger.js +45 -1
  50. package/build/utils/logger.js.map +1 -1
  51. package/build/utils/update-checker.d.ts +30 -5
  52. package/build/utils/update-checker.d.ts.map +1 -1
  53. package/build/utils/update-checker.js +79 -45
  54. package/build/utils/update-checker.js.map +1 -1
  55. package/package.json +1 -1
@@ -4,6 +4,7 @@
4
4
  * Licensed under MIT — see LICENSE file for details.
5
5
  */
6
6
  import { DEFAULT_CACHE_TTLS } from "../api/index.js";
7
+ import { fetchAllObjects } from "../api/paginate.js";
7
8
  import { GetRosterSchema, } from "./schemas.js";
8
9
  import { toolResponse, sanitizeError } from "./tool-helpers.js";
9
10
  import { log } from "../utils/logger.js";
@@ -13,9 +14,9 @@ import { log } from "../utils/logger.js";
13
14
  const INSTRUCTOR_ROLE_ID = 109;
14
15
  const TA_ROLE_ID = 135;
15
16
  /**
16
- * Fetch a page of classlist users with optional filters
17
+ * Fetch every classlist user matching the optional filters, across all pages
17
18
  */
18
- async function fetchClasslistPage(apiClient, courseId, options) {
19
+ async function fetchClasslistUsers(apiClient, courseId, options) {
19
20
  const params = new URLSearchParams();
20
21
  if (options?.roleId !== undefined) {
21
22
  params.append("roleId", options.roleId.toString());
@@ -25,13 +26,9 @@ async function fetchClasslistPage(apiClient, courseId, options) {
25
26
  }
26
27
  const queryString = params.toString();
27
28
  const path = apiClient.le(courseId, `/classlist/paged/${queryString ? "?" + queryString : ""}`);
28
- const response = await apiClient.get(path, {
29
+ return fetchAllObjects(apiClient, path, {
29
30
  ttl: DEFAULT_CACHE_TTLS.roster,
30
31
  });
31
- if (response.Next) {
32
- log("WARN", "get_roster: Pagination detected but not implemented. Some users may be missing.", { courseId, next: response.Next });
33
- }
34
- return response.Objects;
35
32
  }
36
33
  /**
37
34
  * Register get_roster tool
@@ -50,11 +47,11 @@ export function registerGetRoster(server, apiClient) {
50
47
  if (!includeStudents) {
51
48
  // Fetch instructors and TAs in parallel
52
49
  const [instructorResult, taResult] = await Promise.allSettled([
53
- fetchClasslistPage(apiClient, courseId, {
50
+ fetchClasslistUsers(apiClient, courseId, {
54
51
  roleId: INSTRUCTOR_ROLE_ID,
55
52
  searchTerm,
56
53
  }),
57
- fetchClasslistPage(apiClient, courseId, {
54
+ fetchClasslistUsers(apiClient, courseId, {
58
55
  roleId: TA_ROLE_ID,
59
56
  searchTerm,
60
57
  }),
@@ -79,7 +76,7 @@ export function registerGetRoster(server, apiClient) {
79
76
  }
80
77
  else {
81
78
  // Fetch all users
82
- allUsers = await fetchClasslistPage(apiClient, courseId, {
79
+ allUsers = await fetchClasslistUsers(apiClient, courseId, {
83
80
  searchTerm,
84
81
  });
85
82
  // Cap at 100 users to prevent MCP response size issues
@@ -1 +1 @@
1
- {"version":3,"file":"get-roster.js","sourceRoot":"","sources":["../../src/tools/get-roster.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAgB,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EACL,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAmBzC,mEAAmE;AACnE,iEAAiE;AACjE,kFAAkF;AAClF,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAC/B,SAAuB,EACvB,QAAgB,EAChB,OAAkD;IAElD,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IAErC,IAAI,OAAO,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;QACxB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CACvB,QAAQ,EACR,oBAAoB,WAAW,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3D,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,CAAoB,IAAI,EAAE;QAC5D,GAAG,EAAE,kBAAkB,CAAC,MAAM;KAC/B,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QAClB,GAAG,CACD,MAAM,EACN,iFAAiF,EACjF,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAClC,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC,OAAO,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAiB,EACjB,SAAuB;IAEvB,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EACT,qVAAqV;QACvV,WAAW,EAAE,eAAe;KAC7B,EACD,KAAK,EAAE,IAAS,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,GAAG,CAAC,OAAO,EAAE,wBAAwB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAEjD,2BAA2B;YAC3B,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAE9E,IAAI,QAAQ,GAAoB,EAAE,CAAC;YAEnC,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,wCAAwC;gBACxC,MAAM,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;oBAC5D,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE;wBACtC,MAAM,EAAE,kBAAkB;wBAC1B,UAAU;qBACX,CAAC;oBACF,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE;wBACtC,MAAM,EAAE,UAAU;wBAClB,UAAU;qBACX,CAAC;iBACH,CAAC,CAAC;gBAEH,gBAAgB;gBAChB,IAAI,gBAAgB,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;oBAC5C,QAAQ,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBAC3C,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,MAAM,EAAE,yCAAyC,EAAE;wBACrD,KAAK,EAAE,gBAAgB,CAAC,MAAM;qBAC/B,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;oBACpC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACnC,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,MAAM,EAAE,iCAAiC,EAAE;wBAC7C,KAAK,EAAE,QAAQ,CAAC,MAAM;qBACvB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,kBAAkB;gBAClB,QAAQ,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE;oBACvD,UAAU;iBACX,CAAC,CAAC;gBAEH,uDAAuD;gBACvD,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;oBAC1B,GAAG,CAAC,MAAM,EAAE,sDAAsD,EAAE;wBAClE,KAAK,EAAE,QAAQ,CAAC,MAAM;wBACtB,QAAQ,EAAE,GAAG;qBACd,CAAC,CAAC;oBACH,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YAED,sBAAsB;YACtB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACrC,IAAI,EAAE,IAAI,CAAC,WAAW;gBACtB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;gBACzB,IAAI,EAAE,IAAI,CAAC,wBAAwB;aACpC,CAAC,CAAC,CAAC;YAEJ,GAAG,CAAC,MAAM,EAAE,yBAAyB,MAAM,CAAC,MAAM,qBAAqB,QAAQ,EAAE,CAAC,CAAC;YACnF,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"get-roster.js","sourceRoot":"","sources":["../../src/tools/get-roster.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Purdue Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT. See LICENSE file for details.
5
+ */
6
+ export interface AtomicWriteOptions {
7
+ mode?: number;
8
+ /** Injection seam for tests. */
9
+ renameImpl?: (from: string, to: string) => Promise<void>;
10
+ /** Injection seam for tests. */
11
+ sleep?: (ms: number) => Promise<void>;
12
+ }
13
+ export declare function writeFileAtomic(target: string, data: string | Buffer, options?: AtomicWriteOptions): Promise<void>;
14
+ /** Synchronous twin for the config store, which is written from the CLI. */
15
+ export declare function writeFileAtomicSync(target: string, data: string | Buffer, options?: {
16
+ mode?: number;
17
+ }): void;
18
+ //# sourceMappingURL=atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.d.ts","sourceRoot":"","sources":["../../src/utils/atomic-write.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuBH,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,gCAAgC;IAChC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAWD,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9B,IAAI,CAuBN"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Purdue Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT. See LICENSE file for details.
5
+ */
6
+ import { randomBytes } from "node:crypto";
7
+ import * as fs from "node:fs/promises";
8
+ import * as fsSync from "node:fs";
9
+ /**
10
+ * Write a file so that a reader never sees a half-written one.
11
+ *
12
+ * The content is staged to a sibling temp file and then renamed over the
13
+ * target. Rename is atomic on the same filesystem, so a crash, a signal, or
14
+ * a second writer mid-way leaves either the old file or the new one, never a
15
+ * truncated mix. The session store and the config store both hold secrets
16
+ * and are both written by more than one process, which is why they use this.
17
+ *
18
+ * On Windows a rename can fail transiently while antivirus or an indexer
19
+ * holds the target open, so those errors are retried a few times.
20
+ */
21
+ const TRANSIENT_RENAME_ERRORS = new Set(["EPERM", "EBUSY", "EACCES"]);
22
+ const RENAME_ATTEMPTS = 5;
23
+ const RENAME_BASE_DELAY_MS = 50;
24
+ function tempPathFor(target) {
25
+ return `${target}.tmp-${randomBytes(6).toString("hex")}`;
26
+ }
27
+ function isTransient(error) {
28
+ const code = error?.code ?? "";
29
+ return TRANSIENT_RENAME_ERRORS.has(code);
30
+ }
31
+ export async function writeFileAtomic(target, data, options = {}) {
32
+ const { mode, renameImpl = (from, to) => fs.rename(from, to), sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), } = options;
33
+ const tmp = tempPathFor(target);
34
+ await fs.writeFile(tmp, data, mode === undefined ? {} : { mode });
35
+ // writeFile's mode is subject to the umask; chmod is not.
36
+ if (mode !== undefined && process.platform !== "win32") {
37
+ await fs.chmod(tmp, mode);
38
+ }
39
+ try {
40
+ for (let attempt = 1;; attempt++) {
41
+ try {
42
+ await renameImpl(tmp, target);
43
+ return;
44
+ }
45
+ catch (error) {
46
+ if (!isTransient(error) || attempt >= RENAME_ATTEMPTS)
47
+ throw error;
48
+ await sleep(RENAME_BASE_DELAY_MS * attempt);
49
+ }
50
+ }
51
+ }
52
+ catch (error) {
53
+ await fs.rm(tmp, { force: true }).catch(() => { });
54
+ throw error;
55
+ }
56
+ }
57
+ /** Synchronous twin for the config store, which is written from the CLI. */
58
+ export function writeFileAtomicSync(target, data, options = {}) {
59
+ const { mode } = options;
60
+ const tmp = tempPathFor(target);
61
+ fsSync.writeFileSync(tmp, data, mode === undefined ? {} : { mode });
62
+ if (mode !== undefined && process.platform !== "win32") {
63
+ fsSync.chmodSync(tmp, mode);
64
+ }
65
+ try {
66
+ for (let attempt = 1;; attempt++) {
67
+ try {
68
+ fsSync.renameSync(tmp, target);
69
+ return;
70
+ }
71
+ catch (error) {
72
+ if (!isTransient(error) || attempt >= RENAME_ATTEMPTS)
73
+ throw error;
74
+ // A short synchronous pause; there is no event loop to yield to here.
75
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, RENAME_BASE_DELAY_MS * attempt);
76
+ }
77
+ }
78
+ }
79
+ catch (error) {
80
+ fsSync.rmSync(tmp, { force: true });
81
+ throw error;
82
+ }
83
+ }
84
+ //# sourceMappingURL=atomic-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../src/utils/atomic-write.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/utils/config-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAKD,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,eAAe,IAAI,eAAe,CAGjD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAQ7D;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/utils/config-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAKD,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,eAAe,IAAI,eAAe,CAGjD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAU7D;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
@@ -6,6 +6,7 @@
6
6
  import * as fs from "node:fs";
7
7
  import * as path from "node:path";
8
8
  import * as os from "node:os";
9
+ import { writeFileAtomicSync } from "./atomic-write.js";
9
10
  const CONFIG_DIR = path.join(os.homedir(), ".brightspace-mcp");
10
11
  const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
11
12
  export function configStoreExists() {
@@ -20,9 +21,7 @@ export function saveConfigStore(config) {
20
21
  if (!fs.existsSync(CONFIG_DIR)) {
21
22
  fs.mkdirSync(CONFIG_DIR, { recursive: true, ...(isWindows ? {} : { mode: 0o700 }) });
22
23
  }
23
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", {
24
- ...(isWindows ? {} : { mode: 0o600 }),
25
- });
24
+ writeFileAtomicSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", isWindows ? {} : { mode: 0o600 });
26
25
  }
27
26
  export function getConfigStorePath() {
28
27
  return CONFIG_FILE;
@@ -1 +1 @@
1
- {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/utils/config-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAgB9B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD,MAAM,UAAU,iBAAiB;IAC/B,OAAO,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAuB;IACrD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE;QACpE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;KACtC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,WAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/utils/config-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAgBxD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD,MAAM,UAAU,iBAAiB;IAC/B,OAAO,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAuB;IACrD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,mBAAmB,CACjB,WAAW,EACX,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACtC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CACjC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAWlD,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEjD;AAyBD,wBAAgB,GAAG,CACjB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,EACf,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,IAAI,CAKN;AAGD,wBAAgB,iBAAiB,IAAI,IAAI,CAOxC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAWlD,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEjD;AA2ED,wBAAgB,GAAG,CACjB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,EACf,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,IAAI,CAMN;AAGD,wBAAgB,iBAAiB,IAAI,IAAI,CAOxC"}
@@ -16,22 +16,66 @@ export function setLogLevel(level) {
16
16
  /**
17
17
  * Redact sensitive patterns from log output.
18
18
  * Tokens, passwords, and secrets are replaced with first 8 chars + "...REDACTED".
19
+ *
20
+ * Deliberately no blanket uppercase or base32 rule: it would eat course codes
21
+ * like ECE264, which are exactly what a useful log line contains.
19
22
  */
20
23
  function redact(value) {
24
+ // JSON web tokens, wherever they appear
25
+ value = value.replace(/eyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]*)?/g, "eyJ...REDACTED");
21
26
  // Redact Bearer tokens
22
27
  value = value.replace(/Bearer\s+([A-Za-z0-9._~+/=-]{8})[A-Za-z0-9._~+/=-]*/g, "Bearer $1...REDACTED");
23
28
  // Redact cookie: prefixed tokens
24
29
  value = value.replace(/cookie:([^\s]{8})[^\s]*/g, "cookie:$1...REDACTED");
30
+ // JSON-serialized header fields: {"Authorization":"..."}, {"Cookie":"..."}
31
+ value = value.replace(/("(?:authorization|cookie|set-cookie)"\s*:\s*")[^"]*(")/gi, "$1...REDACTED$2");
32
+ // Credentials embedded in a URL: scheme://user:pass@host
33
+ value = value.replace(/(\b[a-z][a-z0-9+.-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi, "$1***:***@");
25
34
  // Redact anything that looks like a long token (40+ chars of base64-like)
26
35
  value = value.replace(/([A-Za-z0-9._~+/=-]{40,})/g, (match) => match.substring(0, 8) + "...REDACTED");
27
36
  return value;
28
37
  }
38
+ const MAX_ARG_LENGTH = 2000;
39
+ /**
40
+ * Turn a log argument into text so the redactor can see inside it. Errors
41
+ * keep their name, message, and first stack frame; objects are serialized
42
+ * with cycles broken; everything else is stringified.
43
+ */
44
+ function serializeArg(arg) {
45
+ if (arg instanceof Error) {
46
+ const frame = arg.stack?.split("\n").find((line) => line.trim().startsWith("at ")) ?? "";
47
+ return `${arg.name}: ${arg.message}${frame ? ` ${frame.trim()}` : ""}`;
48
+ }
49
+ if (typeof arg === "string")
50
+ return arg;
51
+ if (typeof arg === "object" && arg !== null) {
52
+ const seen = new WeakSet();
53
+ try {
54
+ const json = JSON.stringify(arg, (_key, value) => {
55
+ if (typeof value === "bigint")
56
+ return value.toString();
57
+ if (typeof value === "object" && value !== null) {
58
+ if (seen.has(value))
59
+ return "[Circular]";
60
+ seen.add(value);
61
+ }
62
+ return value;
63
+ });
64
+ return json.length > MAX_ARG_LENGTH ? `${json.slice(0, MAX_ARG_LENGTH)}...` : json;
65
+ }
66
+ catch {
67
+ return String(arg);
68
+ }
69
+ }
70
+ return String(arg);
71
+ }
29
72
  export function log(level, message, ...args) {
30
73
  if (LEVEL_ORDER[level] < LEVEL_ORDER[currentLevel])
31
74
  return;
32
75
  const timestamp = new Date().toISOString();
33
76
  const safeMessage = redact(message);
34
- console.error(`[${timestamp}] [${level}] ${safeMessage}`, ...args);
77
+ const safeArgs = args.map((arg) => redact(serializeArg(arg)));
78
+ console.error(`[${timestamp}] [${level}] ${safeMessage}`, ...safeArgs);
35
79
  }
36
80
  // Override console.log in production to prevent accidental stdout writes
37
81
  export function enableStdoutGuard() {
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,IAAI,YAAY,GAAa,MAAM,CAAC;AAEpC,MAAM,WAAW,GAA6B;IAC5C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,KAAe;IACzC,YAAY,GAAG,KAAK,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,SAAS,MAAM,CAAC,KAAa;IAC3B,uBAAuB;IACvB,KAAK,GAAG,KAAK,CAAC,OAAO,CACnB,sDAAsD,EACtD,sBAAsB,CACvB,CAAC;IACF,iCAAiC;IACjC,KAAK,GAAG,KAAK,CAAC,OAAO,CACnB,0BAA0B,EAC1B,sBAAsB,CACvB,CAAC;IACF,0EAA0E;IAC1E,KAAK,GAAG,KAAK,CAAC,OAAO,CACnB,4BAA4B,EAC5B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,aAAa,CACjD,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,GAAG,CACjB,KAAe,EACf,OAAe,EACf,GAAG,IAAe;IAElB,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC;QAAE,OAAO;IAC3D,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,KAAK,KAAK,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;AACrE,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,IAAe,EAAE,EAAE;QACnC,OAAO,CAAC,KAAK,CACX,uDAAuD,EACvD,GAAG,IAAI,CACR,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,34 @@
1
1
  /**
2
- * Background npm update checker — non-blocking fetch on startup.
3
- * Compares installed version against latest on npm registry.
4
- * If a newer version exists, auto-updates (clears npx cache or
5
- * runs npm install -g) so the next launch picks up the new version.
2
+ * Background npm update checker: look, and tell, but never touch.
3
+ *
4
+ * On startup the server asks the npm registry for the latest published
5
+ * version. If it is newer than the running one, the user is told how to
6
+ * update. Nothing is ever installed by this module. The one side effect it
7
+ * keeps is scoped to this package's own stale npx cache directories, because
8
+ * clearing them is what lets `npx brightspace-mcp-server@latest` actually
9
+ * pick up the new version on the next start.
10
+ *
11
+ * Set D2L_NO_UPDATE_CHECK to any value to switch the check off entirely.
6
12
  */
7
- export declare function initUpdateChecker(): void;
13
+ /**
14
+ * True only when `latest` is strictly newer than `installed`, compared as
15
+ * numeric major, minor, patch. Prerelease suffixes are ignored, and anything
16
+ * that does not parse as a version is never "newer", so a registry hiccup
17
+ * cannot announce an update that does not exist.
18
+ */
19
+ export declare function isNewerVersion(latest: string, installed: string): boolean;
20
+ export interface UpdateCheckDeps {
21
+ fetchImpl?: typeof fetch;
22
+ env?: Record<string, string | undefined>;
23
+ installedVersion?: string;
24
+ runningFromNpxCache?: boolean;
25
+ clearCaches?: () => Promise<number>;
26
+ }
27
+ /**
28
+ * Run one update check. Never throws and never blocks the caller for long:
29
+ * the registry request is bounded by a timeout and every failure is
30
+ * swallowed, because a version check must not affect the server.
31
+ */
32
+ export declare function initUpdateChecker(deps?: UpdateCheckDeps): Promise<void>;
8
33
  export declare function getUpdateNotice(): string | null;
9
34
  //# sourceMappingURL=update-checker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-checker.d.ts","sourceRoot":"","sources":["../../src/utils/update-checker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwDH,wBAAgB,iBAAiB,IAAI,IAAI,CA8BxC;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAI/C"}
1
+ {"version":3,"file":"update-checker.d.ts","sourceRoot":"","sources":["../../src/utils/update-checker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA8DH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAQzE;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCjF;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAI/C"}
@@ -1,14 +1,23 @@
1
1
  /**
2
- * Background npm update checker — non-blocking fetch on startup.
3
- * Compares installed version against latest on npm registry.
4
- * If a newer version exists, auto-updates (clears npx cache or
5
- * runs npm install -g) so the next launch picks up the new version.
2
+ * Background npm update checker: look, and tell, but never touch.
3
+ *
4
+ * On startup the server asks the npm registry for the latest published
5
+ * version. If it is newer than the running one, the user is told how to
6
+ * update. Nothing is ever installed by this module. The one side effect it
7
+ * keeps is scoped to this package's own stale npx cache directories, because
8
+ * clearing them is what lets `npx brightspace-mcp-server@latest` actually
9
+ * pick up the new version on the next start.
10
+ *
11
+ * Set D2L_NO_UPDATE_CHECK to any value to switch the check off entirely.
6
12
  */
7
- import { exec } from "node:child_process";
8
13
  import { readFileSync } from "node:fs";
9
- import { rm } from "node:fs/promises";
14
+ import { access, readdir, rm } from "node:fs/promises";
15
+ import { homedir } from "node:os";
10
16
  import { fileURLToPath } from "node:url";
11
17
  import { dirname, resolve, sep } from "node:path";
18
+ const PACKAGE_NAME = "brightspace-mcp-server";
19
+ const REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
20
+ const REGISTRY_TIMEOUT_MS = 5000;
12
21
  const __filename = fileURLToPath(import.meta.url);
13
22
  const projectRoot = resolve(dirname(__filename), "..", "..");
14
23
  let notice = null;
@@ -25,65 +34,90 @@ function isNpxCache() {
25
34
  const normalized = projectRoot.split(sep).join("/");
26
35
  return /[\\/]_npx[\\/][^\\/]+[\\/]node_modules[\\/]brightspace-mcp-server/.test(normalized);
27
36
  }
37
+ /**
38
+ * Remove every npx cache entry that holds a copy of this package, so the next
39
+ * `npx brightspace-mcp-server@latest` downloads the new version instead of
40
+ * reusing a stale one. Touches nothing outside those directories.
41
+ */
28
42
  async function clearAllNpxCaches() {
29
- const { homedir } = await import("node:os");
30
43
  const npxCacheRoot = resolve(homedir(), ".npm", "_npx");
31
- const { readdir } = await import("node:fs/promises");
32
44
  let cleared = 0;
33
45
  try {
34
- const entries = await readdir(npxCacheRoot);
35
- for (const entry of entries) {
36
- const pkgPath = resolve(npxCacheRoot, entry, "node_modules", "brightspace-mcp-server");
46
+ for (const entry of await readdir(npxCacheRoot)) {
47
+ const entryDir = resolve(npxCacheRoot, entry);
37
48
  try {
38
- const { access } = await import("node:fs/promises");
39
- await access(pkgPath);
40
- await rm(resolve(npxCacheRoot, entry), { recursive: true, force: true });
49
+ await access(resolve(entryDir, "node_modules", PACKAGE_NAME));
50
+ await rm(entryDir, { recursive: true, force: true });
41
51
  cleared++;
42
52
  }
43
53
  catch {
44
- // Not a brightspace cache entry, skip
54
+ // Not one of ours, leave it alone.
45
55
  }
46
56
  }
47
57
  }
48
58
  catch {
49
- // npx cache dir doesn't exist or not readable
59
+ // No npx cache, or not readable. Nothing to clear.
50
60
  }
51
61
  return cleared;
52
62
  }
53
- const FALLBACK_MSG = (old, latest) => `Update available: v${old} → v${latest}. ` +
54
- "Run `npx brightspace-mcp-server@latest` or clear your npx cache to update.";
55
- export function initUpdateChecker() {
56
- const installed = getInstalledVersion();
57
- exec("npm view brightspace-mcp-server version", { timeout: 10000 }, (err, stdout) => {
58
- if (err)
63
+ function parseTriple(version) {
64
+ const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(version.trim());
65
+ if (!match)
66
+ return null;
67
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
68
+ }
69
+ /**
70
+ * True only when `latest` is strictly newer than `installed`, compared as
71
+ * numeric major, minor, patch. Prerelease suffixes are ignored, and anything
72
+ * that does not parse as a version is never "newer", so a registry hiccup
73
+ * cannot announce an update that does not exist.
74
+ */
75
+ export function isNewerVersion(latest, installed) {
76
+ const a = parseTriple(latest);
77
+ const b = parseTriple(installed);
78
+ if (!a || !b)
79
+ return false;
80
+ for (let i = 0; i < 3; i++) {
81
+ if (a[i] !== b[i])
82
+ return a[i] > b[i];
83
+ }
84
+ return false;
85
+ }
86
+ /**
87
+ * Run one update check. Never throws and never blocks the caller for long:
88
+ * the registry request is bounded by a timeout and every failure is
89
+ * swallowed, because a version check must not affect the server.
90
+ */
91
+ export async function initUpdateChecker(deps = {}) {
92
+ const { fetchImpl = fetch, env = process.env, installedVersion = getInstalledVersion(), runningFromNpxCache = isNpxCache(), clearCaches = clearAllNpxCaches, } = deps;
93
+ if (env.D2L_NO_UPDATE_CHECK)
94
+ return;
95
+ try {
96
+ const response = await fetchImpl(REGISTRY_URL, {
97
+ headers: { accept: "application/json" },
98
+ signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
99
+ });
100
+ if (!response.ok)
59
101
  return;
60
- const latest = stdout.trim();
61
- if (!latest || latest === installed)
102
+ const latest = (await response.json()).version;
103
+ if (typeof latest !== "string" || !isNewerVersion(latest, installedVersion))
62
104
  return;
63
- if (isNpxCache()) {
64
- clearAllNpxCaches()
65
- .then((count) => {
66
- notice =
67
- `Auto-updated: cleared ${count} npx cache(s) (v${installed} → v${latest}). ` +
68
- "The new version will be downloaded on next restart.";
69
- })
70
- .catch(() => {
71
- notice = FALLBACK_MSG(installed, latest);
72
- });
105
+ if (runningFromNpxCache) {
106
+ const count = await clearCaches();
107
+ notice =
108
+ `Update available: v${installedVersion} to v${latest}. ` +
109
+ `Cleared ${count} stale npx cache director${count === 1 ? "y" : "ies"} for ${PACKAGE_NAME} ` +
110
+ `so the next start downloads v${latest}. Restart your MCP client to pick it up.`;
73
111
  }
74
112
  else {
75
- exec("npm install -g brightspace-mcp-server@latest", { timeout: 60000 }, (installErr) => {
76
- if (installErr) {
77
- notice = FALLBACK_MSG(installed, latest);
78
- }
79
- else {
80
- notice =
81
- `Auto-updated from v${installed} to v${latest}. ` +
82
- "Restart your MCP client to use the new version.";
83
- }
84
- });
113
+ notice =
114
+ `Update available: v${installedVersion} to v${latest}. ` +
115
+ `Run: npx ${PACKAGE_NAME}@latest, or npm install -g ${PACKAGE_NAME}@latest`;
85
116
  }
86
- });
117
+ }
118
+ catch {
119
+ // A version check must never take the server down.
120
+ }
87
121
  }
88
122
  export function getUpdateNotice() {
89
123
  const result = notice;
@@ -1 +1 @@
1
- {"version":3,"file":"update-checker.js","sourceRoot":"","sources":["../../src/utils/update-checker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update-checker.js","sourceRoot":"","sources":["../../src/utils/update-checker.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brightspace-mcp-server",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "mcpName": "io.github.rohanmuppa/brightspace",
5
5
  "description": "MCP server for Brightspace (D2L). Check grades, due dates, assignments, announcements, syllabus, rosters and more via Claude, ChatGPT, Cursor, Windsurf, or any MCP client.",
6
6
  "type": "module",