diff --git a/.agents/plans/bold-emerald-earth-pdf-placeholder-field-positioning.md b/.agents/plans/bold-emerald-earth-pdf-placeholder-field-positioning.md
new file mode 100644
index 000000000..580dbdc14
--- /dev/null
+++ b/.agents/plans/bold-emerald-earth-pdf-placeholder-field-positioning.md
@@ -0,0 +1,161 @@
+---
+date: 2026-01-28
+title: Pdf Placeholder Field Positioning
+---
+
+## Overview
+
+This feature enables automatic field placement in PDFs using placeholder text, eliminating the need for manual coordinate-based positioning. It supports two complementary workflows:
+
+1. **Automatic detection on upload** - PDFs containing structured placeholders like `{{signature, r1}}` have fields created automatically when uploaded
+2. **API placeholder positioning** - Developers can reference any text in a PDF to position fields instead of calculating coordinates
+
+## Goals
+
+- Allow users to prepare documents in Word/Google Docs with placeholders that become signature fields
+- Reduce friction for document preparation workflows
+- Provide API developers with a simpler alternative to coordinate-based field positioning
+- Support documents with repeated placeholders (e.g., initials on every page)
+
+## Placeholder Format (Automatic Detection)
+
+```
+{{FIELD_TYPE, RECIPIENT, option1=value1, option2=value2}}
+```
+
+### Components
+
+- **FIELD_TYPE** (required): One of `signature`, `initials`, `name`, `email`, `date`, `text`, `number`, `radio`, `checkbox`, `dropdown`
+- **RECIPIENT** (required): `r1`, `r2`, `r3`, etc. - identifies which recipient the field belongs to
+- **OPTIONS** (optional): Key-value pairs like `required=true`, `fontSize=14`, `readOnly=true`
+
+### Examples
+
+- `{{signature, r1}}` - Signature field for first recipient
+- `{{text, r1, required=true, label=Company Name}}` - Required text field with label
+- `{{number, r2, minValue=0, maxValue=100}}` - Number field with validation
+
+### Behavior
+
+- Placeholders without recipient identifiers (e.g., `{{signature}}`) are skipped during automatic detection - reserved for API use
+- Invalid field types are silently skipped
+- Placeholder text is covered with white rectangles after field creation
+
+## API Placeholder Positioning
+
+The `/api/v2/envelope/field/create-many` endpoint accepts `placeholder` as an alternative to coordinates:
+
+```json
+{
+ "recipientId": 123,
+ "type": "SIGNATURE",
+ "placeholder": "{{signature}}"
+}
+```
+
+### Parameters
+
+| Parameter | Type | Description |
+| ------------- | ------- | -------------------------------------------- |
+| `placeholder` | string | Text to search for in the PDF |
+| `width` | number | Optional override (percentage) |
+| `height` | number | Optional override (percentage) |
+| `matchAll` | boolean | When true, creates fields at ALL occurrences |
+
+### matchAll Behavior
+
+- Default (`false`): Only first occurrence gets a field
+- `true`: Creates a field at every occurrence of the placeholder text
+
+This is useful for documents requiring initials on every page.
+
+## Implementation Components
+
+### Core Functions
+
+- `extractPlaceholdersFromPDF()` - Scans PDF for `{{...}}` patterns with recipient identifiers
+- `removePlaceholdersFromPDF()` - Covers placeholder text with white rectangles
+- `whiteoutRegions()` - Low-level helper for drawing white boxes on PDF pages
+- `parseFieldTypeFromPlaceholder()` - Converts placeholder field type to FieldType enum
+- `parseFieldMetaFromPlaceholder()` - Parses options into fieldMeta format
+
+### Integration Points
+
+1. **Upload flow** (`create-envelope.ts`, `create-envelope-items.ts`)
+ - Extract placeholders at upload time (before saving to storage)
+ - Pass placeholders in-memory to envelope creation
+ - Create placeholder recipients if none provided
+ - Create fields within the same transaction
+
+2. **API field creation** (`create-envelope-fields.ts`)
+ - Accept `placeholder` as alternative to coordinates
+ - Search PDF for placeholder text
+ - Resolve position from bounding box
+ - Support `matchAll` for multiple occurrences
+
+### Field Meta Parsing
+
+The following properties are explicitly parsed:
+
+- `required`, `readOnly` → boolean
+- `fontSize`, `minValue`, `maxValue`, `characterLimit` → number
+- Other properties pass through as strings
+
+Note: Signature fields do not support fieldMeta options.
+
+## Testing
+
+### E2E Tests
+
+**UI Tests** (`e2e/auto-placing-fields/`):
+
+- Single recipient placeholder detection
+- Multiple recipient placeholder detection
+- Field configuration from placeholder options
+- Skipping placeholders without recipient identifiers
+- Skipping invalid field types
+
+**API Tests** (`e2e/api/v2/placeholder-fields-api.spec.ts`):
+
+- Placeholder-based field positioning
+- Width/height overrides
+- Error on placeholder not found
+- Mixed coordinate and placeholder positioning
+- First occurrence only (default)
+- All occurrences with `matchAll: true`
+
+## Documentation
+
+### User Documentation
+
+`/users/documents/pdf-placeholders` - Explains:
+
+- Placeholder format and syntax
+- Supported field types
+- Recipient identifiers
+- Available options per field type
+- Troubleshooting
+
+### Developer Documentation
+
+`/developers/public-api/reference` - Documents:
+
+- Coordinate-based positioning (existing)
+- Placeholder-based positioning (new)
+- matchAll parameter
+- Mixing both methods
+
+## Edge Cases Handled
+
+1. **No placeholders found** - Original PDF returned unchanged
+2. **Placeholder not found (API)** - Returns error with placeholder text
+3. **Multiple occurrences** - First only by default, all with `matchAll: true`
+4. **No recipient identifier** - Skipped during auto-detection, works for API
+5. **Invalid field type** - Skipped during auto-detection
+6. **Signature field with options** - Options ignored (signature doesn't support fieldMeta)
+
+## Future Considerations
+
+- Support for placeholder text styles (bold, underline) to indicate field properties
+- Template-level placeholder mapping for reusable configurations
+- Placeholder validation in document editor before sending
diff --git a/.env.example b/.env.example
index 7e2b8cb34..29fffa4e9 100644
--- a/.env.example
+++ b/.env.example
@@ -1,3 +1,6 @@
+# The license key to enable enterprise features for self hosters
+NEXT_PRIVATE_DOCUMENSO_LICENSE_KEY=
+
# [[AUTH]]
NEXTAUTH_SECRET="secret"
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 962da1ec9..50137d2e1 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -3,6 +3,12 @@ name: Publish Docker
on:
push:
branches: ['release']
+ workflow_dispatch:
+ inputs:
+ tag:
+ description: 'Git tag to build and publish (e.g., v1.0.0)'
+ required: true
+ type: string
jobs:
build_and_publish_platform_containers:
@@ -18,6 +24,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
+ ref: ${{ inputs.tag || github.ref }}
fetch-tags: true
- name: Login to DockerHub
@@ -38,8 +45,11 @@ jobs:
BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
NEXT_PRIVATE_TELEMETRY_KEY: ${{ secrets.NEXT_PRIVATE_TELEMETRY_KEY }}
NEXT_PRIVATE_TELEMETRY_HOST: ${{ secrets.NEXT_PRIVATE_TELEMETRY_HOST }}
+ APP_VERSION: ${{ inputs.tag || '' }}
run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ if [ -z "$APP_VERSION" ]; then
+ APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ fi
GIT_SHA="$(git rev-parse HEAD)"
docker build \
@@ -65,47 +75,6 @@ jobs:
env:
BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
- - name: Build the chromium docker image
- env:
- BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
- run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
- GIT_SHA="$(git rev-parse HEAD)"
-
- docker build \
- -f ./docker/Dockerfile.chromium \
- --progress=plain \
- --build-arg TAG="$GIT_SHA" \
- -t "documenso/documenso-$BUILD_PLATFORM:latest-chromium" \
- -t "documenso/documenso-$BUILD_PLATFORM:$GIT_SHA-chromium" \
- -t "documenso/documenso-$BUILD_PLATFORM:$APP_VERSION-chromium" \
- -t "ghcr.io/documenso/documenso-$BUILD_PLATFORM:latest-chromium" \
- -t "ghcr.io/documenso/documenso-$BUILD_PLATFORM:$GIT_SHA-chromium" \
- -t "ghcr.io/documenso/documenso-$BUILD_PLATFORM:$APP_VERSION-chromium" \
- .
-
- - name: Push the chromium docker image to DockerHub
- env:
- BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
- run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
- GIT_SHA="$(git rev-parse HEAD)"
-
- docker push "documenso/documenso-$BUILD_PLATFORM:latest-chromium"
- docker push "documenso/documenso-$BUILD_PLATFORM:$GIT_SHA-chromium"
- docker push "documenso/documenso-$BUILD_PLATFORM:$APP_VERSION-chromium" \
-
- - name: Push the chromium docker image to GitHub Container Registry
- env:
- BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
- run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
- GIT_SHA="$(git rev-parse HEAD)"
-
- docker push "ghcr.io/documenso/documenso-$BUILD_PLATFORM:latest-chromium"
- docker push "ghcr.io/documenso/documenso-$BUILD_PLATFORM:$GIT_SHA-chromium"
- docker push "ghcr.io/documenso/documenso-$BUILD_PLATFORM:$APP_VERSION-chromium"
-
create_and_publish_manifest:
name: Create and publish manifest
runs-on: ubuntu-latest
@@ -114,6 +83,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
with:
+ ref: ${{ inputs.tag || github.ref }}
fetch-tags: true
- name: Login to DockerHub
@@ -130,8 +100,12 @@ jobs:
password: ${{ secrets.GH_TOKEN }}
- name: Create and push DockerHub manifest
+ env:
+ APP_VERSION: ${{ inputs.tag || '' }}
run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ if [ -z "$APP_VERSION" ]; then
+ APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ fi
GIT_SHA="$(git rev-parse HEAD)"
# Check if the version is stable (no rc or beta in the version)
@@ -166,46 +140,13 @@ jobs:
docker manifest push documenso/documenso:$GIT_SHA
docker manifest push documenso/documenso:$APP_VERSION
- - name: Create and push DockerHub chromium manifest
- run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
- GIT_SHA="$(git rev-parse HEAD)"
-
- # Check if the version is stable (no rc or beta in the version)
- if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
- docker manifest create \
- documenso/documenso:latest-chromium \
- --amend documenso/documenso-amd64:latest-chromium \
- --amend documenso/documenso-arm64:latest-chromium
-
- docker manifest push documenso/documenso:latest-chromium
- fi
-
- if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
- docker manifest create \
- documenso/documenso:rc-chromium \
- --amend documenso/documenso-amd64:rc-chromium \
- --amend documenso/documenso-arm64:rc-chromium
-
- docker manifest push documenso/documenso:rc-chromium
- fi
-
- docker manifest create \
- documenso/documenso:$GIT_SHA-chromium \
- --amend documenso/documenso-amd64:$GIT_SHA-chromium \
- --amend documenso/documenso-arm64:$GIT_SHA-chromium
-
- docker manifest create \
- documenso/documenso:$APP_VERSION-chromium \
- --amend documenso/documenso-amd64:$APP_VERSION-chromium \
- --amend documenso/documenso-arm64:$APP_VERSION-chromium
-
- docker manifest push documenso/documenso:$GIT_SHA-chromium
- docker manifest push documenso/documenso:$APP_VERSION-chromium
-
- name: Create and push Github Container Registry manifest
+ env:
+ APP_VERSION: ${{ inputs.tag || '' }}
run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ if [ -z "$APP_VERSION" ]; then
+ APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ fi
GIT_SHA="$(git rev-parse HEAD)"
# Check if the version is stable (no rc or beta in the version)
@@ -239,40 +180,3 @@ jobs:
docker manifest push ghcr.io/documenso/documenso:$GIT_SHA
docker manifest push ghcr.io/documenso/documenso:$APP_VERSION
-
- - name: Create and push Github Container Registry chromium manifest
- run: |
- APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
- GIT_SHA="$(git rev-parse HEAD)"
-
- # Check if the version is stable (no rc or beta in the version)
- if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
- docker manifest create \
- ghcr.io/documenso/documenso:latest-chromium \
- --amend ghcr.io/documenso/documenso-amd64:latest-chromium \
- --amend ghcr.io/documenso/documenso-arm64:latest-chromium
-
- docker manifest push ghcr.io/documenso/documenso:latest-chromium
- fi
-
- if [[ "$APP_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
- docker manifest create \
- ghcr.io/documenso/documenso:rc-chromium \
- --amend ghcr.io/documenso/documenso-amd64:rc-chromium \
- --amend ghcr.io/documenso/documenso-arm64:rc-chromium
-
- docker manifest push ghcr.io/documenso/documenso:rc-chromium
- fi
-
- docker manifest create \
- ghcr.io/documenso/documenso:$GIT_SHA-chromium \
- --amend ghcr.io/documenso/documenso-amd64:$GIT_SHA-chromium \
- --amend ghcr.io/documenso/documenso-arm64:$GIT_SHA-chromium
-
- docker manifest create \
- ghcr.io/documenso/documenso:$APP_VERSION-chromium \
- --amend ghcr.io/documenso/documenso-amd64:$APP_VERSION-chromium \
- --amend ghcr.io/documenso/documenso-arm64:$APP_VERSION-chromium
-
- docker manifest push ghcr.io/documenso/documenso:$GIT_SHA-chromium
- docker manifest push ghcr.io/documenso/documenso:$APP_VERSION-chromium
diff --git a/.gitignore b/.gitignore
index e85bd9780..961230226 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,3 +63,7 @@ CLAUDE.md
# scripts
scripts/output*
+
+# license
+.documenso-license.json
+.documenso-license-backup.json
diff --git a/apps/documentation/pages/developers/_meta.js b/apps/documentation/pages/developers/_meta.js
index 2f0f9b24d..4286dc3a3 100644
--- a/apps/documentation/pages/developers/_meta.js
+++ b/apps/documentation/pages/developers/_meta.js
@@ -13,6 +13,7 @@ export default {
title: 'API & Integration Guides',
},
'public-api': 'Public API',
- embedding: 'Embedding',
+ embedding: 'Embedded Signing',
+ 'embedded-authoring': 'Embedded Authoring',
webhooks: 'Webhooks',
};
diff --git a/apps/documentation/pages/developers/embedding/authoring.mdx b/apps/documentation/pages/developers/embedded-authoring.mdx
similarity index 94%
rename from apps/documentation/pages/developers/embedding/authoring.mdx
rename to apps/documentation/pages/developers/embedded-authoring.mdx
index d3427f1c8..4cf6fd659 100644
--- a/apps/documentation/pages/developers/embedding/authoring.mdx
+++ b/apps/documentation/pages/developers/embedded-authoring.mdx
@@ -1,12 +1,25 @@
---
-title: Authoring
+title: Embedded Authoring
description: Learn how to use embedded authoring to create documents and templates in your application
---
+import { Callout } from 'nextra/components';
+
+
+ {licenseData.requestedLicenseKey}
+
+ {license.name}
+
+ {i18n.date(license.periodEnd, DateTime.DATE_MED)}
+
+ {license.licenseKey}
+
+ {enabledFlags.length > 0 ? (
+ enabledFlags
+ .map(
+ ([flag]) =>
+ SUBSCRIPTION_CLAIM_FEATURE_FLAGS[
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
+ flag as keyof typeof SUBSCRIPTION_CLAIM_FEATURE_FLAGS
+ ]?.label || flag,
+ )
+ .join(', ')
+ ) : (
+
+ The V1 API will continue to be supported for the foreseeable future, but it is limited to
+ Legacy Documents (Documents created using the old non-envelope editor).
-📖 [Documentation](https://documen.so/api-v2-docs)
+ Important: To work with the new Envelope document system, you
+ must use the
+ V2 API.
+
+
+
+ {match(license.status)
+ .with('ACTIVE', () => (
+
No members found
} + creatable + loadingIndicator={ + isLoading ? ( +
+
+
- {typeof value === 'number' ? value.toLocaleString('en-US') : value} -
+ {children || ( ++ {typeof value === 'number' ? value.toLocaleString('en-US') : value} +
+ )}{t`None`}
; + return{t`None`}
; } return ( -N/A
+
+
diff --git a/apps/remix/package.json b/apps/remix/package.json
index e7e0fa184..d288b9dc8 100644
--- a/apps/remix/package.json
+++ b/apps/remix/package.json
@@ -106,5 +106,5 @@
"vite-plugin-babel-macros": "^1.0.6",
"vite-tsconfig-paths": "^5.1.4"
},
- "version": "2.5.0"
+ "version": "2.6.0"
}
diff --git a/apps/remix/server/main.js b/apps/remix/server/main.js
index e0d54f65c..15fa84e12 100644
--- a/apps/remix/server/main.js
+++ b/apps/remix/server/main.js
@@ -17,7 +17,7 @@ server.use(
serveStatic({
root: 'build/client',
onFound: (path, c) => {
- if (path.startsWith('./build/client/assets')) {
+ if (path.startsWith('build/client/assets')) {
// Hard cache assets with hashed file names.
c.header('Cache-Control', 'public, immutable, max-age=31536000');
} else {
diff --git a/apps/remix/server/router.ts b/apps/remix/server/router.ts
index bf091a955..12ac294ce 100644
--- a/apps/remix/server/router.ts
+++ b/apps/remix/server/router.ts
@@ -10,6 +10,7 @@ import { tsRestHonoApp } from '@documenso/api/hono';
import { auth } from '@documenso/auth/server';
import { API_V2_BETA_URL, API_V2_URL } from '@documenso/lib/constants/app';
import { jobsClient } from '@documenso/lib/jobs/client';
+import { LicenseClient } from '@documenso/lib/server-only/license/license-client';
import { TelemetryClient } from '@documenso/lib/server-only/telemetry/telemetry-client';
import { getIpAddress } from '@documenso/lib/universal/get-ip-address';
import { env } from '@documenso/lib/utils/env';
@@ -140,4 +141,7 @@ if (env('NODE_ENV') !== 'development') {
void TelemetryClient.start();
}
+// Start license client to verify license on startup.
+void LicenseClient.start();
+
export default app;
diff --git a/docker/start.sh b/docker/start.sh
index 56b225e14..2598eae83 100755
--- a/docker/start.sh
+++ b/docker/start.sh
@@ -11,7 +11,7 @@ CERT_PATH="${NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH:-/opt/documenso/cert.p12}"
if [ -f "$CERT_PATH" ] && [ -r "$CERT_PATH" ]; then
printf "✅ Certificate file found and readable - document signing is ready!\n"
else
- printf "⚠️ Certificate not found or not readable\n"
+ printf "⚠️ Certificate not found or not readable\n"
printf "💡 Tip: Documenso will still start, but document signing will be unavailable\n"
printf "🔧 Check: http://localhost:3000/api/certificate-status for detailed status\n"
fi
diff --git a/package-lock.json b/package-lock.json
index 516ee4b01..8cd8b4d01 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@documenso/root",
- "version": "2.5.0",
+ "version": "2.6.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@documenso/root",
- "version": "2.5.0",
+ "version": "2.6.0",
"hasInstallScript": true,
"workspaces": [
"apps/*",
@@ -15,11 +15,10 @@
"dependencies": {
"@ai-sdk/google-vertex": "3.0.81",
"@documenso/prisma": "*",
- "@libpdf/core": "^0.2.2",
+ "@libpdf/core": "^0.2.5",
"@lingui/conf": "^5.6.0",
"@lingui/core": "^5.6.0",
"ai": "^5.0.104",
- "inngest-cli": "^1.13.7",
"luxon": "^3.7.2",
"patch-package": "^8.0.1",
"posthog-node": "4.18.0",
@@ -42,6 +41,7 @@
"dotenv-cli": "^11.0.0",
"eslint": "^8.57.0",
"husky": "^9.1.7",
+ "inngest-cli": "^1.16.1",
"lint-staged": "^16.2.7",
"nanoid": "^5.1.6",
"nodemailer": "^7.0.10",
@@ -53,11 +53,10 @@
"prisma": "^6.19.0",
"prisma-extension-kysely": "^3.0.0",
"prisma-json-types-generator": "^3.6.2",
- "prisma-kysely": "^2.2.1",
+ "prisma-kysely": "^2.3.0",
"rimraf": "^6.1.2",
"superjson": "^2.2.5",
"syncpack": "^14.0.0-alpha.27",
- "trpc-to-openapi": "2.4.0",
"turbo": "^1.13.4",
"vite": "^7.2.4",
"vite-plugin-static-copy": "^3.1.4",
@@ -109,7 +108,7 @@
},
"apps/remix": {
"name": "@documenso/remix",
- "version": "2.5.0",
+ "version": "2.6.0",
"dependencies": {
"@cantoo/pdf-lib": "^2.5.3",
"@documenso/api": "*",
@@ -4026,6 +4025,19 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/@jest/schemas": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
@@ -4155,9 +4167,9 @@
"license": "MIT"
},
"node_modules/@libpdf/core": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@libpdf/core/-/core-0.2.2.tgz",
- "integrity": "sha512-qxYHUirZc4YSxTYkUVtLHqM9ypC9iKPOpHYfpDIUYAZyDGgcHh4SOwhkInHY/Q51TBajXRv6ZZd9fjSPvoQZnw==",
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/@libpdf/core/-/core-0.2.5.tgz",
+ "integrity": "sha512-+oTpNRkEdL1kVmeJr6qz2wf0yqJx5FmUVN2u0kDuX81wvxyzYOlMjmFD8qbbJqyYiNZp0J7IAcW6VsZr+MW1Uw==",
"license": "MIT",
"dependencies": {
"@noble/ciphers": "^2.1.1",
@@ -17745,6 +17757,7 @@
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
"integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0"
@@ -18988,12 +19001,13 @@
}
},
"node_modules/chownr": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
- "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
- "license": "ISC",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
"engines": {
- "node": ">=10"
+ "node": ">=18"
}
},
"node_modules/ci-info": {
@@ -23886,36 +23900,6 @@
"node": ">=14.14"
}
},
- "node_modules/fs-minipass": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
- "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
- "license": "ISC",
- "dependencies": {
- "minipass": "^3.0.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/fs-minipass/node_modules/minipass": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
- "license": "ISC",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/fs-minipass/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "license": "ISC"
- },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -24650,19 +24634,19 @@
}
},
"node_modules/h3": {
- "version": "1.15.1",
- "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.1.tgz",
- "integrity": "sha512-+ORaOBttdUm1E2Uu/obAyCguiI7MbBvsLTndc3gyK3zU+SYLoZXlyCP9Xgy0gikkGufFLTZXCXD6+4BsufnmHA==",
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.5.tgz",
+ "integrity": "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==",
"license": "MIT",
"dependencies": {
"cookie-es": "^1.2.2",
- "crossws": "^0.3.3",
+ "crossws": "^0.3.5",
"defu": "^6.1.4",
- "destr": "^2.0.3",
+ "destr": "^2.0.5",
"iron-webcrypto": "^1.2.1",
- "node-mock-http": "^1.0.0",
+ "node-mock-http": "^1.0.4",
"radix3": "^1.1.2",
- "ufo": "^1.5.4",
+ "ufo": "^1.6.3",
"uncrypto": "^0.1.3"
}
},
@@ -25494,16 +25478,17 @@
}
},
"node_modules/inngest-cli": {
- "version": "1.13.7",
- "resolved": "https://registry.npmjs.org/inngest-cli/-/inngest-cli-1.13.7.tgz",
- "integrity": "sha512-u3gbUsjsTHfh5quKE3C3sw/NENFPjiWG602SNZya0Eto44U9KGVT0nHp9UoZF5qiG7X83fJqqNEjDKN4FB9JaQ==",
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/inngest-cli/-/inngest-cli-1.16.1.tgz",
+ "integrity": "sha512-B5Z2vgidh6HM7HVsQFZSffJpnTKB0Rm20NDL1qOjBtF8ZZgun+mJNjUYAcqOU4l8SVVEG0nfPnphsWPLZHXdsA==",
+ "dev": true,
"hasInstallScript": true,
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
"adm-zip": "^0.5.10",
"debug": "^4.3.4",
"node-fetch": "^2.6.7",
- "tar": "^6.2.1"
+ "tar": "^7.5.3"
},
"bin": {
"inngest": "bin/inngest",
@@ -27842,9 +27827,9 @@
}
},
"node_modules/mermaid": {
- "version": "11.12.1",
- "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.1.tgz",
- "integrity": "sha512-UlIZrRariB11TY1RtTgUWp65tphtBv4CSq7vyS2ZZ2TgoMjs2nloq+wFqxiwcxlhHUvs7DPGgMjs2aeQxz5h9g==",
+ "version": "11.12.2",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz",
+ "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==",
"license": "MIT",
"dependencies": {
"@braintree/sanitize-url": "^7.1.1",
@@ -28765,54 +28750,24 @@
}
},
"node_modules/minizlib": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
- "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "minipass": "^3.0.0",
- "yallist": "^4.0.0"
+ "minipass": "^7.1.2"
},
"engines": {
- "node": ">= 8"
+ "node": ">= 18"
}
},
- "node_modules/minizlib/node_modules/minipass": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
- "license": "ISC",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/minizlib/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "license": "ISC"
- },
"node_modules/mj-context-menu": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==",
"license": "Apache-2.0"
},
- "node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "license": "MIT",
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/mlly": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
@@ -29443,9 +29398,9 @@
}
},
"node_modules/node-mock-http": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.3.tgz",
- "integrity": "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz",
+ "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==",
"license": "MIT"
},
"node_modules/node-releases": {
@@ -31354,51 +31309,22 @@
}
},
"node_modules/prisma-kysely": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/prisma-kysely/-/prisma-kysely-2.2.1.tgz",
- "integrity": "sha512-hxue1/ZzyBJ8qx6bSBNUjF+A+tl78PM5Sg/wIAIph9hxwdiGcWTr8JPQveva4zvA57bwRJhAJjDvdy8MK4UNuA==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/prisma-kysely/-/prisma-kysely-2.3.0.tgz",
+ "integrity": "sha512-/+VF2t2DlY+t/27hhyH5ULWxBAAsMBPgOo8Ltq7uXpBz49lUf4XuO1ff9HV0l7J3aDojG+YyczEvY0og9uRqsw==",
"license": "MIT",
"dependencies": {
- "@mrleebo/prisma-ast": "^0.13.0",
- "@prisma/generator-helper": "6.16.2",
- "@prisma/internals": "6.16.2",
- "typescript": "^5.9.2",
- "zod": "^4.1.5"
+ "@mrleebo/prisma-ast": "^0.13.1",
+ "@prisma/generator-helper": "^6.2.0",
+ "@prisma/internals": "^6.2.0",
+ "typescript": "^5.9.3",
+ "zod": "^4.3.5"
},
"bin": {
"prisma-kysely": "dist/bin.js"
},
"peerDependencies": {
- "prisma": "~6.16"
- }
- },
- "node_modules/prisma-kysely/node_modules/@prisma/debug": {
- "version": "6.16.2",
- "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.2.tgz",
- "integrity": "sha512-bo4/gA/HVV6u8YK2uY6glhNsJ7r+k/i5iQ9ny/3q5bt9ijCj7WMPUwfTKPvtEgLP+/r26Z686ly11hhcLiQ8zA==",
- "license": "Apache-2.0"
- },
- "node_modules/prisma-kysely/node_modules/@prisma/dmmf": {
- "version": "6.16.2",
- "resolved": "https://registry.npmjs.org/@prisma/dmmf/-/dmmf-6.16.2.tgz",
- "integrity": "sha512-o9ztgdbj2KZXl6DL+oP56TTC0poTLPns9/MeU761b49E1IQ/fd0jwdov1bidlNOiwio8Nsou23xNrYE/db10aA==",
- "license": "Apache-2.0"
- },
- "node_modules/prisma-kysely/node_modules/@prisma/generator": {
- "version": "6.16.2",
- "resolved": "https://registry.npmjs.org/@prisma/generator/-/generator-6.16.2.tgz",
- "integrity": "sha512-7bwRmtMIgfe1rUynh1p9VlmYvEiidbRO6aBphPBS6YGEGSvNe8+QExbRpsqFlFBvIX76BhZCxuEj7ZwALMYRKQ==",
- "license": "Apache-2.0"
- },
- "node_modules/prisma-kysely/node_modules/@prisma/generator-helper": {
- "version": "6.16.2",
- "resolved": "https://registry.npmjs.org/@prisma/generator-helper/-/generator-helper-6.16.2.tgz",
- "integrity": "sha512-8tVnWM8ETJNrvI5CT9eKCW23+aPLNkidC+g9NJn7ghXm60Q7GGlLX5tmvn5dE8tXvs/FSX3MN7KNmNJpOr89Hw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@prisma/debug": "6.16.2",
- "@prisma/dmmf": "6.16.2",
- "@prisma/generator": "6.16.2"
+ "prisma": ">=6.2.0 <7.0.0"
}
},
"node_modules/prismjs": {
@@ -34891,36 +34817,31 @@
}
},
"node_modules/tar": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
- "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
- "license": "ISC",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz",
+ "integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
"dependencies": {
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "minipass": "^5.0.0",
- "minizlib": "^2.1.1",
- "mkdirp": "^1.0.3",
- "yallist": "^4.0.0"
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
},
"engines": {
- "node": ">=10"
- }
- },
- "node_modules/tar/node_modules/minipass": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
- "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
- "license": "ISC",
- "engines": {
- "node": ">=8"
+ "node": ">=18"
}
},
"node_modules/tar/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "license": "ISC"
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/teeny-request": {
"version": "10.1.0",
@@ -35197,9 +35118,9 @@
}
},
"node_modules/trpc-to-openapi": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/trpc-to-openapi/-/trpc-to-openapi-2.4.0.tgz",
- "integrity": "sha512-B6xrwOC3Ab0q1BWD/QbJzK4OUpCLoT02hAzshSUXEuIZGcJZkMG/OJ4/3gd20dyr8aI+CrFirpWKRIo7JmHbMQ==",
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/trpc-to-openapi/-/trpc-to-openapi-2.1.5.tgz",
+ "integrity": "sha512-cX6AlrIBEK0FJe8XJ0wFCroXFqTRpF3J5v4vU5D0Tq7YI1vj8oOIY50iaJX4Gv1PZTA6Dm9DMF7R1MUtlPZ4dQ==",
"license": "MIT",
"workspaces": [
".",
@@ -35212,17 +35133,17 @@
"examples/with-nuxtjs"
],
"dependencies": {
- "co-body": "6.2.0",
- "h3": "1.15.1",
+ "co-body": "^6.1.0",
+ "h3": "^1.6.4",
"openapi3-ts": "4.4.0"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.6.1"
},
"peerDependencies": {
- "@trpc/server": "^11.1.0",
+ "@trpc/server": "^11.0.0-rc.648",
"zod": "^3.23.8",
- "zod-openapi": "4.2.4"
+ "zod-openapi": "^4.1.0"
}
},
"node_modules/trpc-to-openapi/node_modules/@rollup/rollup-linux-x64-gnu": {
@@ -35656,9 +35577,9 @@
}
},
"node_modules/ufo": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
- "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==",
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
+ "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==",
"license": "MIT"
},
"node_modules/uint8array-extras": {
@@ -37466,7 +37387,7 @@
"prisma": "^6.19.0",
"prisma-extension-kysely": "^3.0.0",
"prisma-json-types-generator": "^3.6.2",
- "prisma-kysely": "^2.2.1",
+ "prisma-kysely": "^2.3.0",
"ts-pattern": "^5.9.0",
"zod": "^3.25.76",
"zod-prisma-types": "3.3.5"
@@ -37521,7 +37442,7 @@
"formidable": "^3.5.4",
"luxon": "^3.7.2",
"superjson": "^2.2.5",
- "trpc-to-openapi": "2.4.0",
+ "trpc-to-openapi": "^2.1.5",
"ts-pattern": "^5.9.0",
"zod": "^3.25.76",
"zod-form-data": "^2.0.8",
diff --git a/package.json b/package.json
index fc6635969..3caf4d260 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"apps/*",
"packages/*"
],
- "version": "2.5.0",
+ "version": "2.6.0",
"scripts": {
"postinstall": "patch-package",
"build": "turbo run build",
@@ -61,6 +61,7 @@
"dotenv-cli": "^11.0.0",
"eslint": "^8.57.0",
"husky": "^9.1.7",
+ "inngest-cli": "^1.16.1",
"lint-staged": "^16.2.7",
"nanoid": "^5.1.6",
"nodemailer": "^7.0.10",
@@ -72,11 +73,10 @@
"prisma": "^6.19.0",
"prisma-extension-kysely": "^3.0.0",
"prisma-json-types-generator": "^3.6.2",
- "prisma-kysely": "^2.2.1",
+ "prisma-kysely": "^2.3.0",
"rimraf": "^6.1.2",
"superjson": "^2.2.5",
"syncpack": "^14.0.0-alpha.27",
- "trpc-to-openapi": "2.4.0",
"turbo": "^1.13.4",
"vite": "^7.2.4",
"vite-plugin-static-copy": "^3.1.4",
@@ -86,11 +86,10 @@
"dependencies": {
"@ai-sdk/google-vertex": "3.0.81",
"@documenso/prisma": "*",
- "@libpdf/core": "^0.2.2",
+ "@libpdf/core": "^0.2.5",
"@lingui/conf": "^5.6.0",
"@lingui/core": "^5.6.0",
"ai": "^5.0.104",
- "inngest-cli": "^1.13.7",
"luxon": "^3.7.2",
"patch-package": "^8.0.1",
"posthog-node": "4.18.0",
diff --git a/packages/api/v1/contract.ts b/packages/api/v1/contract.ts
index 50f096498..172c9833f 100644
--- a/packages/api/v1/contract.ts
+++ b/packages/api/v1/contract.ts
@@ -43,6 +43,9 @@ import {
const c = initContract();
+const deprecatedDescription =
+ 'This endpoint is deprecated, but will continue to be supported. For more details, see https://docs.documenso.com/developers/public-api.';
+
export const ApiContractV1 = c.router(
{
getDocuments: {
@@ -55,6 +58,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Get all documents',
+ deprecated: true,
+ description: deprecatedDescription,
},
getDocument: {
@@ -66,6 +71,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Get a single document',
+ deprecated: true,
+ description: deprecatedDescription,
},
downloadSignedDocument: {
@@ -78,6 +85,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Download a signed document when the storage transport is S3',
+ deprecated: true,
+ description: deprecatedDescription,
},
createDocument: {
@@ -90,6 +99,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Upload a new document and get a presigned URL',
+ deprecated: true,
+ description: deprecatedDescription,
},
createTemplate: {
@@ -102,6 +113,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Create a new template and get a presigned URL',
+ deprecated: true,
+ description: deprecatedDescription,
},
deleteTemplate: {
@@ -114,6 +127,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Delete a template',
+ deprecated: true,
+ description: deprecatedDescription,
},
getTemplate: {
@@ -125,6 +140,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Get a single template',
+ deprecated: true,
+ description: deprecatedDescription,
},
getTemplates: {
@@ -137,6 +154,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Get all templates',
+ deprecated: true,
+ description: deprecatedDescription,
},
createDocumentFromTemplate: {
@@ -150,7 +169,7 @@ export const ApiContractV1 = c.router(
},
summary: 'Create a new document from an existing template',
deprecated: true,
- description: `This has been deprecated in favour of "/api/v1/templates/:templateId/generate-document". You may face unpredictable behavior using this endpoint as it is no longer maintained.`,
+ description: `${deprecatedDescription} \n\nIf you must use the V1 API, use "/api/v1/templates/:templateId/generate-document" instead.`,
},
generateDocumentFromTemplate: {
@@ -165,8 +184,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Create a new document from an existing template',
- description:
- 'Create a new document from an existing template. Passing in values for title and meta will override the original values defined in the template. If you do not pass in values for recipients, it will use the values defined in the template.',
+ deprecated: true,
+ description: `${deprecatedDescription} \n\nCreate a new document from an existing template. Passing in values for title and meta will override the original values defined in the template. If you do not pass in values for recipients, it will use the values defined in the template.`,
},
sendDocument: {
@@ -181,9 +200,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Send a document for signing',
- // I'm aware this should be in the variable itself, which it is, however it's difficult for users to find in our current UI.
- description:
- 'Notes\n\n`sendEmail` - Whether to send an email to the recipients asking them to action the document. If you disable this, you will need to manually distribute the document to the recipients using the generated signing links. Defaults to true',
+ deprecated: true,
+ description: `${deprecatedDescription} \n\nNotes\n\nsendEmail - Whether to send an email to the recipients asking them to action the document. If you disable this, you will need to manually distribute the document to the recipients using the generated signing links. Defaults to true`,
},
resendDocument: {
@@ -198,6 +216,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Re-send a document for signing',
+ deprecated: true,
+ description: deprecatedDescription,
},
deleteDocument: {
@@ -210,6 +230,8 @@ export const ApiContractV1 = c.router(
404: ZUnsuccessfulResponseSchema,
},
summary: 'Delete a document',
+ deprecated: true,
+ description: deprecatedDescription,
},
createRecipient: {
@@ -224,6 +246,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Create a recipient for a document',
+ deprecated: true,
+ description: deprecatedDescription,
},
updateRecipient: {
@@ -238,6 +262,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Update a recipient for a document',
+ deprecated: true,
+ description: deprecatedDescription,
},
deleteRecipient: {
@@ -252,6 +278,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Delete a recipient from a document',
+ deprecated: true,
+ description: deprecatedDescription,
},
createField: {
@@ -266,6 +294,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Create a field for a document',
+ deprecated: true,
+ description: deprecatedDescription,
},
updateField: {
@@ -280,6 +310,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Update a field for a document',
+ deprecated: true,
+ description: deprecatedDescription,
},
deleteField: {
@@ -294,6 +326,8 @@ export const ApiContractV1 = c.router(
500: ZUnsuccessfulResponseSchema,
},
summary: 'Delete a field from a document',
+ deprecated: true,
+ description: deprecatedDescription,
},
},
{
diff --git a/packages/api/v1/implementation.ts b/packages/api/v1/implementation.ts
index 4dba574ab..b3d9825c0 100644
--- a/packages/api/v1/implementation.ts
+++ b/packages/api/v1/implementation.ts
@@ -796,6 +796,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, {
title: body.title,
},
attachments: body.attachments,
+ formValues: body.formValues,
requestMetadata: metadata,
});
diff --git a/packages/api/v1/openapi.ts b/packages/api/v1/openapi.ts
index 293395b18..43cecb2ac 100644
--- a/packages/api/v1/openapi.ts
+++ b/packages/api/v1/openapi.ts
@@ -11,7 +11,8 @@ export const OpenAPIV1 = Object.assign(
info: {
title: 'Documenso API',
version: '1.0.0',
- description: 'The Documenso API for retrieving, creating, updating and deleting documents.',
+ description:
+ 'API V1 is deprecated, but will continue to be supported. For more details, see https://docs.documenso.com/developers/public-api. \n\nThe Documenso API for retrieving, creating, updating and deleting documents.',
},
servers: [
{
diff --git a/packages/app-tests/e2e/api/v2/placeholder-fields-api.spec.ts b/packages/app-tests/e2e/api/v2/placeholder-fields-api.spec.ts
new file mode 100644
index 000000000..e25beaef7
--- /dev/null
+++ b/packages/app-tests/e2e/api/v2/placeholder-fields-api.spec.ts
@@ -0,0 +1,453 @@
+import { PDF, StandardFonts } from '@libpdf/core';
+import type { APIRequestContext } from '@playwright/test';
+import { expect, test } from '@playwright/test';
+import type { Team, User } from '@prisma/client';
+import fs from 'node:fs';
+import path from 'node:path';
+
+import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
+import { createApiToken } from '@documenso/lib/server-only/public-api/create-api-token';
+import { prisma } from '@documenso/prisma';
+import { EnvelopeType, FieldType, RecipientRole } from '@documenso/prisma/client';
+import { seedUser } from '@documenso/prisma/seed/users';
+import type {
+ TCreateEnvelopePayload,
+ TCreateEnvelopeResponse,
+} from '@documenso/trpc/server/envelope-router/create-envelope.types';
+import type { TCreateEnvelopeRecipientsRequest } from '@documenso/trpc/server/envelope-router/envelope-recipients/create-envelope-recipients.types';
+import type { TGetEnvelopeResponse } from '@documenso/trpc/server/envelope-router/get-envelope.types';
+
+const WEBAPP_BASE_URL = NEXT_PUBLIC_WEBAPP_URL();
+const baseUrl = `${WEBAPP_BASE_URL}/api/v2-beta`;
+
+const FIXTURES_DIR = path.join(__dirname, '../../../../assets/fixtures/auto-placement');
+
+test.describe.configure({ mode: 'parallel' });
+
+test.describe('Placeholder-based field creation', () => {
+ let user: User, team: Team, token: string;
+
+ test.beforeEach(async () => {
+ ({ user, team } = await seedUser());
+ ({ token } = await createApiToken({
+ userId: user.id,
+ teamId: team.id,
+ tokenName: 'test',
+ expiresIn: null,
+ }));
+ });
+
+ const createEnvelopeWithPdf = async (
+ request: APIRequestContext,
+ pdfFilename: string,
+ ): Promise