Skip to content

feat(canvas): add Canvas LMS - #487

Open
Dhirenderchoudhary wants to merge 10 commits into
corsairdev:mainfrom
Dhirenderchoudhary:feat/canvas-plugin
Open

feat(canvas): add Canvas LMS#487
Dhirenderchoudhary wants to merge 10 commits into
corsairdev:mainfrom
Dhirenderchoudhary:feat/canvas-plugin

Conversation

@Dhirenderchoudhary

@Dhirenderchoudhary Dhirenderchoudhary commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR introduces a comprehensive Canvas LMS integration to Corsair.

Key Features:

  • Added canvas plugin with over 200+ REST and GraphQL endpoints.
  • Implemented operations registry covering courses, assignments, quizzes, modules, discussions, conversations, groups, enrollments, and more.
  • Built on the data-driven factory pattern with autogenerated input/output Zod schemas, endpoint metadata, and risk levels.
  • Full support for both Bearer token (API key) and OAuth 2.0 authentication flows.
  • Added dynamic baseUrl resolution to accommodate both cloud and self-hosted Canvas instances.
  • 100% type safety with zero TypeScript errors and passing test suites.

Closes #486

Checklist

Before submitting your PR, please verify the following:

  • I have run pnpm lint and all checks pass (Note: passed for canvas package)
  • I have run pnpm typecheck and there are no TypeScript errors
  • I have run pnpm build and all packages build successfully
  • I have run pnpm test and all tests pass (Canvas tests passing 5/5)
  • I have added or updated tests where applicable
  • I have added or updated necessary documentation

Screenshots / Demos (if applicable)

Screenshot 2026-07-22 at 1 21 23 PM

Additional Notes

  • Dependencies: Uses standard Corsair core utilities. No external dependencies were added to the monorepo root.
  • Webhooks: Webhook tenant matchers and signatures are configured using standard Canvas header specifications (x-canvas-signature).

Summary by CodeRabbit

  • New Features
    • Added Canvas LMS integration with typed API access across courses, users, assignments, grading, files, discussions, reports, and more.
    • Added API key, OAuth, and webhook authentication support.
    • Added verified webhook triggers for assignments, submissions, discussions, file uploads, and course creation.
    • Added request and response validation, rate-limit retries, and authentication error handling.
    • Added Canvas tenant matching and OAuth tenant linking.
    • Added route metadata and risk classification for supported operations.
  • Tests
    • Added comprehensive coverage for API requests, schemas, authentication, tenant linking, and webhook verification.

@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@Dhirenderchoudhary is attempting to deploy a commit to the corsair Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the core Changes in packages/corsair label Jul 22, 2026
@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Canvas LMS integration now includes:

  • A data-driven endpoint registry with runtime input and output validation.
  • Per-instance HTTPS base URL resolution and bearer-authenticated HTTP requests.
  • API-key and OAuth authentication flows.
  • Signed webhook handling with numeric and UUID tenant-link namespaces.
  • Behavioral coverage for endpoint dispatch, schemas, authentication, tenant resolution, and webhook verification.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/canvas/client.ts Implements HTTPS instance normalization, path interpolation, Canvas query serialization, bearer authentication, and transport-level rate-limit retries.
packages/canvas/endpoints/factory.ts Resolves the configured Canvas instance and applies operation-specific input and output schemas around each request.
packages/canvas/endpoints/types.ts Requires declared path parameters and mutation bodies while preserving bodyless Canvas actions.
packages/canvas/endpoints/response-schemas.ts Defines operation-aware response schemas for REST collections, resource objects, GraphQL responses, deletions, and text downloads.
packages/canvas/webhooks/types.ts Parses Canvas event names and authenticates webhook payloads with a non-empty secret, raw body, and timing-safe HMAC comparison.
packages/canvas/webhooks/tenant-matcher.ts Routes webhook tenants through distinct numeric account-ID and root-account UUID namespaces.
packages/canvas/webhooks/oauth-tenant-link.ts Resolves OAuth tenant links from token metadata or an unambiguous Canvas account lookup.
packages/canvas/api.test.ts Exercises all registered operations and validates URL resolution, serialization, schemas, authentication, webhook verification, and tenant linking.
packages/canvas/index.ts Registers Canvas authentication, endpoints, schemas, metadata, webhooks, tenant matching, and instance-specific OAuth configuration.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Caller["Canvas endpoint caller"] --> Input["Validate operation input"]
  Input --> BaseURL["Resolve plugin or account base URL"]
  BaseURL --> HTTP["Canvas REST / GraphQL request"]
  HTTP --> Output["Validate operation response"]
  Output --> Result["Return typed result"]
  Canvas["Canvas Live Event"] --> Match["Match event and tenant"]
  Match --> Verify["Verify HMAC signature"]
  Verify --> Trigger["Dispatch webhook trigger"]
Loading

Reviews (13): Last reviewed commit: "feat(canvas): add Canvas API response sc..." | Re-trigger Greptile

Comment thread packages/canvas/webhooks/types.ts Outdated
Comment thread packages/canvas/endpoints/factory.ts Outdated
Comment thread packages/canvas/client.ts Outdated
Comment thread packages/canvas/endpoints/factory.ts Outdated
Comment thread packages/canvas/endpoints/types.ts Outdated
Comment thread packages/canvas/webhooks/tenant-matcher.ts Outdated
Comment thread packages/canvas/schema.test.ts
Comment thread packages/canvas/endpoints/example.ts Outdated
Comment thread packages/canvas/schema/database.ts Outdated
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Plugin PR scorecard — packages/canvas

Check Status Notes
R1 — Scope: plugin files only
R2 — Tests with assertions
R3 — Description complete
R3 — Linked issue / claim
R4 — Demo video / recording

Rules: PLUGIN_PR_RULES.md · re-runs on every push

@github-actions github-actions Bot added the gate:failed Plugin PR gate checks failing label Jul 22, 2026
@github-actions

Copy link
Copy Markdown

Hey @Dhirenderchoudhary, thanks for the contribution! 🏴‍☠️ Before a maintainer reviews, please fix the items below — the review re-runs automatically on your next push.

Must fix

  • P1 packages/canvas/webhooks/types.ts:61Webhook Verification Always Succeeds
    Any request whose payload has type: "example" and whose headers pass the plugin matcher is accepted without checking its signature, raw body, or secret. An attacker can forge an event that the handler records and returns as authentic.

Rule Used: Flag boilerplate residue from the plugin generator... (source)

  • P1 packages/canvas/endpoints/factory.ts:28Configured Instance URL Is Dropped
    The factory does not pass the plugin's baseUrl to makeCanvasRequest. Calling an endpoint after configuring a self-hosted Canvas instance therefore sends the request and bearer token to the default canvas.instructure.com host instead of the configured institution.

Rule Used: Verify the implementation matches the PR descripti... (source)

  • P1 packages/canvas/client.ts:83Error Wrapping Removes Rate Limits
    A Canvas 429 is converted from ApiError to CanvasAPIError, discarding its status and retryAfter. When the message does not contain the literal text 429 or rate_limited, the registered rate-limit matcher misses it and the request receives no retries.

Rule Used: Every endpoint must validate inputs and outputs wi... (source)

  • P1 packages/canvas/endpoints/factory.ts:29Responses Bypass Zod Validation
    The generic type argument only affects TypeScript and does not parse the response with CanvasEndpointOutputSchemas[name]. A malformed response, including an array where the public schema promises a record, is returned to callers without the required output validation.

Rule Used: Every endpoint must validate inputs and outputs wi... (source)

  • P1 packages/canvas/endpoints/types.ts:44Mutation Bodies Remain Optional
    Both sides of the needsBody condition use bodySchema.optional(). Create and update endpoints therefore accept missing bodies and send undefined to Canvas, even when the operation requires request data, shifting a known input error into a remote API failure.

Rule Used: Every endpoint must validate inputs and outputs wi... (source)

  • P1 packages/canvas/webhooks/tenant-matcher.ts:24Placeholder Tenant Field Blocks Routing
    The matcher only recognizes the scaffold field tenant_external_id. A Canvas event without that invented field returns null, while the OAuth resolver also returns null unless the token response contains the same placeholder, so connected accounts cannot establish or resolve a tenant routing key.

Rule Used: Flag boilerplate residue from the plugin generator... (source)

  • P1 packages/canvas/schema.test.ts:46Endpoints Have No Behavioral Tests
    These tests only inspect registry metadata and schema presence; none of the implemented endpoints is called or checked for its URL, serialized input, response validation, or error handling. This leaves every real endpoint without the corresponding test required for a plugin implementation.

Rule Used: Flag any types on exported or public surfaces as... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  • P1 packages/canvas/endpoints/example.ts:3Generator Placeholder Remains
    This is the generator's leftover endpoints/example.ts placeholder rather than part of the factory implementation. The plugin rules explicitly reject this residue in a completed integration.

Rule Used: Flag boilerplate residue from the plugin generator... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  • P1 packages/canvas/schema/database.ts:9Database Schema Is Still Scaffolded
    The file retains the generator TODO and commented example entity while CanvasSchema.entities remains empty. This is prohibited boilerplate residue; either implement the intended persisted entities or remove the unused scaffold.

Rule Used: Flag boilerplate residue from the plugin generator... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

PR requirements (rules)

  • R4 — Required in "Screenshots / Demos" before a maintainer reviews

If anything remains after your next push, a bot commit will clean it up; a maintainer always does the final review and merge.

@github-actions github-actions Bot added the bot:round-1 Review bot posted consolidated findings label Jul 22, 2026
Comment thread packages/canvas/endpoints/types.ts Outdated
@github-actions github-actions Bot added bot:round-2 Review bot pushed an automated fix and removed gate:failed Plugin PR gate checks failing labels Jul 22, 2026
@github-actions

Copy link
Copy Markdown

Remaining findings are being fixed by a bot commit — it will be re-reviewed automatically.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Maintainer review needed

Automated rounds are exhausted. Remaining findings:

  • P1 packages/canvas/webhooks/tenant-matcher.tsTenant identifier namespaces conflict
    When a Canvas Live Event identifies its tenant through metadata.root_account_uuid without an earlier numeric account ID, this matcher returns the UUID as a canvas_account_id, while the OAuth resolver persists a numeric account ID under that link type. Exact tenant-link lookup therefore cannot match the valid webhook to its connected account.

Knowledge Base Used: The provider-plugin package pattern

@github-actions github-actions Bot added the needs-maintainer Automated rounds exhausted - human review needed label Jul 22, 2026
Comment thread packages/canvas/webhooks/types.ts
@Dhirenderchoudhary Dhirenderchoudhary removed the needs-maintainer Automated rounds exhausted - human review needed label Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 664341ca-1891-40b1-9464-aff129e93e2b

📥 Commits

Reviewing files that changed from the base of the PR and between 382007f and 6a8a7b6.

📒 Files selected for processing (6)
  • packages/canvas/api.test.ts
  • packages/canvas/endpoints/response-schemas.ts
  • packages/canvas/endpoints/types.ts
  • packages/canvas/schema.test.ts
  • packages/canvas/webhooks/oauth-tenant-link.ts
  • packages/canvas/webhooks/tenant-matcher.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/canvas/schema.test.ts
  • packages/canvas/endpoints/types.ts
  • packages/canvas/webhooks/oauth-tenant-link.ts
  • packages/canvas/api.test.ts
  • packages/canvas/webhooks/tenant-matcher.ts

📝 Walkthrough

Walkthrough

Adds a Canvas LMS provider with typed REST and GraphQL operations, authenticated requests, endpoint schemas, API-key and OAuth support, webhook verification and triggers, tenant resolution, packaging, tests, and provider registration.

Changes

Canvas operation contracts

Layer / File(s) Summary
Operation catalog, routes, and schemas
packages/canvas/endpoints/operations.ts, packages/canvas/endpoints/routes.ts, packages/canvas/endpoints/types.ts, packages/canvas/endpoints/response-schemas.ts
Defines Canvas REST and GraphQL operations, route metadata, typed request inputs, response outputs, and generated Zod schemas.

Canvas endpoint execution

Layer / File(s) Summary
Request client and endpoint factory
packages/canvas/client.ts, packages/canvas/endpoints/factory.ts, packages/canvas/endpoints/index.ts, packages/canvas/error-handlers.ts
Normalizes base URLs, encodes paths, sends authenticated requests, applies retry handling, validates inputs and responses, and exports grouped endpoints.

Canvas plugin wiring and packaging

Layer / File(s) Summary
Plugin registration and package setup
packages/canvas/index.ts, packages/canvas/schema/index.ts, packages/canvas/package.json, packages/canvas/tsconfig.json, packages/canvas/tsup.config.ts, packages/canvas/jest.config.cjs, packages/corsair/core/constants.ts
Registers endpoint and webhook catalogs, configures authentication and metadata, resolves credentials, exports types, registers Canvas as a provider, and defines package tooling.

Canvas webhook support

Layer / File(s) Summary
Webhook schemas, verification, triggers, and tenant resolution
packages/canvas/webhooks/*
Adds payload schemas, event matching, HMAC-SHA256 verification, tenant matching, OAuth tenant links, and six webhook triggers.

Validation

Layer / File(s) Summary
Schema and integration tests
packages/canvas/schema.test.ts, packages/canvas/api.test.ts
Tests operation coverage, endpoint requests, base URL resolution, mutation bodies, response arrays, webhook verification, event matching, rate-limit handling, and tenant resolution.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • corsairdev/corsair#369: Adds a provider plugin with typed API clients, endpoint catalogs, schemas, authentication, error handling, and package wiring.

Suggested reviewers: devjain32

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding the Canvas LMS integration.
Linked Issues check ✅ Passed The PR satisfies the core [#486] objectives with broad Canvas coverage, dual authentication, tenant base URLs, rate-limit handling, and webhook support.
Out of Scope Changes check ✅ Passed All changes support the Canvas integration, package setup, tests, or provider registration; no unrelated scope is evident.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added ci CI / GitHub Actions app App / Hub-facing app code docs Docs / Mintlify / markdown changes plugin Changes inside a plugin package cli CLI package changes labels Aug 3, 2026
Comment thread packages/canvas/client.ts Fixed
@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator Author

@greptile review

@Dhirenderchoudhary Dhirenderchoudhary removed ci CI / GitHub Actions app App / Hub-facing app code docs Docs / Mintlify / markdown changes labels Aug 3, 2026
@Dhirenderchoudhary Dhirenderchoudhary removed the cli CLI package changes label Aug 3, 2026
Comment thread packages/canvas/endpoints/types.ts Outdated
@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator Author

@greptile review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (9)
packages/corsair/core/constants.ts (1)

220-316: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add 'canvas' to AllProviders for autocomplete consistency.

No exhaustive AllProviders handling exists, and (string & {}) keeps the type open. The omission does not affect assignability or exhaustive switches.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/corsair/core/constants.ts` around lines 220 - 316, Update the
AllProviders type to include the literal provider value 'canvas' alongside the
existing provider names, preserving the open (string & {}) fallback and current
type behavior.
packages/canvas/index.ts (1)

578-579: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the canvasOperations import to the top of the file.

The import sits between declarations at Line 579. ES module imports hoist, so the behavior is correct. The placement still breaks the convention used by the other imports in this file and can confuse readers and tooling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/index.ts` around lines 578 - 579, Move the canvasOperations
import from its current position between declarations to the file’s top import
section, alongside the other module imports. Do not change how canvasOperations
is used.
packages/canvas/endpoints/operations.ts (2)

619-628: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the duplicate deleteAMessage operation.

deleteAMessage declares the same method and the same path as deleteConversationMessages. Two operation names for one Canvas endpoint increase the public surface without adding capability.

♻️ Proposed removal
 	deleteConversationMessages: {
 		method: 'POST',
 		path: '/api/v1/conversations/{conversation_id}/remove_messages',
 		description: 'Delete specific messages from a Canvas conversation',
 	},
-	deleteAMessage: {
-		method: 'POST',
-		path: '/api/v1/conversations/{conversation_id}/remove_messages',
-		description: 'Delete messages from a Canvas conversation',
-	},

Also remove deleteAMessage from the Conversations group in packages/canvas/endpoints/index.ts and from canvasEndpointsNested.conversations in packages/canvas/index.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/operations.ts` around lines 619 - 628, Remove the
duplicate deleteAMessage operation from the endpoint definitions, and remove its
references from the Conversations group and canvasEndpointsNested.conversations.
Retain deleteConversationMessages as the sole operation for this method and
path.

63-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document that GraphQL operations require a caller-supplied query document.

Many entries map to POST /api/graphql with the same method and path. The factory sends only input.body to that path. Therefore getAccountGraphQl, getAssignment2, createAssignmentGraphQl, and getLegacyNode are behaviorally identical passthroughs. The descriptions state that each operation retrieves or creates a specific resource. That is only true when the caller supplies the correct GraphQL query and variables in the body.

Two options improve this:

  • Add the GraphQL document to the operation metadata and merge it in the factory.
  • Update the descriptions to state that the caller must supply query and variables.

Also applies to: 223-228, 244-248, 1210-1215

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/operations.ts` around lines 63 - 68, Update the
descriptions for getAccountGraphQl, getAssignment2, createAssignmentGraphQl, and
getLegacyNode to state that callers must supply the appropriate GraphQL query
document and variables in input.body. Preserve their existing method and path
metadata; do not claim resource-specific behavior is built in unless the factory
also supplies the GraphQL document.
packages/canvas/endpoints/factory.ts (1)

12-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Type the base_url key getter instead of casting ctx.keys.

canvasAuthConfig declares account: ['base_url'] for both auth types in packages/canvas/index.ts (Lines 105-112). The generated key context should therefore expose the base_url getter. The cast to { get_base_url?: () => Promise<string | null | undefined> } hides that contract. If the generated getter name changes, the cast keeps compiling and the fallback silently returns undefined.

Use the typed KeyBuilderContext shape for Canvas here, or export a small typed helper from packages/canvas/index.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/factory.ts` around lines 12 - 28, Update
resolveCanvasBaseUrl to use the generated KeyBuilderContext type for ctx.keys,
preserving the base_url getter contract declared by canvasAuthConfig instead of
casting to an ad hoc getter shape. Reuse the existing Canvas typing from
canvas/index.ts or export a focused typed helper there, and keep the current
option/account fallback behavior unchanged.
packages/canvas/jest.config.cjs (1)

5-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the copied patterns that do not apply to this package.

collectCoverageFrom excludes jest.config.ts, but this file is jest.config.cjs, so the exclusion never applies. The **/plugins/** and **/setup/** entries in testMatch target directories that this package does not contain. The **/*.test.ts pattern already covers schema.test.ts.

♻️ Proposed cleanup
 	testMatch: [
 		'**/*.test.ts',
 		'**/tests/**/*.test.ts',
-		'**/plugins/**/*.test.ts',
-		'**/setup/**/*.test.ts',
 	],
 	collectCoverageFrom: [
 		'**/*.ts',
 		'!**/*.d.ts',
 		'!**/node_modules/**',
 		'!**/dist/**',
-		'!jest.config.ts',
+		'!tsup.config.ts',
 		'!tests/**',
 	],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/jest.config.cjs` around lines 5 - 18, Clean up the Jest
configuration by removing the redundant `**/plugins/**/*.test.ts` and
`**/setup/**/*.test.ts` entries from `testMatch`, and remove the ineffective
`!jest.config.ts` exclusion from `collectCoverageFrom` because the config is
CJS. Keep the broad `**/*.test.ts` matching and all applicable coverage
exclusions unchanged.
packages/canvas/endpoints/types.ts (1)

35-56: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Unresolved path placeholders reach the Canvas API. No layer enforces that a value exists for each {placeholder} in an operation path: the generated input schema keeps pathParams fully optional, and resolvePath substitutes silently. A call such as getSingleCourse({}) therefore sends a request whose URL still contains the literal placeholder, and Canvas answers with a confusing error instead of a local validation failure.

  • packages/canvas/endpoints/types.ts#L35-L56: extract the placeholder names from operation.path and require each one as a non-empty string in the generated input schema.
  • packages/canvas/client.ts#L37-L47: replace all placeholders with a global regex and throw when a value is missing, so an unresolved placeholder cannot reach the request URL.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/types.ts` around lines 35 - 56, The generated
schema in createRequestInputSchema must extract every placeholder from
operation.path and require each corresponding pathParams value to be a non-empty
string, while keeping unrelated parameters optional. In
packages/canvas/endpoints/types.ts lines 35-56, add this per-operation
validation. In packages/canvas/client.ts lines 37-47, update resolvePath to
replace all occurrences using a global placeholder match and throw when any
required value is missing, preventing unresolved placeholders from reaching the
request URL.
packages/canvas/tsconfig.json (1)

17-19: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Exclude non-library files from the declaration project. include: ["./**/*"] includes schema.test.ts and tsup.config.ts; exclude these files to prevent declaration output for them. Keep references: []; workspace package resolution handles the corsair imports.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/tsconfig.json` around lines 17 - 19, Update the declaration
project configuration in packages/canvas/tsconfig.json to exclude schema.test.ts
and tsup.config.ts alongside dist and node_modules, while preserving the
existing include pattern and references: [] setting.
packages/canvas/endpoints/index.ts (1)

4-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add an exhaustiveness check for endpoint groups.

defineGroup permits partial registration. Add a type-level or test-level assertion that every CanvasOperationName appears in exactly one endpoint group.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/index.ts` around lines 4 - 14, Add an
exhaustiveness assertion alongside defineGroup and the endpoint-group
declarations so every CanvasOperationName is registered exactly once: reject
missing names and duplicate registrations at the type or test level. Keep
defineGroup’s generated endpoint mapping behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/canvas/client.ts`:
- Around line 12-22: Update normalizeCanvasBaseUrl to parse the trimmed URL with
new URL(), require the protocol to be exactly https:, and reject malformed or
non-HTTPS values before returning the normalized base URL. Preserve
trailing-slash removal and the existing required-value validation, using the
parsed URL result to ensure the base URL includes a valid host.
- Around line 65-86: Update the request preparation in the Canvas client around
the config and requestOptions objects to transform array-valued query parameters
into Canvas bracketed keys such as include[] before passing them to the shared
executor. Preserve the existing bearer-token configuration and ensure non-array
query parameters remain unchanged.

In `@packages/canvas/endpoints/factory.ts`:
- Around line 54-58: Update the completion logging around logEventFromContext in
the endpoint handler to avoid passing the full input object, which may contain
personal or access-token data. Construct and pass only non-sensitive metadata,
or redact input.body, pathParams, and query fields known to contain sensitive
values, while preserving the parsed response and completed-event behavior.

In `@packages/canvas/endpoints/types.ts`:
- Around line 65-75: Widen canvasResponseSchema in CanvasEndpointOutputSchemas
to accept successful responses with undefined, empty-string, and other string
bodies in addition to JSON objects and arrays. Preserve the existing object and
array validation so factory.ts parsing continues to validate structured
responses without turning 204 DELETE results or getRubricsUploadTemplate into
errors.

In `@packages/canvas/error-handlers.ts`:
- Around line 5-18: Restrict the fallback matching in RATE_LIMIT_ERROR.match so
“429” is recognized only when the error message clearly indicates rate limiting,
while preserving the existing ApiError status check and rate_limited matching.
Remove the broad substring behavior that treats unrelated identifiers containing
429 as retryable.

In `@packages/canvas/index.ts`:
- Around line 630-644: Update the OAuth configuration created by canvas() so
authUrl and tokenUrl use each tenant’s account base_url, matching
resolveCanvasBaseUrl in the endpoint factory, instead of resolving
options.baseUrl only once. If OAuth URLs cannot be resolved per tenant by the
framework, require options.baseUrl for oauth_2 and reject configuration without
it rather than falling back to the public Canvas host.
- Around line 581-601: Update CanvasOperation in operations.ts to support an
optional riskLevel, then modify buildEndpointMeta to prefer an operation’s
explicit riskLevel over HTTP-method inference. Mark deleteDiscussionEntry,
deleteDiscussionTopicGraphQl, deleteSubmissionDraft, and deleteOutcomeLinks as
destructive so PluginPermissionsConfig enforces the correct permission.

In `@packages/canvas/webhooks/types.ts`:
- Around line 91-99: Update verifyCanvasWebhookSignature to normalize
request.headers['x-canvas-signature'] by selecting the first element when it is
an array, while preserving the existing string and missing-header behavior. Use
the normalized string for subsequent signature verification instead of directly
casting the header value.

---

Nitpick comments:
In `@packages/canvas/endpoints/factory.ts`:
- Around line 12-28: Update resolveCanvasBaseUrl to use the generated
KeyBuilderContext type for ctx.keys, preserving the base_url getter contract
declared by canvasAuthConfig instead of casting to an ad hoc getter shape. Reuse
the existing Canvas typing from canvas/index.ts or export a focused typed helper
there, and keep the current option/account fallback behavior unchanged.

In `@packages/canvas/endpoints/index.ts`:
- Around line 4-14: Add an exhaustiveness assertion alongside defineGroup and
the endpoint-group declarations so every CanvasOperationName is registered
exactly once: reject missing names and duplicate registrations at the type or
test level. Keep defineGroup’s generated endpoint mapping behavior unchanged.

In `@packages/canvas/endpoints/operations.ts`:
- Around line 619-628: Remove the duplicate deleteAMessage operation from the
endpoint definitions, and remove its references from the Conversations group and
canvasEndpointsNested.conversations. Retain deleteConversationMessages as the
sole operation for this method and path.
- Around line 63-68: Update the descriptions for getAccountGraphQl,
getAssignment2, createAssignmentGraphQl, and getLegacyNode to state that callers
must supply the appropriate GraphQL query document and variables in input.body.
Preserve their existing method and path metadata; do not claim resource-specific
behavior is built in unless the factory also supplies the GraphQL document.

In `@packages/canvas/endpoints/types.ts`:
- Around line 35-56: The generated schema in createRequestInputSchema must
extract every placeholder from operation.path and require each corresponding
pathParams value to be a non-empty string, while keeping unrelated parameters
optional. In packages/canvas/endpoints/types.ts lines 35-56, add this
per-operation validation. In packages/canvas/client.ts lines 37-47, update
resolvePath to replace all occurrences using a global placeholder match and
throw when any required value is missing, preventing unresolved placeholders
from reaching the request URL.

In `@packages/canvas/index.ts`:
- Around line 578-579: Move the canvasOperations import from its current
position between declarations to the file’s top import section, alongside the
other module imports. Do not change how canvasOperations is used.

In `@packages/canvas/jest.config.cjs`:
- Around line 5-18: Clean up the Jest configuration by removing the redundant
`**/plugins/**/*.test.ts` and `**/setup/**/*.test.ts` entries from `testMatch`,
and remove the ineffective `!jest.config.ts` exclusion from
`collectCoverageFrom` because the config is CJS. Keep the broad `**/*.test.ts`
matching and all applicable coverage exclusions unchanged.

In `@packages/canvas/tsconfig.json`:
- Around line 17-19: Update the declaration project configuration in
packages/canvas/tsconfig.json to exclude schema.test.ts and tsup.config.ts
alongside dist and node_modules, while preserving the existing include pattern
and references: [] setting.

In `@packages/corsair/core/constants.ts`:
- Around line 220-316: Update the AllProviders type to include the literal
provider value 'canvas' alongside the existing provider names, preserving the
open (string & {}) fallback and current type behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a6d72a4b-7ce9-4b84-ad90-8ffbe5279db5

📥 Commits

Reviewing files that changed from the base of the PR and between 839b807 and 092957c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • packages/canvas/client.ts
  • packages/canvas/endpoints/factory.ts
  • packages/canvas/endpoints/index.ts
  • packages/canvas/endpoints/operations.ts
  • packages/canvas/endpoints/types.ts
  • packages/canvas/error-handlers.ts
  • packages/canvas/index.ts
  • packages/canvas/jest.config.cjs
  • packages/canvas/package.json
  • packages/canvas/schema.test.ts
  • packages/canvas/schema/index.ts
  • packages/canvas/tsconfig.json
  • packages/canvas/tsup.config.ts
  • packages/canvas/webhooks/index.ts
  • packages/canvas/webhooks/oauth-tenant-link.ts
  • packages/canvas/webhooks/tenant-matcher.ts
  • packages/canvas/webhooks/triggers.ts
  • packages/canvas/webhooks/types.ts
  • packages/corsair/core/constants.ts

Comment thread packages/canvas/client.ts
Comment thread packages/canvas/client.ts
Comment thread packages/canvas/endpoints/factory.ts
Comment thread packages/canvas/endpoints/types.ts Outdated
Comment thread packages/canvas/error-handlers.ts
Comment thread packages/canvas/index.ts
Comment thread packages/canvas/index.ts Outdated
Comment thread packages/canvas/webhooks/types.ts
@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator Author

@greptile review

Comment thread packages/canvas/endpoints/types.ts Outdated
Comment thread packages/canvas/endpoints/types.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/canvas/endpoints/operations.ts (2)

207-210: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use user_id in the last-attended route.

Canvas defines this endpoint as /api/v1/courses/{course_id}/users/{user_id}/last_attended, not an enrollment-scoped route.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/operations.ts` around lines 207 - 210, Update the
addLastAttendedDate operation’s path to use the Canvas user-scoped route with
the {user_id} placeholder instead of the enrollment-scoped {enrollment_id}
route, while preserving the existing method and operation metadata.

492-495: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Mark both no-body POST operations as bodyless.

duplicateGroupDiscussionTopic needs no body. assignUnassignedMembersToGroupCategory only has optional sync query input. Without bodyless: true, valid path-only calls fail local validation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/operations.ts` around lines 492 - 495, Mark both
duplicateGroupDiscussionTopic and assignUnassignedMembersToGroupCategory
operation definitions as bodyless: true, while preserving the existing method,
paths, and optional sync query input.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/canvas/webhooks/oauth-tenant-link.ts`:
- Around line 59-64: Replace the accounts[0] fallback in the OAuth tenant-link
resolution with an explicit account identifier from the OAuth contract; when no
identifier exists or multiple accounts remain ambiguous, return null instead of
selecting an arbitrary account. Update the surrounding account-resolution flow
and add coverage for reordered multi-account responses and paginated results.

---

Outside diff comments:
In `@packages/canvas/endpoints/operations.ts`:
- Around line 207-210: Update the addLastAttendedDate operation’s path to use
the Canvas user-scoped route with the {user_id} placeholder instead of the
enrollment-scoped {enrollment_id} route, while preserving the existing method
and operation metadata.
- Around line 492-495: Mark both duplicateGroupDiscussionTopic and
assignUnassignedMembersToGroupCategory operation definitions as bodyless: true,
while preserving the existing method, paths, and optional sync query input.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5be6ea9b-b88e-4427-89c4-2c986f7af8a6

📥 Commits

Reviewing files that changed from the base of the PR and between 092957c and 92e07ec.

📒 Files selected for processing (6)
  • packages/canvas/api.test.ts
  • packages/canvas/client.ts
  • packages/canvas/endpoints/operations.ts
  • packages/canvas/endpoints/types.ts
  • packages/canvas/schema.test.ts
  • packages/canvas/webhooks/oauth-tenant-link.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/canvas/client.ts
  • packages/canvas/schema.test.ts

Comment thread packages/canvas/webhooks/oauth-tenant-link.ts Outdated
@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator Author

@greptile review

Comment thread packages/canvas/webhooks/tenant-matcher.ts Outdated
@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator Author

@greptile review

@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator Author

@greptile review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (5)
packages/canvas/endpoints/routes.ts (2)

53-59: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Use a Map for route lookup.

canvasRoutes holds over 200 entries. getCanvasRoute performs a linear scan on every call. Build a Map<CanvasOperationName, CanvasRoute> once at module load and read from it.

♻️ Proposed refactor
+const canvasRouteByKey = new Map<CanvasOperationName, CanvasRoute>(
+	canvasRoutes.map((entry) => [entry.key, entry]),
+);
+
 export function getCanvasRoute(key: CanvasOperationName): CanvasRoute {
-	const route = canvasRoutes.find((entry) => entry.key === key);
+	const route = canvasRouteByKey.get(key);
 	if (!route) {
 		throw new Error(`[canvas] Unknown operation: ${key}`);
 	}
 	return route;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/routes.ts` around lines 53 - 59, Replace the linear
canvasRoutes.find lookup in getCanvasRoute with a module-level
Map<CanvasOperationName, CanvasRoute> initialized once from canvasRoutes.
Retrieve routes by key from the Map, preserve the existing unknown-operation
error and return behavior, and avoid rebuilding the Map per call.

24-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

pathParamsOf duplicates pathParamNames in packages/canvas/endpoints/types.ts.

Both functions extract {param} placeholders with the same regular expression. Export one helper and import it in the other module. This keeps the path-parameter contract in a single place.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/routes.ts` around lines 24 - 26, Remove the
duplicate placeholder extraction from pathParamsOf and reuse the exported
pathParamNames helper from the endpoints types module instead. Update the
relevant import/export declarations so both call sites share the single
implementation and preserve the existing readonly string-array behavior.
packages/canvas/endpoints/response-schemas.ts (2)

449-468: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive expectsListResponse from the schema instead of repeating the branches.

expectsListResponse duplicates every branch of createResponseSchema. If one function changes, the two can disagree, and packages/canvas/api.test.ts builds mock responses from expectsListResponse. A test would then pass while the runtime schema rejects the real response.

Compute the answer from the schema that createResponseSchema returns.

♻️ Proposed refactor
 export function expectsListResponse(
 	name: CanvasOperationName,
 	operation: CanvasOperation = canvasOperations[name],
 ): boolean {
-	if (operation.path === '/api/graphql') return false;
-	if (operation.method === 'DELETE') return false;
-	if (operation.path.includes('/upload')) return false;
-	const resource = resourceSchemaFor(name, operation);
-	if (
-		resource === CanvasPermissionsSchema ||
-		resource === CanvasUnreadCountSchema ||
-		resource === CanvasQuotaSchema ||
-		resource === CanvasSubmissionSummarySchema ||
-		resource === CanvasJsonObjectSchema ||
-		resource === CanvasJsonArraySchema
-	) {
-		return resource === CanvasJsonArraySchema;
-	}
-	return isListOperation(name, operation);
+	return createResponseSchema(name, operation) instanceof z.ZodArray;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/response-schemas.ts` around lines 449 - 468,
Refactor expectsListResponse to derive its result from the response schema
produced by createResponseSchema, rather than duplicating path, method, and
resource-specific branches. Reuse the existing schema-generation symbols and
determine whether the returned schema represents a list, keeping the boolean
consistent with runtime validation.

13-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Replace .passthrough() with z.looseObject() across this file. Zod 4 deprecates the method, and z.looseObject() preserves unknown keys.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/response-schemas.ts` around lines 13 - 17, Replace
the deprecated .passthrough() usage on CanvasEntitySchema and any other schemas
in this file with z.looseObject(), preserving each schema’s existing fields and
unknown-key behavior.
packages/canvas/endpoints/operations.ts (1)

68-73: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider marking read-only GraphQL operations as read.

riskFor in packages/canvas/endpoints/routes.ts maps any POST to write. All GraphQL operations use POST, so query-only operations such as getAccountGraphQl, getLegacyNode, getAuditLogs, getInternalSettings, getModuleItem, and getAssignmentGroup are reported as write risk. The new riskLevel field can correct this metadata for query-only GraphQL operations.

Note that the GraphQL document is supplied by the caller in input.body, so a read label is only accurate if callers are constrained to queries. Choose the label that matches the intended guarantee.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/canvas/endpoints/operations.ts` around lines 68 - 73, Update the
GraphQL endpoint metadata for getAccountGraphQl and the other query-only
operations (getLegacyNode, getAuditLogs, getInternalSettings, getModuleItem, and
getAssignmentGroup) to use the riskLevel field with a read value only if callers
are constrained to query documents; otherwise retain write to reflect the
caller-supplied GraphQL operation. Ensure each label matches the intended
guarantee and riskFor consumes this metadata.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/canvas/endpoints/response-schemas.ts`:
- Around line 415-446: Update createResponseSchema to return operation-specific
wrapper schemas for getQuizStatistics, getOutcomeResults,
createBatchOverridesInACourse, and polling create operations returning polls,
poll_choices, poll_sessions, or poll_submissions. Define or reuse strict Zod
schemas matching each documented response shape, including the
assignment-overrides array, and select them by operation name before generic
resource/list handling; do not use a permissive fallback.

In `@packages/canvas/endpoints/types.ts`:
- Around line 62-67: Update CanvasEndpointInputs to derive body optionality from
each operation’s mutation and bodyless status, matching
createRequestInputSchema: require a non-empty body for mutations that are not
bodyless, while preserving optional body for bodyless or non-mutation
operations. Ensure the existing pathParams mapping remains unchanged.

In `@packages/canvas/webhooks/oauth-tenant-link.ts`:
- Around line 44-46: Update the singleton-row branch in the tenant-link
resolution function so it does not use the child row’s id as the tenant identity
when parent_account_id is set. Prefer a valid root_account_id from the row or
related account data, and return null when no valid root identity is available;
preserve the existing behavior for root accounts.

In `@packages/canvas/webhooks/tenant-matcher.ts`:
- Around line 5-8: The numericAccountId function in
packages/canvas/webhooks/tenant-matcher.ts:5-8 must iterate through all values
and return the first normalized string matching /^\d+$/, rather than validating
only firstString(values). In
packages/canvas/webhooks/oauth-tenant-link.ts:74-76, scan canvas_account_id,
account_id, and root_account_id for the first normalized numeric value before
checking UUID fields.

---

Nitpick comments:
In `@packages/canvas/endpoints/operations.ts`:
- Around line 68-73: Update the GraphQL endpoint metadata for getAccountGraphQl
and the other query-only operations (getLegacyNode, getAuditLogs,
getInternalSettings, getModuleItem, and getAssignmentGroup) to use the riskLevel
field with a read value only if callers are constrained to query documents;
otherwise retain write to reflect the caller-supplied GraphQL operation. Ensure
each label matches the intended guarantee and riskFor consumes this metadata.

In `@packages/canvas/endpoints/response-schemas.ts`:
- Around line 449-468: Refactor expectsListResponse to derive its result from
the response schema produced by createResponseSchema, rather than duplicating
path, method, and resource-specific branches. Reuse the existing
schema-generation symbols and determine whether the returned schema represents a
list, keeping the boolean consistent with runtime validation.
- Around line 13-17: Replace the deprecated .passthrough() usage on
CanvasEntitySchema and any other schemas in this file with z.looseObject(),
preserving each schema’s existing fields and unknown-key behavior.

In `@packages/canvas/endpoints/routes.ts`:
- Around line 53-59: Replace the linear canvasRoutes.find lookup in
getCanvasRoute with a module-level Map<CanvasOperationName, CanvasRoute>
initialized once from canvasRoutes. Retrieve routes by key from the Map,
preserve the existing unknown-operation error and return behavior, and avoid
rebuilding the Map per call.
- Around line 24-26: Remove the duplicate placeholder extraction from
pathParamsOf and reuse the exported pathParamNames helper from the endpoints
types module instead. Update the relevant import/export declarations so both
call sites share the single implementation and preserve the existing readonly
string-array behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ef056dd4-115d-4e3a-adf9-d4531366220e

📥 Commits

Reviewing files that changed from the base of the PR and between 92e07ec and 382007f.

📒 Files selected for processing (17)
  • packages/canvas/api.test.ts
  • packages/canvas/client.ts
  • packages/canvas/endpoints/factory.ts
  • packages/canvas/endpoints/index.ts
  • packages/canvas/endpoints/operations.ts
  • packages/canvas/endpoints/response-schemas.ts
  • packages/canvas/endpoints/routes.ts
  • packages/canvas/endpoints/types.ts
  • packages/canvas/error-handlers.ts
  • packages/canvas/index.ts
  • packages/canvas/jest.config.cjs
  • packages/canvas/schema.test.ts
  • packages/canvas/tsconfig.json
  • packages/canvas/webhooks/oauth-tenant-link.ts
  • packages/canvas/webhooks/tenant-matcher.ts
  • packages/canvas/webhooks/types.ts
  • packages/corsair/core/constants.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/canvas/tsconfig.json
  • packages/canvas/endpoints/factory.ts
  • packages/canvas/error-handlers.ts
  • packages/canvas/webhooks/types.ts
  • packages/canvas/client.ts
  • packages/canvas/schema.test.ts

Comment thread packages/canvas/endpoints/response-schemas.ts
Comment thread packages/canvas/endpoints/types.ts
Comment thread packages/canvas/webhooks/oauth-tenant-link.ts
Comment thread packages/canvas/webhooks/tenant-matcher.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:round-1 Review bot posted consolidated findings bot:round-2 Review bot pushed an automated fix core Changes in packages/corsair plugin Changes inside a plugin package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integration request: Canvas LMS

2 participants