Skip to content

chore: sync upstream 2026 09 11 - #13

Merged
austinw8 merged 68 commits into
mainfrom
chore/sync-upstream-2026-09-11
Sep 12, 2026
Merged

austinw8 merged 68 commits into
mainfrom
chore/sync-upstream-2026-09-11

Conversation

@austinw8

Copy link
Copy Markdown
Collaborator

Summary

Syncs main with upstream/main (documenso/documenso), bringing in 54 commits (through v2.18.0 and beyond) since our last sync. main was 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 against upstream/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):

  • i18n removal (14 files): kept our English-only deletion (translation files, workflows, language-switcher UI) over upstream's continued non-English translation work, consistent with the recent chore: drop multi-language support decision. Regenerated packages/lib/translations/en/web.po via lingui extract afterward rather than hand-merging the generated catalog.
  • Settings unification: upstream shipped a large "unified settings" rewrite (UnifiedSettingsLayout etc.) touching menu-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).
  • AI features (packages/lib/constants/app.ts, env.ts): upstream independently added the same IS_AI_FEATURES_CONFIGURED feature 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 returned false in 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.
  • Password-change emails: adopted upstream's new self-service-vs-admin-initiated copy split in reset-password.tsx / send-reset-password.ts, keeping our sender identity and support address (using the existing SUPPORT_EMAIL constant instead of the hardcoded address that was there before).
  • Dropped two Documenso commercial upsells that came in via upstream features: a "View plans" button linking to documenso.com/pricing in the self-signed-document email, and an "Enterprise / contact sales" + "compare plans" block in the org-create dialog. Consistent with our fork already stripping this kind of content elsewhere.
  • Team documents page: took upstream's rewrite (adds bulk actions, folders, drag-drop, filters) and re-removed the team avatar+heading block we'd previously dropped.
  • packages/lib/jobs/definitions/internal/alert-organisation-seat-drift.handler.ts (new upstream file, not conflicted): referenced DOCUMENSO_INTERNAL_EMAIL, which doesn't exist on our fork — renamed to our KEEPCONTRACTS_INTERNAL_EMAIL.
  • package-lock.json was 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 backing scripts/*.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) — clean
  • npx biome check on all changed .ts/.tsx files — zero errors (327 pre-existing warnings across upstream's own new files, none introduced by conflict resolution)
  • npm install — clean, patches apply
  • npm run translate:extract — clean, 3217 messages, none missing

dguyen and others added 30 commits July 23, 2026 13:57
## 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

![Before and after: copy button added next to the license key show/hide
toggle](https://artifacts.duncan.land/documenso-pr3123-license-copy)

> 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`.
catalinpit and others added 21 commits September 1, 2026 13:54
`/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
@austinw8
austinw8 merged commit 0657814 into main Sep 12, 2026
3 of 6 checks passed
@austinw8
austinw8 deleted the chore/sync-upstream-2026-09-11 branch September 12, 2026 00:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.