canvas-lms-mcp 2.0.0 → 2.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.
- package/README.md +5 -5
- package/dist/canvas/activity-stream.d.ts +35 -0
- package/dist/canvas/activity-stream.d.ts.map +1 -0
- package/dist/canvas/client.d.ts +3 -1
- package/dist/canvas/client.d.ts.map +1 -1
- package/dist/canvas/index.cjs +3 -3
- package/dist/canvas/index.d.ts +4 -0
- package/dist/canvas/index.d.ts.map +1 -1
- package/dist/canvas/index.js +2 -2
- package/dist/canvas/planner.d.ts +31 -0
- package/dist/canvas/planner.d.ts.map +1 -0
- package/dist/canvas/types.d.ts +326 -1
- package/dist/canvas/types.d.ts.map +1 -1
- package/dist/{chunk-KNYGBEL5.cjs → chunk-C2C3TYWD.cjs} +16 -8
- package/dist/chunk-C2C3TYWD.cjs.map +1 -0
- package/dist/{chunk-66PSR2DZ.cjs → chunk-EMIO4XD4.cjs} +75 -4
- package/dist/chunk-EMIO4XD4.cjs.map +1 -0
- package/dist/{chunk-KHJEIVEQ.js → chunk-FKTJGYLG.js} +410 -9
- package/dist/chunk-FKTJGYLG.js.map +1 -0
- package/dist/{chunk-5B3JDDYC.js → chunk-FP4A34TD.js} +73 -2
- package/dist/chunk-FP4A34TD.js.map +1 -0
- package/dist/{chunk-AWI5UBRV.cjs → chunk-JR74DYXY.cjs} +805 -404
- package/dist/chunk-JR74DYXY.cjs.map +1 -0
- package/dist/{chunk-VVIZW7HE.js → chunk-W5DF5YBG.js} +13 -5
- package/dist/{chunk-VVIZW7HE.js.map → chunk-W5DF5YBG.js.map} +1 -1
- package/dist/http.cjs +6 -6
- package/dist/http.js +3 -3
- package/dist/init.cjs +3 -3
- package/dist/init.js +1 -1
- package/dist/provenance/fields.d.ts.map +1 -1
- package/dist/pseudonym/coverage.d.ts.map +1 -1
- package/dist/pseudonym/pseudonymizer.d.ts +118 -1
- package/dist/pseudonym/pseudonymizer.d.ts.map +1 -1
- package/dist/server.cjs +4 -4
- package/dist/server.js +3 -3
- package/dist/stdio.cjs +4 -4
- package/dist/stdio.js +3 -3
- package/dist/tools/student.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-5B3JDDYC.js.map +0 -1
- package/dist/chunk-66PSR2DZ.cjs.map +0 -1
- package/dist/chunk-AWI5UBRV.cjs.map +0 -1
- package/dist/chunk-KHJEIVEQ.js.map +0 -1
- package/dist/chunk-KNYGBEL5.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
MCP server for [Canvas LMS](https://www.instructure.com/canvas). Read courses, assignments, submissions, rubrics, quizzes; grade, comment, manage course content, and handle Canvas admin workflows from any AI agent.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
172 tools across Canvas courses, assignments, submissions, gradebook history, rubrics, quizzes, New Quizzes (LTI), files, users, groups, enrollments, discussions, modules, pages, calendar, conversations, peer reviews, accounts, analytics, outcomes, grading standards, grade projection, link audit, accessibility audit, content exports, content migrations, quiz accommodations, appointment groups, student workflows, student search, dashboard, instructor attention workflows, and health checks. Three deployment modes: stdio, HTTP, and library import.
|
|
15
15
|
|
|
16
16
|
## One-click install (Claude Desktop)
|
|
17
17
|
|
|
@@ -45,7 +45,7 @@ Installs the MCP server (via `npx canvas-lms-mcp`) and all 16 [Agent Skills](#ag
|
|
|
45
45
|
| | canvas-lms-mcp | [vishalsachdev/canvas-mcp](https://github.com/vishalsachdev/canvas-mcp) | [DMontgomery40/mcp-canvas-lms](https://github.com/DMontgomery40/mcp-canvas-lms) |
|
|
46
46
|
|---|---|---|---|
|
|
47
47
|
| Language | TypeScript | Python | TypeScript |
|
|
48
|
-
| Tools |
|
|
48
|
+
| Tools | 172 | 80+ | 54 |
|
|
49
49
|
| License | [](https://github.com/bruchris/canvas-lms-mcp/blob/main/LICENSE) | [](https://github.com/vishalsachdev/canvas-mcp/blob/main/LICENSE) | [](https://github.com/DMontgomery40/mcp-canvas-lms/blob/main/LICENSE) |
|
|
50
50
|
| Last commit | [](https://github.com/bruchris/canvas-lms-mcp) | [](https://github.com/vishalsachdev/canvas-mcp) | [](https://github.com/DMontgomery40/mcp-canvas-lms) |
|
|
51
51
|
|
|
@@ -152,7 +152,7 @@ Once configured, try these prompts with your AI client:
|
|
|
152
152
|
| Attention | `list_submission_comments_needing_attention`, `list_students_needing_attention` |
|
|
153
153
|
| FERPA (conditional) | `resolve_pseudonym` — stdio only, registered when `CANVAS_PSEUDONYMIZE_STUDENTS=true` and `CANVAS_PSEUDONYMIZE_REVERSE_LOOKUP=true` |
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
120 tools are read-only and 52 tools perform Canvas write operations. When FERPA mode is enabled **on the stdio transport**, `resolve_pseudonym` is registered as the 173rd tool overall (121st read tool). The HTTP transport never registers it — see [FERPA mode](#ferpa-mode-student-pseudonymization).
|
|
156
156
|
|
|
157
157
|
All write tools require appropriate Canvas permissions. Canvas enforces its own permission model -- the MCP server does not bypass it.
|
|
158
158
|
|
|
@@ -545,8 +545,8 @@ Three roles, plus the default of "unset = every tool":
|
|
|
545
545
|
|
|
546
546
|
| `CANVAS_ROLE` | Tools exposed | Typical use |
|
|
547
547
|
|---------------|---------------|-------------|
|
|
548
|
-
| _(unset)_ | all (~
|
|
549
|
-
| `student` | ~
|
|
548
|
+
| _(unset)_ | all (~172) | default; backwards-compatible |
|
|
549
|
+
| `student` | ~61 | a student's own courses, grades, submissions, and read-only course content |
|
|
550
550
|
| `teacher` | ~149 | grading, roster, content authoring, analytics |
|
|
551
551
|
| `admin` | ~161 | everything `teacher` sees plus account-level tools (`enroll_user`, `list_account_users`, …) |
|
|
552
552
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CanvasHttpClient } from './client';
|
|
2
|
+
import type { CanvasActivityStreamEntry, CanvasActivityStreamSummaryEntry } from './types';
|
|
3
|
+
export interface ActivityStreamQuery {
|
|
4
|
+
onlyActiveCourses?: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Stop following `Link: rel="next"` once this many items have accumulated.
|
|
7
|
+
* Bounds the WORK, not just the result: `paginate()` otherwise follows every
|
|
8
|
+
* page to exhaustion (up to `maxPaginationPages`, default 1000) before
|
|
9
|
+
* returning, so slicing afterwards would still have fetched up to 100,000
|
|
10
|
+
* items.
|
|
11
|
+
*/
|
|
12
|
+
maxItems?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class ActivityStreamModule {
|
|
15
|
+
private client;
|
|
16
|
+
constructor(client: CanvasHttpClient);
|
|
17
|
+
/**
|
|
18
|
+
* `GET /users/self/activity_stream/summary` is the one stream endpoint Canvas
|
|
19
|
+
* does not paginate (`api_render_stream_summary` has no `Api.paginate` call),
|
|
20
|
+
* so this uses `request()` rather than `paginate()` — the inverse of every
|
|
21
|
+
* other activity-stream endpoint.
|
|
22
|
+
*/
|
|
23
|
+
getSummary(onlyActiveCourses?: boolean): Promise<CanvasActivityStreamSummaryEntry[]>;
|
|
24
|
+
/**
|
|
25
|
+
* `GET /users/self/activity_stream` — the cross-course stream itself.
|
|
26
|
+
*
|
|
27
|
+
* Uses `paginate()`, which is not interchangeable with `request()` here:
|
|
28
|
+
* Canvas renders this endpoint through `Api.paginate(scope, self, …,
|
|
29
|
+
* default_per_page: 21)`, so a `request()` call would silently return 21
|
|
30
|
+
* items with no error and no `Link` header followed. `paginate()` sets
|
|
31
|
+
* `per_page=100` (Canvas's `MAX_PER_PAGE`) and follows the links.
|
|
32
|
+
*/
|
|
33
|
+
getStream(query?: ActivityStreamQuery): Promise<CanvasActivityStreamEntry[]>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=activity-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-stream.d.ts","sourceRoot":"","sources":["../../src/canvas/activity-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAAgC,EAAE,MAAM,SAAS,CAAA;AAE1F,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,qBAAa,oBAAoB;IACnB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAE5C;;;;;OAKG;IACG,UAAU,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,gCAAgC,EAAE,CAAC;IAO1F;;;;;;;;OAQG;IACG,SAAS,CAAC,KAAK,GAAE,mBAAwB,GAAG,OAAO,CAAC,yBAAyB,EAAE,CAAC;CAOvF"}
|
package/dist/canvas/client.d.ts
CHANGED
|
@@ -25,7 +25,9 @@ export declare class CanvasHttpClient {
|
|
|
25
25
|
* which is the expected response for DELETE operations.
|
|
26
26
|
*/
|
|
27
27
|
request<T>(endpoint: string, options?: CanvasRequestOptions): Promise<T>;
|
|
28
|
-
paginate<T>(endpoint: string, params?: CanvasQueryParams
|
|
28
|
+
paginate<T>(endpoint: string, params?: CanvasQueryParams, options?: {
|
|
29
|
+
maxItems?: number;
|
|
30
|
+
}): Promise<T[]>;
|
|
29
31
|
paginateEnvelope<T>(endpoint: string, envelopeKey: string, params?: CanvasQueryParams): Promise<T[]>;
|
|
30
32
|
/**
|
|
31
33
|
* The header block every Canvas request shares. Defining it in one place is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/canvas/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,SAAS,CAAA;AAEtE,qBAAa,cAAe,SAAQ,KAAK;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;gBAEJ,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAM9D;AAKD,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD;;;;OAIG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAA;CAC1B;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,kBAAkB,CAAQ;gBAEtB,MAAM,EAAE,kBAAkB;IAMtC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;;;OAIG;IACG,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,CAAC,CAAC;IA2C5E,QAAQ,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/canvas/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,SAAS,CAAA;AAEtE,qBAAa,cAAe,SAAQ,KAAK;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;gBAEJ,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAM9D;AAKD,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD;;;;OAIG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAA;CAC1B;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,kBAAkB,CAAQ;gBAEtB,MAAM,EAAE,kBAAkB;IAMtC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;;;OAIG;IACG,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,CAAC,CAAC;IA2C5E,QAAQ,CAAC,CAAC,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAC9B,OAAO,CAAC,CAAC,EAAE,CAAC;IA6CT,gBAAgB,CAAC,CAAC,EACtB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,iBAAiB,GACzB,OAAO,CAAC,CAAC,EAAE,CAAC;IAsCf;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IAQrB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,aAAa;CAKtB"}
|
package/dist/canvas/index.cjs
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkEMIO4XD4cjs = require('../chunk-EMIO4XD4.cjs');
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var _chunkC2C3TYWDcjs = require('../chunk-C2C3TYWD.cjs');
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
@@ -25,5 +25,5 @@ var _chunkKNYGBEL5cjs = require('../chunk-KNYGBEL5.cjs');
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
exports.CANVAS_MAX_ID =
|
|
28
|
+
exports.CANVAS_MAX_ID = _chunkEMIO4XD4cjs.CANVAS_MAX_ID; exports.CanvasApiError = _chunkC2C3TYWDcjs.CanvasApiError; exports.CanvasClient = _chunkEMIO4XD4cjs.CanvasClient; exports.CanvasHttpClient = _chunkC2C3TYWDcjs.CanvasHttpClient; exports.MAX_SAFE_CANVAS_NUMBER_ID = _chunkEMIO4XD4cjs.MAX_SAFE_CANVAS_NUMBER_ID; exports.appendCanvasQuery = _chunkC2C3TYWDcjs.appendCanvasQuery; exports.canvasIdInput = _chunkEMIO4XD4cjs.canvasIdInput; exports.canvasIdList = _chunkEMIO4XD4cjs.canvasIdList; exports.compareCanvasIds = _chunkEMIO4XD4cjs.compareCanvasIds; exports.normalizeCanvasIdInput = _chunkEMIO4XD4cjs.normalizeCanvasIdInput; exports.toCanvasQuery = _chunkC2C3TYWDcjs.toCanvasQuery;
|
|
29
29
|
//# sourceMappingURL=index.cjs.map
|
package/dist/canvas/index.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ import { ContentMigrationsModule } from './content-migrations';
|
|
|
25
25
|
import { GradingStandardsModule } from './grading-standards';
|
|
26
26
|
import { LatePolicyModule } from './late-policy';
|
|
27
27
|
import { AppointmentGroupsModule } from './appointment-groups';
|
|
28
|
+
import { ActivityStreamModule } from './activity-stream';
|
|
29
|
+
import { PlannerModule } from './planner';
|
|
28
30
|
/**
|
|
29
31
|
* Standalone Canvas REST API client. Composed of modular per-domain classes
|
|
30
32
|
* sharing a `CanvasHttpClient`. Throws `CanvasApiError` on Canvas-side failures.
|
|
@@ -65,6 +67,8 @@ export declare class CanvasClient {
|
|
|
65
67
|
gradingStandards: GradingStandardsModule;
|
|
66
68
|
latePolicy: LatePolicyModule;
|
|
67
69
|
appointmentGroups: AppointmentGroupsModule;
|
|
70
|
+
activityStream: ActivityStreamModule;
|
|
71
|
+
planner: PlannerModule;
|
|
68
72
|
constructor(config: CanvasClientConfig);
|
|
69
73
|
}
|
|
70
74
|
export { CanvasHttpClient, CanvasApiError } from './client';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/canvas/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/canvas/index.ts"],"names":[],"mappings":"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"}
|
package/dist/canvas/index.js
CHANGED
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
canvasIdList,
|
|
7
7
|
compareCanvasIds,
|
|
8
8
|
normalizeCanvasIdInput
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-FP4A34TD.js";
|
|
10
10
|
import {
|
|
11
11
|
CanvasApiError,
|
|
12
12
|
CanvasHttpClient,
|
|
13
13
|
appendCanvasQuery,
|
|
14
14
|
toCanvasQuery
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-W5DF5YBG.js";
|
|
16
16
|
export {
|
|
17
17
|
CANVAS_MAX_ID,
|
|
18
18
|
CanvasApiError,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CanvasHttpClient } from './client';
|
|
2
|
+
import type { CanvasPlannerItem } from './types';
|
|
3
|
+
export interface PlannerItemsQuery {
|
|
4
|
+
startDate?: string;
|
|
5
|
+
endDate?: string;
|
|
6
|
+
contextCodes?: string[];
|
|
7
|
+
filter?: 'new_activity' | 'incomplete_items' | 'complete_items';
|
|
8
|
+
/**
|
|
9
|
+
* Stop following `Link: rel="next"` once this many items have accumulated.
|
|
10
|
+
* Same rationale as `ActivityStreamQuery.maxItems`: bounds the WORK, not
|
|
11
|
+
* just the result.
|
|
12
|
+
*/
|
|
13
|
+
maxItems?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class PlannerModule {
|
|
16
|
+
private client;
|
|
17
|
+
constructor(client: CanvasHttpClient);
|
|
18
|
+
/**
|
|
19
|
+
* `GET /planner/items` — unions nine Canvas collections (assignments,
|
|
20
|
+
* ungraded quizzes, planner notes, wiki pages, ungraded discussions,
|
|
21
|
+
* calendar events, peer reviews, sub-assignments, peer-review
|
|
22
|
+
* sub-assignments) into one cross-course/cross-group feed.
|
|
23
|
+
*
|
|
24
|
+
* Uses `paginate()`: `Api.paginate(items, self, …)` sets no
|
|
25
|
+
* `default_per_page`, so Canvas falls back to `Api::PER_PAGE = 10` absent an
|
|
26
|
+
* explicit `per_page` (BRU-2797 §3.2) — the same `request()`-vs-`paginate()`
|
|
27
|
+
* hazard as the activity stream.
|
|
28
|
+
*/
|
|
29
|
+
listItems(query?: PlannerItemsQuery): Promise<CanvasPlannerItem[]>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=planner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/canvas/planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEhD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,MAAM,CAAC,EAAE,cAAc,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,gBAAgB;IAE5C;;;;;;;;;;OAUG;IACG,SAAS,CAAC,KAAK,GAAE,iBAAsB,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;CAY7E"}
|
package/dist/canvas/types.d.ts
CHANGED
|
@@ -285,12 +285,69 @@ export interface CanvasAttachment {
|
|
|
285
285
|
content_type: string;
|
|
286
286
|
size: number;
|
|
287
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* Canvas's `user_display_json` (`lib/api/v1/user.rb`): `{id, anonymous_id,
|
|
290
|
+
* display_name, avatar_image_url, html_url, pronouns}`, where `display_name` is
|
|
291
|
+
* `user.short_name` — a REAL NAME. It is returned `{}` when the user is nil, so
|
|
292
|
+
* every field is optional.
|
|
293
|
+
*
|
|
294
|
+
* This shape shows up wherever Canvas wants "enough to render a byline", and it
|
|
295
|
+
* is easy to miss because it spells the name `display_name` rather than `name`:
|
|
296
|
+
* a wrapper that looks for `name` / `user_name` / `author_name` walks straight
|
|
297
|
+
* past it. The pseudonymizer rewrites `display_name` and nulls the sibling
|
|
298
|
+
* `avatar_image_url` / `pronouns` — a face and a pronoun set beside a masked
|
|
299
|
+
* name are the same leak — but never `id` / `anonymous_id` / `html_url`, which
|
|
300
|
+
* are identifiers, and identifiers are preserved everywhere in this layer.
|
|
301
|
+
*/
|
|
302
|
+
export interface CanvasUserDisplay {
|
|
303
|
+
id?: CanvasId;
|
|
304
|
+
anonymous_id?: string;
|
|
305
|
+
display_name?: string;
|
|
306
|
+
avatar_image_url?: string | null;
|
|
307
|
+
html_url?: string;
|
|
308
|
+
pronouns?: string | null;
|
|
309
|
+
[key: string]: unknown;
|
|
310
|
+
}
|
|
288
311
|
export interface CanvasSubmissionComment {
|
|
289
312
|
id: CanvasId;
|
|
290
|
-
|
|
313
|
+
/**
|
|
314
|
+
* `null` when the viewer lacks `:read_author` on the comment:
|
|
315
|
+
* `submission_comment_json`'s `else` branch sets `author_id: nil` together
|
|
316
|
+
* with `author: {}` and `author_name: "Anonymous User"`
|
|
317
|
+
* (lib/api/v1/submission_comment.rb:68-72 at the pinned Canvas SHA
|
|
318
|
+
* 1c9f0bb8013ed69c4f2efe11fd483025469b7e6c).
|
|
319
|
+
*
|
|
320
|
+
* ~~Declared non-null.~~ Widened 2026-10-10 (BRU-2865): the declaration had
|
|
321
|
+
* contradicted that branch since the branch was first cited, and the two
|
|
322
|
+
* sites that key a pseudonym off this field were written against the
|
|
323
|
+
* declaration rather than the serializer. Derive the key with
|
|
324
|
+
* `submissionCommentAuthorKey` rather than `String(author_id)` — `null`
|
|
325
|
+
* means "this comment carries no identity at all", not "key the map on the
|
|
326
|
+
* string `null`".
|
|
327
|
+
*/
|
|
328
|
+
author_id: CanvasId | null;
|
|
291
329
|
author_name: string;
|
|
292
330
|
comment: string;
|
|
293
331
|
created_at: string;
|
|
332
|
+
/**
|
|
333
|
+
* `submission_comment_json` sets this to `user_display_json(comment.author,
|
|
334
|
+
* …)` whenever the viewer holds `:read_author` — so a comment normally
|
|
335
|
+
* carries the author's `display_name` BESIDE `author_name`, and masking only
|
|
336
|
+
* `author_name` leaves the real name one key over.
|
|
337
|
+
*
|
|
338
|
+
* ~~Optional because the anonymous-moderated branch replaces it with `{}`.~~
|
|
339
|
+
* Corrected 2026-10-10 (BRU-2864): it is `submission_comment_json`'s OWN
|
|
340
|
+
* `else` branch that sets `author: {}`, together with `author_id: nil` and
|
|
341
|
+
* `author_name: "Anonymous User"`, when the viewer lacks `:read_author`
|
|
342
|
+
* (lib/api/v1/submission_comment.rb:68-72 at the pinned Canvas SHA
|
|
343
|
+
* 1c9f0bb8013ed69c4f2efe11fd483025469b7e6c).
|
|
344
|
+
* `anonymous_moderated_submission_comments_json` — the serializer that does
|
|
345
|
+
* `json.delete(:author_id)` — never emits this key at all, because
|
|
346
|
+
* `ANONYMOUS_MODERATED_JSON_ATTRIBUTES` (lines 24-36) has no `author` entry.
|
|
347
|
+
* So there is no shape in either serializer where `author.id` survives an
|
|
348
|
+
* absent `author_id`, and this key is never a fallback source for it.
|
|
349
|
+
*/
|
|
350
|
+
author?: CanvasUserDisplay;
|
|
294
351
|
}
|
|
295
352
|
export interface CanvasGradebookHistoryGrader {
|
|
296
353
|
id: CanvasId;
|
|
@@ -873,6 +930,274 @@ export interface CanvasActivityStreamItem {
|
|
|
873
930
|
count: number;
|
|
874
931
|
unread_count: number;
|
|
875
932
|
}
|
|
933
|
+
/**
|
|
934
|
+
* One entry from GET /users/self/activity_stream/summary — `{type, count,
|
|
935
|
+
* unread_count}`. `CanvasActivityStreamItem` above already models this exact
|
|
936
|
+
* shape under a misleading name (it is used for the *course* activity stream
|
|
937
|
+
* summary, not a stream item); this is the correctly-named declaration for the
|
|
938
|
+
* cross-course summary endpoint. Renaming the existing type is tracked
|
|
939
|
+
* separately (BRU-2797 §1 C2, §11 Q4) and is not bundled here.
|
|
940
|
+
*/
|
|
941
|
+
export interface CanvasActivityStreamSummaryEntry {
|
|
942
|
+
type: string;
|
|
943
|
+
count: number;
|
|
944
|
+
unread_count: number;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* One `root_discussion_entries[]` entry on a `DiscussionTopic` / `Announcement`
|
|
948
|
+
* activity-stream item. Canvas caps the array at `StreamItem::LATEST_ENTRY_LIMIT`
|
|
949
|
+
* (3) at write time, and the nested `user` is the only place the stream spells a
|
|
950
|
+
* discussion author with an identifier beside the name.
|
|
951
|
+
*
|
|
952
|
+
* `user_id` can be missing or `null` — the pinned serializer SHA
|
|
953
|
+
* (1c9f0bb8013ed69c4f2efe11fd483025469b7e6c) can emit this nested `user`
|
|
954
|
+
* object with no usable identity (BRU-2868). There is nothing to key a stable
|
|
955
|
+
* pseudonym on in that case; see `anonymizeActivityStreamEntry`.
|
|
956
|
+
*/
|
|
957
|
+
export interface CanvasActivityStreamRootEntry {
|
|
958
|
+
user: {
|
|
959
|
+
user_id?: CanvasId | null;
|
|
960
|
+
user_name: string;
|
|
961
|
+
};
|
|
962
|
+
message: string | null;
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* One `latest_messages[]` entry on a `Conversation` activity-stream item, built
|
|
966
|
+
* by `StreamItem#prepare_conversation`: `{id, created_at, author_id, message,
|
|
967
|
+
* participating_user_ids}`.
|
|
968
|
+
*
|
|
969
|
+
* Note what is NOT here: no name of any kind. The stream's conversation arm
|
|
970
|
+
* carries identifiers and message text only, which is why
|
|
971
|
+
* `Pseudonymizer.anonymizeActivityStream` has nothing to rewrite on it (the
|
|
972
|
+
* pseudonymizer rewrites names, never ids — `applyPseudonymToUser` preserves
|
|
973
|
+
* `user.id`). The message body is handled by provenance fencing instead.
|
|
974
|
+
*/
|
|
975
|
+
export interface CanvasActivityStreamConversationMessage {
|
|
976
|
+
id: CanvasId;
|
|
977
|
+
created_at: string;
|
|
978
|
+
author_id: CanvasId;
|
|
979
|
+
message: string;
|
|
980
|
+
participating_user_ids: CanvasId[];
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* One `discussion_entries[]` entry on the activity stream's `Submission` arm.
|
|
984
|
+
*
|
|
985
|
+
* `submission_attempt_json` emits `discussion_entries` for any submission to a
|
|
986
|
+
* `discussion_topic` assignment — it is in the default-on
|
|
987
|
+
* `SUBMISSION_OTHER_FIELDS`, and the stream narrows nothing — by calling
|
|
988
|
+
* `discussion_entry_api_json(entries, topic.context, user, session)` with four
|
|
989
|
+
* arguments, i.e. under the default `includes = %i[user_name subentries
|
|
990
|
+
* display_user]`.
|
|
991
|
+
*
|
|
992
|
+
* All three identity surfaces below can carry a real name, and they do NOT
|
|
993
|
+
* appear together. Per `serialize_entry`, `user_name` and `user_id` are both
|
|
994
|
+
* omitted when the entry is deleted, while `user` is emitted whenever
|
|
995
|
+
* `:display_user` is in includes — that guard has no `deleted?` check. So a
|
|
996
|
+
* deleted entry is `{user: {id, display_name, …}}` with no `user_id` and no
|
|
997
|
+
* `user_name`: keying off `user_name` alone silently passes that name through.
|
|
998
|
+
*
|
|
999
|
+
* `recent_replies` is the recursion and the only subentry key upstream emits
|
|
1000
|
+
* (`discussion_entry_subentries`, capped at 10 with `has_more_replies`).
|
|
1001
|
+
* Upstream nests exactly one level — the method returns `{}` unless
|
|
1002
|
+
* `entry.root_entry_id.nil?` — but this type and its pseudonymizer are
|
|
1003
|
+
* recursive regardless, because a depth assumption is not worth a leak.
|
|
1004
|
+
*/
|
|
1005
|
+
export interface CanvasSubmissionDiscussionEntry {
|
|
1006
|
+
id?: CanvasId;
|
|
1007
|
+
created_at?: string;
|
|
1008
|
+
updated_at?: string;
|
|
1009
|
+
parent_id?: CanvasId | null;
|
|
1010
|
+
/** Omitted when the entry is deleted. */
|
|
1011
|
+
user_id?: CanvasId;
|
|
1012
|
+
/** Omitted when the entry is deleted. */
|
|
1013
|
+
user_name?: string;
|
|
1014
|
+
/** Present even on a deleted entry — see the note above. */
|
|
1015
|
+
user?: CanvasUserDisplay;
|
|
1016
|
+
editor_id?: CanvasId;
|
|
1017
|
+
message?: string;
|
|
1018
|
+
deleted?: boolean;
|
|
1019
|
+
recent_replies?: CanvasSubmissionDiscussionEntry[];
|
|
1020
|
+
has_more_replies?: boolean;
|
|
1021
|
+
[key: string]: unknown;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* One entry from `GET /users/self/activity_stream`.
|
|
1025
|
+
*
|
|
1026
|
+
* `context_type` is `"Course"` | `"Group"` and EXACTLY ONE of `course_id` /
|
|
1027
|
+
* `group_id` is present — the key name is derived from the context type by
|
|
1028
|
+
* Canvas's `Api::V1::Context#context_data`, so the other key is ABSENT, not
|
|
1029
|
+
* null. Canvas's own doc block shows both keys with `group_id: null`; it is
|
|
1030
|
+
* wrong. Every optional field is therefore `?` and never `| null`: a
|
|
1031
|
+
* `null`-checking consumer cannot detect an absent key.
|
|
1032
|
+
*
|
|
1033
|
+
* The index signature is deliberate, not laziness. The `Submission` arm merges a
|
|
1034
|
+
* whole `submission_json(submission, assignment, …, includes = %w[submission_comments
|
|
1035
|
+
* assignment course html_url user])` into the item, so the key set of that one arm
|
|
1036
|
+
* is as wide as Canvas's submission serializer and grows with it. The fields named
|
|
1037
|
+
* below are the ones this server reads, pseudonymizes or fences; everything else
|
|
1038
|
+
* passes through untyped rather than being silently dropped from the declaration.
|
|
1039
|
+
*/
|
|
1040
|
+
export interface CanvasActivityStreamEntry {
|
|
1041
|
+
/** The stream item's own id, not the underlying object's. */
|
|
1042
|
+
id: CanvasId;
|
|
1043
|
+
created_at: string;
|
|
1044
|
+
updated_at: string;
|
|
1045
|
+
title: string | null;
|
|
1046
|
+
message: string | null;
|
|
1047
|
+
/**
|
|
1048
|
+
* A Ruby class name (`stream_item.data.class.name`), overwritten to
|
|
1049
|
+
* `"WebConference"` / `"Collaboration"` for those arms. Not a closed set —
|
|
1050
|
+
* `(string & {})` keeps it open, because the value is computed at runtime and
|
|
1051
|
+
* the serializer's `else` arm raises rather than enumerating.
|
|
1052
|
+
*/
|
|
1053
|
+
type: 'DiscussionTopic' | 'Announcement' | 'Conversation' | 'Message' | 'Submission' | 'WebConference' | 'Collaboration' | 'AssessmentRequest' | 'DiscussionEntry' | (string & {});
|
|
1054
|
+
/** Re-derived from `conversation_participants` on the `Conversation` arm, where it may be null. */
|
|
1055
|
+
read_state: boolean | null;
|
|
1056
|
+
context_type?: 'Course' | 'Group' | (string & {});
|
|
1057
|
+
course_id?: CanvasId;
|
|
1058
|
+
group_id?: CanvasId;
|
|
1059
|
+
html_url?: string;
|
|
1060
|
+
/** `Message` items set `url` alongside `html_url`, both from `data.url`. */
|
|
1061
|
+
url?: string;
|
|
1062
|
+
discussion_topic_id?: CanvasId;
|
|
1063
|
+
announcement_id?: CanvasId;
|
|
1064
|
+
total_root_discussion_entries?: number;
|
|
1065
|
+
require_initial_post?: boolean | null;
|
|
1066
|
+
user_has_posted?: boolean | null;
|
|
1067
|
+
root_discussion_entries?: CanvasActivityStreamRootEntry[];
|
|
1068
|
+
conversation_id?: CanvasId;
|
|
1069
|
+
private?: boolean;
|
|
1070
|
+
participant_count?: number;
|
|
1071
|
+
latest_messages?: CanvasActivityStreamConversationMessage[];
|
|
1072
|
+
message_id?: CanvasId;
|
|
1073
|
+
notification_category?: string | null;
|
|
1074
|
+
submission_id?: CanvasId;
|
|
1075
|
+
assignment_id?: CanvasId;
|
|
1076
|
+
user_id?: CanvasId;
|
|
1077
|
+
grader_id?: CanvasId | null;
|
|
1078
|
+
body?: string | null;
|
|
1079
|
+
user?: CanvasUser;
|
|
1080
|
+
submission_comments?: CanvasSubmissionComment[];
|
|
1081
|
+
/**
|
|
1082
|
+
* Discussion-topic submissions only, but default-on when they occur — see
|
|
1083
|
+
* {@link CanvasSubmissionDiscussionEntry}. Name-bearing and recursive.
|
|
1084
|
+
*/
|
|
1085
|
+
discussion_entries?: CanvasSubmissionDiscussionEntry[];
|
|
1086
|
+
/**
|
|
1087
|
+
* `attempt.proxy_submitter.short_name` — a BARE STRING, not a user object,
|
|
1088
|
+
* emitted with its `proxy_submitter_id` sibling whenever
|
|
1089
|
+
* `attempt.proxy_submission?`. Because it is a naked string there is no
|
|
1090
|
+
* `user`-shaped container for a generic walker to find.
|
|
1091
|
+
*/
|
|
1092
|
+
proxy_submitter?: string;
|
|
1093
|
+
proxy_submitter_id?: CanvasId;
|
|
1094
|
+
web_conference_id?: CanvasId;
|
|
1095
|
+
collaboration_id?: CanvasId;
|
|
1096
|
+
assessment_request_id?: CanvasId;
|
|
1097
|
+
/**
|
|
1098
|
+
* `DiscussionEntry` only. The serializer emits this name with NO accompanying
|
|
1099
|
+
* identifier (`hash["author_name"] = discussion_entry.author_name` is the whole
|
|
1100
|
+
* arm beside `message`), so a stable pseudonym is not derivable for it — see
|
|
1101
|
+
* `Pseudonymizer.anonymizeActivityStream`.
|
|
1102
|
+
*/
|
|
1103
|
+
author_name?: string;
|
|
1104
|
+
[key: string]: unknown;
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* `PlannerOverride` json from `planner_override_json` — present only when the
|
|
1108
|
+
* student has toggled an item's planner visibility ("mark as done" /
|
|
1109
|
+
* "dismiss"). It is `api_json` on the AR record plus a re-derived
|
|
1110
|
+
* `plannable_type` and `assignment_id`. None of its fields identify anyone
|
|
1111
|
+
* but the authenticated caller — it is their own planner override.
|
|
1112
|
+
*/
|
|
1113
|
+
export interface CanvasPlannerOverride {
|
|
1114
|
+
id: CanvasId;
|
|
1115
|
+
plannable_id: CanvasId;
|
|
1116
|
+
plannable_type: string;
|
|
1117
|
+
user_id: CanvasId;
|
|
1118
|
+
assignment_id: CanvasId | null;
|
|
1119
|
+
marked_complete: boolean;
|
|
1120
|
+
dismissed: boolean;
|
|
1121
|
+
created_at: string;
|
|
1122
|
+
updated_at: string;
|
|
1123
|
+
deleted_at: string | null;
|
|
1124
|
+
[key: string]: unknown;
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* The caller's own submission status on a planner item's underlying
|
|
1128
|
+
* Assignment / SubAssignment / PeerReviewSubAssignment, from
|
|
1129
|
+
* `submission_statuses_for` → `submission_statuses`.
|
|
1130
|
+
*/
|
|
1131
|
+
export interface CanvasPlannerSubmissionStatus {
|
|
1132
|
+
submitted?: boolean;
|
|
1133
|
+
excused?: boolean;
|
|
1134
|
+
graded?: boolean;
|
|
1135
|
+
posted_at?: string | null;
|
|
1136
|
+
late?: boolean;
|
|
1137
|
+
missing?: boolean;
|
|
1138
|
+
needs_grading?: boolean;
|
|
1139
|
+
has_feedback?: boolean;
|
|
1140
|
+
redo_request?: boolean;
|
|
1141
|
+
feedback?: {
|
|
1142
|
+
comment: string;
|
|
1143
|
+
is_media: boolean;
|
|
1144
|
+
author_name?: string;
|
|
1145
|
+
author_avatar_url?: string | null;
|
|
1146
|
+
};
|
|
1147
|
+
[key: string]: unknown;
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* One entry from `GET /planner/items`.
|
|
1151
|
+
*
|
|
1152
|
+
* `context_type` / `course_id` / `group_id` share the exact derivation and
|
|
1153
|
+
* absent-not-null caveat as {@link CanvasActivityStreamEntry}
|
|
1154
|
+
* (`Api::V1::Context#context_data`, BRU-2797 §1 C7) — a group-context item
|
|
1155
|
+
* has no `course_id` key at all, not a null one.
|
|
1156
|
+
*
|
|
1157
|
+
* `plannable` is the polymorphic underlying object; its shape is keyed by
|
|
1158
|
+
* `plannable_type` and varies per arm (`lib/api/v1/planner_item.rb`
|
|
1159
|
+
* `planner_item_json`, pinned SHA 1c9f0bb8013ed69c4f2efe11fd483025469b7e6c).
|
|
1160
|
+
* No arm carries a third-party user record — the richest is `planner_note`,
|
|
1161
|
+
* whose own `user_id` is the authenticated caller's own id, never another
|
|
1162
|
+
* student's (BRU-2797 §6.1) — so this is declared as a loose object rather
|
|
1163
|
+
* than a per-arm union.
|
|
1164
|
+
*/
|
|
1165
|
+
export interface CanvasPlannerItem {
|
|
1166
|
+
context_type?: 'Course' | 'Group' | (string & {});
|
|
1167
|
+
course_id?: CanvasId;
|
|
1168
|
+
group_id?: CanvasId;
|
|
1169
|
+
/** The caller's own course nickname when set, else the course name — join on `course_id`, never this. */
|
|
1170
|
+
context_name?: string;
|
|
1171
|
+
context_image?: string | null;
|
|
1172
|
+
plannable_id: CanvasId;
|
|
1173
|
+
/**
|
|
1174
|
+
* A `PlannerHelper::PLANNABLE_TYPES` key — snake_case, NOT the Ruby class
|
|
1175
|
+
* name, unlike the activity stream's `type`. Not a closed set — kept open
|
|
1176
|
+
* with `(string & {})` for the same reason as the activity stream's `type`.
|
|
1177
|
+
*/
|
|
1178
|
+
plannable_type: 'assignment' | 'quiz' | 'planner_note' | 'wiki_page' | 'discussion_topic' | 'announcement' | 'calendar_event' | 'assessment_request' | 'sub_assignment' | 'peer_review_sub_assignment' | (string & {});
|
|
1179
|
+
/** `null` unless the student has toggled this item's planner visibility. */
|
|
1180
|
+
planner_override: CanvasPlannerOverride | null;
|
|
1181
|
+
/**
|
|
1182
|
+
* `false` or an object — a union, not a nullable object. Canvas initialises
|
|
1183
|
+
* `submission_status = { submissions: false }` and only replaces it with a
|
|
1184
|
+
* hash for a submittable plannable; a consumer writing
|
|
1185
|
+
* `item.submissions?.graded` would silently read `undefined` on the
|
|
1186
|
+
* boolean arm if this were declared `CanvasPlannerSubmissionStatus | null`.
|
|
1187
|
+
*/
|
|
1188
|
+
submissions: false | CanvasPlannerSubmissionStatus;
|
|
1189
|
+
new_activity: boolean;
|
|
1190
|
+
plannable_date: string;
|
|
1191
|
+
/** The polymorphic underlying object. Shape varies by `plannable_type`; no arm carries a third-party user record. */
|
|
1192
|
+
plannable: Record<string, unknown>;
|
|
1193
|
+
/** Absent for `planner_note` items — Canvas has no html_url for individual planner notes. */
|
|
1194
|
+
html_url?: string;
|
|
1195
|
+
/** `sub_assignment` discussion-checkpoint items only. */
|
|
1196
|
+
details?: {
|
|
1197
|
+
reply_to_entry_required_count: number;
|
|
1198
|
+
};
|
|
1199
|
+
[key: string]: unknown;
|
|
1200
|
+
}
|
|
876
1201
|
export interface CanvasStudentSummary {
|
|
877
1202
|
id: CanvasId;
|
|
878
1203
|
page_views: number;
|