## Summary
- Add optional `rawBody?: string` to `LogicFunctionEvent` and forward it
from the route trigger so HMAC-based webhook signatures (GitHub's
`X-Hub-Signature-256`, Stripe, …) can be verified by user logic
functions.
- Update `github-connector`'s `getRawBodyForSignature` to prefer
`event.rawBody` (with the existing string/base64/null fallbacks kept for
older runtimes).
## Why
GitHub computes `X-Hub-Signature-256` over the **raw bytes** of the
request body. The receiver must verify against those exact bytes — key
order, whitespace and unicode escaping all matter, so the parsed JSON
body cannot be re-serialized to them.
Today the route trigger calls `extractBody(request)` which returns the
parsed object only. NestJS already preserves the raw body on
`request.rawBody` (the app is bootstrapped with `rawBody: true` in
`main.ts`), but it was never propagated into `LogicFunctionEvent`.
As a result the github-connector's webhook handler always took the "raw
body unavailable" branch and rejected every delivery (after #19961 /
962c2b3c14). With this change, signature verification can succeed
end-to-end.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
- Adds an `isSelfReview` boolean to the consolidated `PullRequestReview`
record (`true` when the reviewer is the same contributor as the PR
author).
- Filters `isSelfReview === true` rows out of the top-reviewers
leaderboard (`top-contributors`) and per-contributor review stats
(`contributor-stats`) so contributors are credited only for reviews on
**other people's** PRs.
- Both the live ingestion path (`fetch-prs`) and the recompute job
(`recompute-pull-request-reviews`) now thread `prAuthorId` to
`buildConsolidatedRow`, so re-running either is sufficient to backfill
existing rows — no extra migration needed.
## Test plan
- [x] `yarn test
src/modules/github/pull-request-review/utils/consolidate-reviews.integration-test.ts`
— 20 tests passing, including new coverage for the `isSelfReview` helper
and `buildConsolidatedRow` payload.
- [ ] After merge: re-run `fetch-prs` (or
`recompute-pull-request-reviews`) once on a target workspace to backfill
`isSelfReview` on existing `PullRequestReview` rows, then verify the
top-reviewers leaderboard no longer credits self-reviews.
Made with [Cursor](https://cursor.com)
## Summary
Logic-function bundles produced by the SDK CLI were ~1.2 MB each (source
maps ~3.1 MB) because esbuild was inlining `twenty-sdk/define` and its
transitive dependencies (zod + locales, twenty-shared, etc.). Those
`define*` factories are pure build-time metadata used only by the
manifest extractor — the Lambda runtime only ever invokes
`default.config.handler`, so the factories are dead weight at runtime.
This PR shrinks the bundles to ~9.5 KB each (~99% reduction) without
changing runtime behaviour.
## What changes
- **Stub `twenty-sdk/define` at user-app build time.** New esbuild
plugin
(`packages/twenty-sdk/src/cli/utilities/build/common/plugins/stub-twenty-sdk-define.plugin.ts`)
intercepts every import of `twenty-sdk/define` during user-app builds
and replaces it with a tiny virtual module:
- Factory functions (`defineLogicFunction`,
`definePostInstallLogicFunction`, …) become `(config) => ({ success:
true, config, errors: [] })`.
- Enums and helpers become `Proxy`-based no-ops.
- Wired into both the one-shot build (`build-application.ts`) and the
watcher (`esbuild-watcher.ts`), for logic functions and front
components.
- **New runtime barrel `twenty-sdk/logic-function`.** Re-exports only
the types logic-function authors need (`InstallPayload`, `RoutePayload`,
`CronPayload`, `DatabaseEventPayload`, `LogicFunctionConfig`,
`InputJsonSchema`, …). Compiled `.mjs` is 36 bytes. Wired into Vite,
Rollup `.d.ts` bundling, `package.json#exports`, and `typesVersions`.
- **Lint enforcement.** Added an oxlint `no-restricted-imports` rule
that forbids `twenty-shared` / `twenty-shared/*` imports from
`**/*.logic-function.ts` and `**/logic-functions/**/*.ts`, with a help
message pointing at the new barrel. Applied to the `create-twenty-app`
template and to `github-connector`, `hello-world`, `postcard`.
- **Migrated existing sources.** All logic-function files across
`community/{github-connector, apollo-enrich}`, `examples/{hello-world,
postcard}`, and `internal/{twenty-for-twenty, self-hosting, exa}` now
import types from `twenty-sdk/logic-function` instead of
`twenty-sdk/define` or `twenty-shared/*`. Renamed leftover
`InstallLogicFunctionPayload` references to `InstallPayload`.
## Why this is safe
- `define*` exports from `twenty-sdk/define` are metadata factories
whose call expressions are statically inspected by the manifest
extractor (`manifest-extract-config.ts`). They're never evaluated at
runtime — the Lambda executor only walks `default.config.handler`
(`logic-function-drivers/constants/executor/index.mjs`).
- The stub keeps the same call shape (`{ success, config, errors }`), so
any logic-function module that re-exports
`defineX(config).config.handler` still resolves to the user's handler at
runtime.
- Front-component bundles are unaffected by the stub because the
pre-existing JSX transform plugin
(`jsx-transform-to-remote-dom-worker-format-plugin.ts`) unwraps
`defineFrontComponent(...)` earlier in the pipeline. That's intentional
— front-component bloat is React/Preact, not in scope here.
## Measurements (github-connector)
| Asset | Before | After |
|---|---|---|
| `*.logic-function.mjs` | ~1.2 MB | ~9.5 KB |
| `*.logic-function.mjs.map` | ~3.1 MB | ~22 KB |
## Summary
Adds a new community app at
`packages/twenty-apps/community/github-connector` that demonstrates a
complete, production-style GitHub integration built on the Twenty SDK.
It is extracted (and decoupled) from the internal `twenty-eng` workspace
so external developers can use it as a reference for their own
connectors.
What it ships:
- **Six synced objects**: `pullRequest`, `pullRequestReview`,
`pullRequestReviewEvent`, `issue`, `projectItem`, `engineer`
- **Logic functions** for periodic backfills (PRs, reviews, issues,
project items, contributors) and a single signed-webhook route trigger
(`POST /github/webhook`) that performs idempotent upserts for
`pull_request`, `pull_request_review`, `issues`, and `projects_v2_item`
events
- **Views, navigation menu items and a GitHub folder** so the data is
discoverable in the UI out of the box
- **Configurable repos / project numbers** via `GITHUB_REPOS` and
`GITHUB_PROJECT_NUMBERS` application variables — no hardcoded org
## Authentication
Two interchangeable modes (PAT preferred for quick setup, GitHub App
recommended for production):
1. **Personal Access Token** — set `GITHUB_TOKEN`. Used as-is for both
REST and GraphQL.
2. **GitHub App** — set `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`,
`GITHUB_APP_INSTALLATION_ID`. Issues a signed JWT, exchanges it for a
short-lived installation token, and caches the token until expiry.
Webhook signature verification (`X-Hub-Signature-256`) is enforced when
`GITHUB_WEBHOOK_SECRET` is set.
## Notes
- Built on `twenty-sdk@2.0.0` / `twenty-client-sdk@2.0.0`
- Decoupled from internal modules (`quality/bug`, `discord`, `release`,
`code-build`, `project-management`) — `mustBeQa` is inlined and a local
`github` nav folder replaces shared ones
- `npx twenty typecheck`, `yarn lint`, and `npx twenty build` all run
cleanly
- Includes a comprehensive README with setup, env vars, webhook
configuration, and the auth resolution flow