chore: sync upstream 2026 09 11 - #13
Merged
Merged
Conversation
## Description Adds a copy button next to the show/hide toggle for the license key in the admin panel license card (Admin Panel → Stats). - Ghost button matching the existing eye-toggle styling (`h-6 w-6`, `CopyIcon`) - Uses the standard `useCopyToClipboard` + toast pattern (same as `template-direct-link-badge.tsx`) - Copies the key regardless of masked/visible state New translation strings will be picked up by the next `chore: extract translations` run. ## Before / After  > Screenshots taken against a locally mocked ACTIVE license (the mock is not part of this PR). ## Testing - `npx tsc --noEmit -p apps/remix` clean - `biome check` clean - Smoke-tested in browser: clicking the button fires the "Copied to clipboard" toast (visible in the screenshot above)
…ocumenso#3132) ## Description Corrects the webhooks documentation, which described delivery behavior that does not exist in the implementation. ## Changes Made - Replaced the fabricated retry schedule (5 attempts / immediate-to-2h backoff) with the real provider-dependent behavior: retries belong to the job provider (`NEXT_PRIVATE_JOBS_PROVIDER`) — local (default) 4 total attempts back-to-back, BullMQ 3 attempts with exponential backoff from 1s, Inngest 5 attempts with platform backoff. - Fixed the webhook timeout from 30 seconds to 10 seconds (`WEBHOOK_TIMEOUT_MS = 10_000`, hard abort). - Clarified failure semantics: non-2xx fails, 3xx redirects are not followed (`redirect: 'manual'`), network/SSRF-blocked calls record response code 0; failed deliveries mark only the `WebhookCall` record — the webhook itself is never auto-disabled. - Corrected URL requirements: `http://` is accepted; documented the SSRF guard (private/loopback blocked, `NEXT_PRIVATE_WEBHOOK_SSRF_BYPASS_HOSTS` bypass for self-hosters). - Added `envelopeId` to both field tables and all payload/recipient JSON examples; framed numeric `id` as the legacy v1 identifier. - Removed a documented `documentMeta` field that exists in neither the Zod schema nor Prisma; fixed timezone/dateFormat examples to the hardcoded `Etc/UTC` / `yyyy-MM-dd hh:mm a` values. - Added missing `REJECTED`/`CANCELLED` statuses and `TEMPLATE_DIRECT_LINK` source; fixed `templateId` to `null` on TEMPLATE_* examples; documented the previously missing `RECIPIENT_EXPIRED` event across setup, events, and verification pages. ## Testing Performed Docs-only change. Every claim verified against the implementation (`execute-webhook-call.ts`, job clients, `webhook-payload.ts`, `assert-webhook-url.ts`, webhook-router schema).
Swaps the tab row and dropdowns for faceted filter pills (status, sender, period) with a shared reset, and moves URL param handling to nuqs. <img width="2198" height="1674" alt="image" src="https://github.com/user-attachments/assets/6996431c-09c8-45c3-bc30-f0a1e503c941" />
Previously attempting to complete a document which is already completed you'd get a generic error toast. Now when completing a document that you have already completed you are redirected to the completed page. Handles cases where two mutations managed to fire racing eachother.
Use our fork of `skia-canvas` for rendering which handles encoding characters correctly with the caveat font and other similar fonts that can group glyphs like ligatures. This resolves issues with pdf text extraction where characters were unable to be extracted due to lacking any data within the cmaps.
Redesigns the popover shown when hovering a recipient field avatar in
the envelope view.
- Field-first hierarchy: header shows field-type icon + "{Type} field"
with inline status (Signed/Pending/Read Only) as a colored dot + label
- Recipient (name/email) moved to a recessed footer well as secondary
context
- Hide-field action moved from floating over the text to a ghost icon
button in the footer well
- Added a `FieldType` → icon map mirroring `field-selector.tsx`
## Screenshots
| Before | After |
| --- | --- |
| <img
src="https://raw.githubusercontent.com/ephraimduncan/documenso/assets-pr-3070-hover-card/.github/assets/hover-before.png"
width="320" alt="Previous hover tooltip: centered badge, title and
recipient text" /> | <img
src="https://raw.githubusercontent.com/ephraimduncan/documenso/assets-pr-3070-hover-card/.github/assets/hover-after.png"
width="320" alt="New hover card: field-first header with status,
recipient footer well" /> |
## Description
The rate limits page claimed "No rate limit headers are currently
provided" and advised a fixed 60-second wait. The middleware has been
setting standard headers on every API response.
## Changes Made
- Documented `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and
`X-RateLimit-Reset` (Unix epoch seconds) on every `/api/v1`, `/api/v2`,
and `/api/v2-beta` response, and `Retry-After` (seconds, min 1) on 429s.
- Explained that windows are fixed epoch-aligned 1-minute buckets, so
the real wait is 1–60s — clients should honor `Retry-After` instead of
sleeping a fixed 60s.
- Showed both 429 body shapes: the global per-IP limiter's `{ "error":
... }` vs AppError-based `code`/`message`/`statusCode`.
- Covered the three distinct 429 sources: global per-IP limit,
organisation windowed limits, and monthly envelope quota (which sends no
rate-limit headers).
- Added `/api/v2-beta/*` to the documented scope; left the
verified-correct 1000/min figure and plan-limits table untouched.
## Testing Performed
Docs-only change. Verified against `rate-limit-middleware.ts`,
`rate-limit.ts`, `check-organisation-rate-limits.ts`,
`check-monthly-quota.ts`, and the remix server router.
…pdate routes (documenso#3134) ## Description The envelope cancel, delete, and update routes rendered without descriptions in the generated OpenAPI reference. ## Changes Made - Added route-level OpenAPI `description` to `cancel-envelope.types.ts`, `delete-envelope.types.ts`, and `update-envelope.types.ts`. - Added field-level `.describe()` calls on request schemas, matching the style of sibling envelope-router schemas (e.g. `get-envelopes-by-ids.types.ts`, `distribute-envelope.types.ts`). ## Testing Performed `npx tsc --noEmit -p packages/trpc` passes with no errors. Metadata-only change — no runtime behavior affected.
…menso#3135) ## Description Documents API page: adds the missing Cancel Document section and fixes a fabricated request body on get-many that would fail schema validation for anyone copying the docs. ## Changes Made - Added a `## Cancel Document` section: `POST /envelope/cancel` with `{ envelopeId, reason? }`, PENDING-only (400 otherwise), not idempotent, two-stage access (404 if not visible, 401 without owner/MANAGER+), fires `DOCUMENT_CANCELLED` webhook, emails only SENT/OPENED non-CC non-rejected recipients. - Replaced the fabricated `envelopeIds: [...]` get-many body with the real nested selector: `{ "ids": { "type": "envelopeId" | "documentId" | "templateId", "ids": [...] } }` (string[] for envelopeId, number[] otherwise, 1–20 IDs). - Added the missing `### Response` for get-many (`{ "data": [...] }`) and documented silent filtering of inaccessible IDs (no 404). - Added `CANCELLED` to the status table, mermaid state diagram, transitions prose, and filter values. - Removed the nonexistent `source: "API"` value (real enum: `DOCUMENT | TEMPLATE | TEMPLATE_DIRECT_LINK`). - Fixed fabricated `pagination` wrappers to the real flat shape `{ data, count, currentPage, perPage, totalPages }`; fixed Field `id` type and mismatched code fences. - Migration guide: warned that get-many's body shape changed from `documentIds: number[]` — the breaking part of that migration. ## Testing Performed Docs-only change (plus the migration guide). Verified against the envelope-router types, `cancel-document.ts`, the cancel e2e spec, and `schema.prisma`.
`/api/health` and `/api/certificate-status` reported the cert as available when `NEXT_PRIVATE_SIGNING_TRANSPORT` was unset, even though sealing defaults to the local P12 and fails if it is missing, unreadable, or expired.
Upgrade to Node 24 LTS, using the alpine 3.23 tag to handle issues with streaming zip files on 24.16 which hangs npm ci. Pin npm to 11.19.1 for min-release-age-exclude support. Slim the runner image by dropping dev deps, the react-email CLI, and esbuild, none of which run in production. Install turbo from the lockfile version instead of a hardcoded one.
Selecting password auth failed with a generic "Unauthorized" for users who signed up via OAuth or passkey, with no way to set one. Detect the missing password and email the existing reset link from the signing dialog and security settings. Require a 2FA code and rate limit update-password.
…-2026-09-11 # Conflicts: # .github/workflows/translations-force-pull.yml # .github/workflows/translations-pull.yml # .github/workflows/translations-upload.yml # README.md # apps/remix/app/components/dialogs/organisation-create-dialog.tsx # apps/remix/app/components/general/app-command-menu.tsx # apps/remix/app/components/general/menu-switcher.tsx # apps/remix/app/components/general/org-menu-switcher.tsx # apps/remix/app/root.tsx # apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx # apps/remix/app/routes/_authenticated+/settings+/_layout.tsx # apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents._index.tsx # apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings._layout.tsx # apps/remix/app/routes/_index.tsx # apps/remix/app/routes/_unauthenticated+/organisation.decline.$token.tsx # apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx # apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx # apps/remix/react-router.config.ts # docker/testing/compose.yml # package-lock.json # packages/api/v1/openapi.ts # packages/app-tests/e2e/teams/default-recipients.spec.ts # packages/email/template-components/template-branding-logo.tsx # packages/email/template-components/template-document-image.tsx # packages/email/template-components/template-document-self-signed.tsx # packages/email/templates/admin-user-created.tsx # packages/email/templates/reset-password.tsx # packages/lib/constants/app.ts # packages/lib/server-only/auth/send-reset-password.ts # packages/lib/translations/de/web.po # packages/lib/translations/en/web.po # packages/lib/translations/es/web.po # packages/lib/translations/fr/web.po # packages/lib/translations/it/web.po # packages/lib/translations/ja/web.po # packages/lib/translations/ko/web.po # packages/lib/translations/nl/web.po # packages/lib/translations/pl/web.po # packages/lib/translations/pt-BR/web.po # packages/lib/translations/zh/web.po # packages/ui/components/common/language-switcher-dialog.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Syncs
mainwithupstream/main(documenso/documenso), bringing in 54 commits (through v2.18.0 and beyond) since our last sync.mainwas already merged separately for the v2.18.0 admin auth-bypass security fix (#12); this is the rest of the backlog.Merge instructions
Please merge this PR with "Create a merge commit", not "Squash and merge" — squashing collapses the two-parent merge into one commit with no ancestry link to upstream, which silently breaks
git merge-base/ahead-behind tracking againstupstream/main(see #5/#6 for the previous time this happened and had to be fixed in a follow-up PR).Conflict resolution notes
36 files conflicted. Notable resolutions (all others were mechanical: header-size/branding-only, or one side untouched):
chore: drop multi-language supportdecision. Regeneratedpackages/lib/translations/en/web.povialingui extractafterward rather than hand-merging the generated catalog.UnifiedSettingsLayoutetc.) touchingmenu-switcher.tsx,org-menu-switcher.tsx,app-command-menu.tsx, and the settings layout routes. Took upstream's versions and reapplied our specific customizations on top (header sizes, dropped the language-switcher entries).packages/lib/constants/app.ts,env.ts): upstream independently added the sameIS_AI_FEATURES_CONFIGUREDfeature we added in feat: enable AI features with Google Vertex AI service account support #10, but with a client/server-safe split (ours called Vertex env vars directly, which silently always returnedfalsein the browser). Merged: kept our broader credential support (API key / service account JSON / ADC) but adopted upstream's public-env-flag pattern so the client-side check actually works.reset-password.tsx/send-reset-password.ts, keeping our sender identity and support address (using the existingSUPPORT_EMAILconstant instead of the hardcoded address that was there before).packages/lib/jobs/definitions/internal/alert-organisation-seat-drift.handler.ts(new upstream file, not conflicted): referencedDOCUMENSO_INTERNAL_EMAIL, which doesn't exist on our fork — renamed to ourKEEPCONTRACTS_INTERNAL_EMAIL.package-lock.jsonwas regenerated (npm install) rather than hand-merged.Also worth knowing: upstream deleted 3 of their own Claude-Code skill definitions (
.agents/skills/create-justification,create-plan,create-scratch, plus their backingscripts/*.ts) since our fork diverged. Since our side never modified them, the merge correctly took upstream's deletion — this isn't something introduced by this PR, but flagging it since it removes tooling that may have been in active use locally.Verification
npm run typecheck(apps/remix) — cleannpx biome checkon all changed.ts/.tsxfiles — zero errors (327 pre-existing warnings across upstream's own new files, none introduced by conflict resolution)npm install— clean, patches applynpm run translate:extract— clean, 3217 messages, none missing