-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add Nango integrations setup for data syncing #144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Initialize nango-integrations folder with CLI (v0.69.14) - Add example GitHub sync for fetching issues across repos - Add sync types for Nango record handling - Exclude nango-integrations from eslint (CLI-generated code)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughIntroduces a new Changes
Sequence Diagram(s)sequenceDiagram
participant Nango as Nango Sync
participant GitHub as GitHub API
participant DB as Nango Database
rect rgb(200, 220, 240)
note over Nango,DB: Fetch Issues Workflow
end
Nango->>GitHub: GET /user/repos (paginated, limit=100)
GitHub-->>Nango: User repositories
loop For each repository
Nango->>GitHub: GET /repos/{owner}/{repo}/issues (paginated, limit=100)
GitHub-->>Nango: Issues list
rect rgb(240, 220, 200)
note over Nango: Filter pull requests,<br/>map to GithubIssue schema
end
Nango->>DB: batchSave(GithubIssue records)
DB-->>Nango: Batch saved
rect rgb(220, 240, 220)
note over Nango: Log batch progress
end
end
Nango->>DB: Delete previous GithubIssue records
DB-->>Nango: Records deleted
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (7)
src/server/api/services/sync/types.ts (1)
5-41: Consider adding Zod schemas for runtime validation.Since this code will process external data from Nango syncs and Zod is already a project dependency, consider adding Zod schemas alongside these TypeScript types to provide runtime validation and type safety when parsing API responses.
Example approach:
import { z } from "zod"; export const NangoRecordMetadataSchema = z.object({ deleted_at: z.string().nullable(), last_action: z.enum(["ADDED", "UPDATED", "DELETED"]), first_seen_at: z.string(), last_modified_at: z.string(), cursor: z.string(), }); export type NangoRecordMetadata = z.infer<typeof NangoRecordMetadataSchema>; export const NangoRecordSchema = <T extends z.ZodTypeAny>(dataSchema: T) => z.object({ id: z.string(), _nango_metadata: NangoRecordMetadataSchema, data: dataSchema, }); export type NangoRecord<T = Record<string, unknown>> = { id: string; _nango_metadata: NangoRecordMetadata; data: T; }; // Similar patterns for other interfaces...This would enable safe parsing of external API responses with
.parse()or.safeParse().nango-integrations/github/actions/createIssue.ts (2)
4-16: Input schema fields are largely unused by the action.The
issueSchemarequires 11 fields (id, owner, repo, etc.), but theexecfunction only usesinput.title. The action also ignoresinput.ownerandinput.repo, hardcoding the target repository toNangoHQ/interactive-demo.If this is intentional for demo purposes, consider simplifying the input schema to only require the fields actually used, or add a comment clarifying the intent.
-const issueSchema = z.object({ - id: z.string(), - owner: z.string(), - repo: z.string(), - issue_number: z.number(), - title: z.string(), - state: z.string(), - author: z.string(), - author_id: z.number(), - body: z.string(), - date_created: z.string(), - date_last_modified: z.string(), -}); +// Minimal schema for demo action - only title is used +const issueSchema = z.object({ + title: z.string(), +});
26-35: Missing error handling for the GitHub API proxy call.The
execfunction does not handle potential errors fromnango.proxy(). If the API call fails (e.g., rate limiting, auth issues, network errors), the error will propagate unhandled.Consider adding error handling or at minimum logging failures for observability.
exec: async (nango, input) => { - await nango.proxy({ - endpoint: "/repos/NangoHQ/interactive-demo/issues", - data: { - title: `[demo] ${input.title}`, - body: `This issue was created automatically using Nango Action.`, - labels: ["automatic"], - }, - }); + try { + await nango.proxy({ + endpoint: "/repos/NangoHQ/interactive-demo/issues", + data: { + title: `[demo] ${input.title}`, + body: `This issue was created automatically using Nango Action.`, + labels: ["automatic"], + }, + }); + } catch (error) { + await nango.log(`Failed to create issue: ${error}`); + throw error; + } },nango-integrations/github/syncs/fetchIssues.ts (2)
84-98: Avoidany[]return type; define a repository interface for type safety.Using
any[]loses type information and can mask bugs. Consider defining a minimal interface for the repository shape you need.+interface GithubRepository { + name: string; + owner: { login: string }; +} -async function getAllRepositories(nango: NangoSyncLocal): Promise<any[]> { - const records: any[] = []; +async function getAllRepositories(nango: NangoSyncLocal): Promise<GithubRepository[]> { + const records: GithubRepository[] = [];
75-78: Webhook handler is a no-op placeholder.The
onWebhookhandler only logs the payload without processing it. If webhook handling isn't needed yet, consider adding a TODO comment or removing it to avoid confusion.nango-integrations/build/github_on-events_pre-connection-deletion.cjs (1)
27-35: Placeholder implementation for connection deletion.The event handler currently only logs a message. For production use, consider implementing cleanup logic such as deleting synced records or notifying downstream systems.
nango-integrations/build/github_syncs_fetchIssues.cjs (1)
106-118: Helper function is correct but could use better typing.The repository fetching logic is sound. Consider adding proper TypeScript types for the repository objects in the source file instead of
any[]for better type safety.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
nango-integrations/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (12)
eslint.config.js(1 hunks)nango-integrations/.gitignore(1 hunks)nango-integrations/build/github_actions_createIssue.cjs(1 hunks)nango-integrations/build/github_on-events_pre-connection-deletion.cjs(1 hunks)nango-integrations/build/github_syncs_fetchIssues.cjs(1 hunks)nango-integrations/github/actions/createIssue.ts(1 hunks)nango-integrations/github/on-events/pre-connection-deletion.ts(1 hunks)nango-integrations/github/syncs/fetchIssues.ts(1 hunks)nango-integrations/index.ts(1 hunks)nango-integrations/package.json(1 hunks)nango-integrations/tsconfig.json(1 hunks)src/server/api/services/sync/types.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: In TypeScript files, use@typescript-eslint/consistent-type-importsto enforce inline type imports and sort imports with @trivago/prettier-plugin-sort-imports
Use the tRPC server caller API fromsrc/trpc/server.tsdirectly in Server Components for 10x faster performance instead of client-side hooks
Files:
nango-integrations/github/on-events/pre-connection-deletion.tssrc/server/api/services/sync/types.tsnango-integrations/github/actions/createIssue.tsnango-integrations/index.tsnango-integrations/github/syncs/fetchIssues.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
Use TanStack Query (via tRPC hooks) for server state management, client-side data fetching, and automatic cache invalidation
Files:
nango-integrations/github/on-events/pre-connection-deletion.tssrc/server/api/services/sync/types.tsnango-integrations/github/actions/createIssue.tsnango-integrations/index.tsnango-integrations/github/syncs/fetchIssues.ts
src/server/api/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Add new tRPC routers in
src/server/api/routers/[name].tsand register them in theappRouterinsrc/server/api/root.ts
Files:
src/server/api/services/sync/types.ts
🧠 Learnings (1)
📚 Learning: 2025-12-02T13:36:55.215Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-02T13:36:55.215Z
Learning: Applies to **/*.{ts,tsx} : In TypeScript files, use `typescript-eslint/consistent-type-imports` to enforce inline type imports and sort imports with trivago/prettier-plugin-sort-imports
Applied to files:
eslint.config.jsnango-integrations/tsconfig.json
🧬 Code graph analysis (5)
nango-integrations/github/actions/createIssue.ts (1)
src/server/nango.ts (1)
nango(12-12)
nango-integrations/build/github_actions_createIssue.cjs (1)
src/server/nango.ts (1)
nango(12-12)
nango-integrations/build/github_on-events_pre-connection-deletion.cjs (1)
src/server/nango.ts (1)
nango(12-12)
nango-integrations/build/github_syncs_fetchIssues.cjs (1)
src/server/nango.ts (1)
nango(12-12)
nango-integrations/github/syncs/fetchIssues.ts (2)
src/server/nango.ts (1)
nango(12-12)nango-integrations/build/github_syncs_fetchIssues.cjs (6)
repos(69-69)proxyConfig(71-76)proxyConfig(108-113)issues(78-78)mappedIssues(79-91)records(107-107)
🔇 Additional comments (8)
eslint.config.js (1)
11-11: LGTM! Appropriate exclusion of CLI-generated code.Adding
nango-integrations/**to the ESLint ignores aligns with the PR objective to exclude CLI-generated Nango code from linting.nango-integrations/.gitignore (1)
1-8: LGTM! Standard ignore patterns.The ignore rules appropriately cover environment files, Nango build artifacts, and Node.js dependencies.
nango-integrations/tsconfig.json (1)
1-30: LGTM! Strict TypeScript configuration managed by Nango CLI.The configuration enables comprehensive strict type checking, which will help catch errors early. As noted in line 3, this file is managed by Nango and should not be manually edited.
nango-integrations/package.json (1)
14-15: Bothnango@0.69.14andzod@4.0.5are valid, published versions with no known security vulnerabilities. Zod's recent ReDoS vulnerability affected versions 3.21.0–3.22.3 only, and Nango has no reported security advisories for this release. These versions are safe to use.nango-integrations/index.ts (1)
1-3: LGTM!The side-effect imports correctly aggregate GitHub integration modules for runtime registration. Using
.jsextensions is appropriate for ESM output.nango-integrations/build/github_actions_createIssue.cjs (1)
1-74: Verify if committing build artifacts is intentional.This appears to be a CLI-generated build artifact. Typically, build outputs are excluded from version control (via
.gitignore) and regenerated during CI/CD. However, some deployment workflows require pre-built artifacts.Please confirm this is intentional for Nango's deployment model. If the build step can run during deployment, consider adding
nango-integrations/build/to.gitignore.nango-integrations/github/on-events/pre-connection-deletion.ts (1)
3-9: Placeholder implementation is functional but minimal.The handler currently only logs "Executed". For production use, consider implementing actual cleanup logic (e.g., revoking tokens, cleaning up external resources) before connection deletion.
This is fine as scaffolding for the initial setup.
nango-integrations/build/github_syncs_fetchIssues.cjs (1)
51-104: Sync logic is well-structured.The sync implementation correctly:
- Filters out pull requests (Line 78)
- Batches saves for efficiency (Line 93)
- Cleans up stale records from previous runs (Line 98)
The hourly frequency with full sync may require attention to GitHub API rate limits (5,000 requests/hour for authenticated requests). Since the Nango SDK (@nangohq/node@0.69.10) handles pagination internally, verify that rate limit backoff and retry logic are enabled in your Nango configuration to avoid hitting 429 errors during multi-repository syncs.
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
|
|
||
| // nango-integrations/github/on-events/pre-connection-deletion.ts | ||
| var pre_connection_deletion_exports = {}; | ||
| __export(pre_connection_deletion_exports, { | ||
| default: () => pre_connection_deletion_default, | ||
| onEvent: () => onEvent | ||
| }); | ||
| module.exports = __toCommonJS(pre_connection_deletion_exports); | ||
| var onEvent = { | ||
| type: "onEvent", | ||
| event: "pre-connection-deletion", | ||
| // 'post-connection-creation' | 'validate-connection' | ||
| description: "This script is executed before a connection is deleted", | ||
| exec: async (nango) => { | ||
| await nango.log("Executed"); | ||
| } | ||
| }; | ||
| var pre_connection_deletion_default = onEvent; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| onEvent | ||
| }); | ||
| //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsibmFuZ28taW50ZWdyYXRpb25zL2dpdGh1Yi9vbi1ldmVudHMvcHJlLWNvbm5lY3Rpb24tZGVsZXRpb24udHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB7IGNyZWF0ZU9uRXZlbnQgfSBmcm9tICduYW5nbyc7XG5leHBvcnQgY29uc3Qgb25FdmVudCA9IHtcbiAgdHlwZTogXCJvbkV2ZW50XCIsXG4gIGV2ZW50OiAncHJlLWNvbm5lY3Rpb24tZGVsZXRpb24nLFxuICAvLyAncG9zdC1jb25uZWN0aW9uLWNyZWF0aW9uJyB8ICd2YWxpZGF0ZS1jb25uZWN0aW9uJ1xuICBkZXNjcmlwdGlvbjogJ1RoaXMgc2NyaXB0IGlzIGV4ZWN1dGVkIGJlZm9yZSBhIGNvbm5lY3Rpb24gaXMgZGVsZXRlZCcsXG4gIGV4ZWM6IGFzeW5jIG5hbmdvID0+IHtcbiAgICBhd2FpdCBuYW5nby5sb2coJ0V4ZWN1dGVkJyk7XG4gIH1cbn07XG5leHBvcnQgZGVmYXVsdCBvbkV2ZW50OyJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ08sSUFBTSxVQUFVO0FBQUEsRUFDckIsTUFBTTtBQUFBLEVBQ04sT0FBTztBQUFBO0FBQUEsRUFFUCxhQUFhO0FBQUEsRUFDYixNQUFNLE9BQU0sVUFBUztBQUNuQixVQUFNLE1BQU0sSUFBSSxVQUFVO0FBQUEsRUFDNUI7QUFDRjtBQUNBLElBQU8sa0NBQVE7IiwKICAibmFtZXMiOiBbXQp9Cg== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Nango integration framework build artifacts deployment requirements
💡 Result:
Summary of key build-artifact / deployment requirements for Nango integrations:
- Nango CLI + project layout: install the nango CLI (npm) and keep integrations in a version-controlled nango-integrations/ folder (nango init creates structure). [1][2]
- Runtime tooling: Node.js/npm for building functions, and Docker (or Docker Compose) when using local/self‑hosted Nango or sample apps. [2][3][4]
- Environment variables / secrets: provide NANGO_SECRET_KEY_DEV and NANGO_SECRET_KEY_PROD for CLI auth, set NANGO_HOSTPORT to your instance URL for self‑hosted, and any .env in ./nango-integrations with these values. CI deploys must supply those secrets. [1][2]
- Encryption key (self-hosted): a persistent NANGO_ENCRYPTION_KEY is required for self‑hosted deployments (cannot be re‑generated later). [5]
- Deployment commands / CI: use nango deploy (can target envs like dev/prod); CI should install nango CLI, load env secrets, and may pass flags like --auto-confirm or --allow-destructive when needed. [1][2][5]
- Ports / infra (self-hosted): default OSS ports (server 3003, Postgres 5432) when using docker-compose; adapt as needed in .env/docker-compose. [4]
- Best practices: keep integrations in source control, include .env templates, and automate deploys in CI with appropriate secret management. [2][3]
Sources: Nango CLI & env docs; Functions/setup and deploy guides; Sample app deployment; Self-hosting (docker compose); note on NANGO_ENCRYPTION_KEY. [1][2][3][4][5]
🏁 Script executed:
# Check if there are other similar compiled artifacts in the build directory
fd -e cjs nango-integrations/build/ | head -20Repository: drifter089/orgOS
Length of output: 465
🏁 Script executed:
# Look for build configuration and CI/CD setup
fd -e json -e yaml -e yml -e toml . | grep -E "(package\.json|tsconfig|esbuild|webpack|build|ci)" | head -30Repository: drifter089/orgOS
Length of output: 151
🏁 Script executed:
# Search for documentation about nango-integrations structure
find . -name "README*" -o -name "*.md" | xargs grep -l "nango-integrations\|build artifact" 2>/dev/null | head -10Repository: drifter089/orgOS
Length of output: 42
🏁 Script executed:
# Explore nango-integrations directory structure
ls -la nango-integrations/ 2>/dev/null | head -20Repository: drifter089/orgOS
Length of output: 620
🏁 Script executed:
# Check the actual build directory
ls -la nango-integrations/build/ 2>/dev/null | head -30Repository: drifter089/orgOS
Length of output: 423
🏁 Script executed:
# Check package.json build scripts
cat nango-integrations/package.json | head -50Repository: drifter089/orgOS
Length of output: 342
🏁 Script executed:
# Check .gitignore for build patterns
cat .gitignore 2>/dev/nullRepository: drifter089/orgOS
Length of output: 874
🏁 Script executed:
# Look for nango CLI config (nango.yaml or similar)
find nango-integrations -name "nango.yaml" -o -name "nango.yml" -o -name ".nangorc*" 2>/dev/nullRepository: drifter089/orgOS
Length of output: 42
🏁 Script executed:
# Verify the nango-integrations/.gitignore specifically
cat nango-integrations/.gitignoreRepository: drifter089/orgOS
Length of output: 147
🏁 Script executed:
# Check if build files are tracked by git
cd nango-integrations && git ls-files build/ 2>/dev/null || echo "Not in git or error"Repository: drifter089/orgOS
Length of output: 182
🏁 Script executed:
# Look at the source TypeScript files
find nango-integrations/github -name "*.ts" -type f | head -10Repository: drifter089/orgOS
Length of output: 218
🏁 Script executed:
# Check git history to see if build files were recently added
git log --oneline nango-integrations/build/ 2>/dev/null | head -5Repository: drifter089/orgOS
Length of output: 127
🏁 Script executed:
# Verify the compilation flow - does nango compile generate these files?
cat nango-integrations/tsconfig.jsonRepository: drifter089/orgOS
Length of output: 986
Remove committed build artifacts from the nango-integrations/build directory.
The compiled .cjs files in nango-integrations/build/ are build artifacts generated by nango compile from TypeScript sources. Nango's own tsconfig.json explicitly excludes the build directory, indicating these files should not be in version control. They are regenerated during deployment via nango deploy. Remove all .cjs files from nango-integrations/build/ and add build/ to nango-integrations/.gitignore. Keep only the source .ts files in nango-integrations/github/.
🤖 Prompt for AI Agents
In nango-integrations/build/github_on-events_pre-connection-deletion.cjs (lines
1-41): this is a compiled build artifact that should not be committed; remove
this .cjs file (and any other files under nango-integrations/build/), add build/
to nango-integrations/.gitignore, ensure only the original TypeScript source
files remain under nango-integrations/github/, and update the commit so the
build output is no longer tracked.
| var issueSchema = z.object({ | ||
| id: z.string(), | ||
| owner: z.string(), | ||
| repo: z.string(), | ||
| issue_number: z.number(), | ||
| title: z.string(), | ||
| state: z.string(), | ||
| author: z.string(), | ||
| author_id: z.number(), | ||
| body: z.string(), | ||
| date_created: z.string(), | ||
| date_last_modified: z.string() | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Find the source TypeScript file
find . -name "fetchIssues.ts" -type fRepository: drifter089/orgOS
Length of output: 108
🌐 Web query:
GitHub REST API issue object body field null
💡 Result:
Common causes
- The issue really has no body (empty) — then the JSON "body" is null.
- You're requesting the default/other media type that doesn't return the raw "body" field; GitHub exposes different representations (body, body_text, body_html) only when the appropriate Accept media type is used.
What to do - Verify the issue actually has text in the web UI.
- Request the body explicitly by sending an Accept header such as:
- application/vnd.github.raw+json (returns body)
- application/vnd.github.text+json (returns body_text)
- application/vnd.github.html+json (returns body_html)
- application/vnd.github.full+json (returns body, body_text, body_html)
References
- GitHub REST issues docs (media types & body fields). [1] [2]
Sources
[1] REST API endpoints for issues — GitHub Docs. [turn0search0]
[2] REST API endpoints for issues (Enterprise) — GitHub Docs. [turn0search3]
🏁 Script executed:
cat -n ./nango-integrations/github/syncs/fetchIssues.tsRepository: drifter089/orgOS
Length of output: 3295
Fix nullable body field in schema.
The body field is defined as z.string(), but GitHub's API returns null for issues without a description. This causes validation failures when syncing such issues. Update the schema in the source TypeScript file:
- body: z.string(),
+ body: z.string().nullable(),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var issueSchema = z.object({ | |
| id: z.string(), | |
| owner: z.string(), | |
| repo: z.string(), | |
| issue_number: z.number(), | |
| title: z.string(), | |
| state: z.string(), | |
| author: z.string(), | |
| author_id: z.number(), | |
| body: z.string(), | |
| date_created: z.string(), | |
| date_last_modified: z.string() | |
| }); | |
| var issueSchema = z.object({ | |
| id: z.string(), | |
| owner: z.string(), | |
| repo: z.string(), | |
| issue_number: z.number(), | |
| title: z.string(), | |
| state: z.string(), | |
| author: z.string(), | |
| author_id: z.number(), | |
| body: z.string().nullable(), | |
| date_created: z.string(), | |
| date_last_modified: z.string() | |
| }); |
🤖 Prompt for AI Agents
In nango-integrations/build/github_syncs_fetchIssues.cjs around lines 38 to 50,
the issueSchema defines body as z.string() which fails when GitHub returns null;
replace the body schema with a nullable string (e.g., change body: z.string() to
body: z.string().nullable()) so validation accepts both string and null; update
the source TypeScript schema (not just the built CJS) and rebuild to propagate
the change.
| exec: async (nango) => { | ||
| const repos = await getAllRepositories(nango); | ||
| for (const repo of repos) { | ||
| const proxyConfig = { | ||
| endpoint: `/repos/${repo.owner.login}/${repo.name}/issues`, | ||
| paginate: { | ||
| limit: LIMIT | ||
| } | ||
| }; | ||
| for await (const issueBatch of nango.paginate(proxyConfig)) { | ||
| const issues = issueBatch.filter((issue) => !("pull_request" in issue)); | ||
| const mappedIssues = issues.map((issue) => ({ | ||
| id: issue.id, | ||
| owner: repo.owner.login, | ||
| repo: repo.name, | ||
| issue_number: issue.number, | ||
| title: issue.title, | ||
| state: issue.state, | ||
| author: issue.user.login, | ||
| author_id: issue.user.id, | ||
| body: issue.body, | ||
| date_created: issue.created_at, | ||
| date_last_modified: issue.updated_at | ||
| })); | ||
| if (mappedIssues.length > 0) { | ||
| await nango.batchSave(mappedIssues, "GithubIssue"); | ||
| await nango.log(`Sent ${mappedIssues.length} issues from ${repo.owner.login}/${repo.name}`); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for individual repository failures.
The sync iterates through all repositories without try-catch blocks. If fetching issues from one repository fails (e.g., due to permissions or API errors), the entire sync will fail and subsequent repositories won't be processed.
Consider wrapping the per-repository logic in try-catch in the source TypeScript file:
for (const repo of repos) {
try {
const proxyConfig = { /* ... */ };
for await (const issueBatch of nango.paginate(proxyConfig)) {
// ... existing logic
}
} catch (error) {
await nango.log(`Failed to fetch issues from ${repo.owner.login}/${repo.name}: ${error}`);
// Continue with next repository
}
}🤖 Prompt for AI Agents
In nango-integrations/build/github_syncs_fetchIssues.cjs around lines 68 to 97,
the loop over repos lacks per-repository error handling so a failure fetching
one repo's issues can abort the whole sync; wrap the logic that builds
proxyConfig and the for-await-of nango.paginate(...) processing (including
filtering, mapping, batchSave and log) in a try-catch that on catch awaits
nango.log with a message containing the repo owner/name and the caught error,
then continues to the next repo so other repositories still get processed.
| const issueSchema = z.object({ | ||
| id: z.string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type mismatch: id schema expects string but GitHub returns number.
GitHub's API returns issue.id as a number, but the schema defines id: z.string(). At line 50, you assign id: issue.id directly without conversion, which will cause Zod validation to fail if schema validation is enabled.
const issueSchema = z.object({
- id: z.string(),
+ id: z.number(),
owner: z.string(),Or convert at mapping time:
const mappedIssues: GithubIssue[] = issues.map((issue) => ({
- id: issue.id,
+ id: String(issue.id),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const issueSchema = z.object({ | |
| id: z.string(), | |
| const issueSchema = z.object({ | |
| id: z.number(), | |
| owner: z.string(), |
🤖 Prompt for AI Agents
In nango-integrations/github/syncs/fetchIssues.ts around lines 5 to 6 and the
mapping at line ~50, the Zod schema defines id: z.string() but GitHub returns
issue.id as a number; fix by making the schema and mapping consistent — either
change the schema to id: z.number() (and update any downstream code expecting a
string) or keep a string schema and coerce the value (use z.coerce.string() for
the schema or convert the id when mapping with String(issue.id)); ensure the
chosen approach is applied both in the schema and where issue.id is assigned so
Zod validation succeeds.
| const mappedIssues: GithubIssue[] = issues.map((issue) => ({ | ||
| id: issue.id, | ||
| owner: repo.owner.login, | ||
| repo: repo.name, | ||
| issue_number: issue.number, | ||
| title: issue.title, | ||
| state: issue.state, | ||
| author: issue.user.login, | ||
| author_id: issue.user.id, | ||
| body: issue.body, | ||
| date_created: issue.created_at, | ||
| date_last_modified: issue.updated_at, | ||
| })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential null reference errors in issue mapping.
Several GitHub API fields can be null:
issue.bodyis nullable (returnsnullfor issues without a body)issue.usercan benullfor deleted/ghost users, causingissue.user.loginandissue.user.idto throw
const mappedIssues: GithubIssue[] = issues.map((issue) => ({
id: issue.id,
owner: repo.owner.login,
repo: repo.name,
issue_number: issue.number,
title: issue.title,
state: issue.state,
- author: issue.user.login,
- author_id: issue.user.id,
- body: issue.body,
+ author: issue.user?.login ?? "ghost",
+ author_id: issue.user?.id ?? 0,
+ body: issue.body ?? "",
date_created: issue.created_at,
date_last_modified: issue.updated_at,
}));🤖 Prompt for AI Agents
In nango-integrations/github/syncs/fetchIssues.ts around lines 49 to 61 the
mapping assumes issue.user and issue.body are non-null which can throw for
deleted/ghost users or issues without a body; update the mapping to safely
handle nullables by using optional chaining and sensible fallbacks (e.g.,
issue.user?.login ?? null or 'ghost', issue.user?.id ?? null) and defaulting
issue.body to '' or null to match your GithubIssue type, and if needed adjust
the GithubIssue type to accept nullable author/author_id/body so the compiler
reflects these safe values.
Summary
Sets up Nango integrations infrastructure for continuous data syncing from external APIs. This replaces manual API fetching with automated syncs that keep data fresh.
Key Changes
nango-integrations/folder with Nango CLI (v0.69.14)Next Steps
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.