chore: merged main

This commit is contained in:
Catalin Pit
2026-06-17 12:04:51 +03:00
103 changed files with 6524 additions and 77 deletions
@@ -1,3 +1,4 @@
import { IS_INSTANCE_CSC_MODE } from '@documenso/lib/constants/app';
import { ZRecipientActionAuthTypesSchema, ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
import type { TEditorEnvelope } from '@documenso/lib/types/envelope-editor';
import { ZRecipientEmailSchema } from '@documenso/lib/types/recipient';
@@ -22,11 +23,49 @@ const LocalRecipientSchema = z.object({
type TLocalRecipient = z.infer<typeof LocalRecipientSchema>;
export const ZEditorRecipientsFormSchema = z.object({
signers: z.array(LocalRecipientSchema),
signingOrder: z.nativeEnum(DocumentSigningOrder),
allowDictateNextSigner: z.boolean().default(false),
});
/**
* Backstop validation that mirrors the CSC-mode UI overrides in
* `EnvelopeEditorProvider`. If anything bypasses the disabled controls (URL
* tampering, legacy form state, embedded host) the form refuses to submit
* rather than persisting values the TSP flow can't honour.
*/
export const ZEditorRecipientsFormSchema = z
.object({
signers: z.array(LocalRecipientSchema),
signingOrder: z.nativeEnum(DocumentSigningOrder),
allowDictateNextSigner: z.boolean().default(false),
})
.superRefine((data, ctx) => {
if (!IS_INSTANCE_CSC_MODE()) {
return;
}
if (data.signingOrder !== DocumentSigningOrder.SEQUENTIAL) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'CSC envelopes must use SEQUENTIAL signing order.',
path: ['signingOrder'],
});
}
if (data.allowDictateNextSigner) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'CSC envelopes do not support next-signer dictation.',
path: ['allowDictateNextSigner'],
});
}
data.signers.forEach((signer, index) => {
if (signer.role === RecipientRole.ASSISTANT) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'CSC envelopes do not support the assistant role.',
path: ['signers', index, 'role'],
});
}
});
});
export type TEditorRecipientsFormSchema = z.infer<typeof ZEditorRecipientsFormSchema>;
@@ -1,3 +1,4 @@
import { IS_INSTANCE_CSC_MODE } from '@documenso/lib/constants/app';
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
import {
DEFAULT_EDITOR_CONFIG,
@@ -36,6 +37,12 @@ type EnvelopeEditorProviderValue = {
isEmbedded: boolean;
isDocument: boolean;
isTemplate: boolean;
/**
* Whether the instance is running in CSC (Cloud Signature Consortium) mode.
* Components can branch on this for any additional CSC-only UI gating
* beyond the overrides already baked into `editorConfig`.
*/
isCscMode: boolean;
setLocalEnvelope: (localEnvelope: Partial<TEditorEnvelope>) => void;
updateEnvelope: (envelopeUpdates: UpdateEnvelopePayload) => void;
@@ -91,7 +98,7 @@ export const useCurrentEnvelopeEditor = () => {
export const EnvelopeEditorProvider = ({
children,
editorConfig = DEFAULT_EDITOR_CONFIG,
editorConfig: providedEditorConfig = DEFAULT_EDITOR_CONFIG,
initialEnvelope,
organisationEmails,
}: EnvelopeEditorProviderProps) => {
@@ -103,6 +110,31 @@ export const EnvelopeEditorProvider = ({
const [envelope, _setEnvelope] = useState(initialEnvelope);
const [autosaveError, setAutosaveError] = useState<boolean>(false);
const isCscMode = IS_INSTANCE_CSC_MODE();
/**
* CSC-mode overrides applied on top of any caller-supplied editor config.
* TSP envelopes are forced SEQUENTIAL at send-time and the sign path has no
* nextSigner dictation; the assistant role's pre-fill semantics don't map
* onto each recipient signing their own complete PDF state. Hide all three
* up-front so authors don't pick options that would get silently coerced.
*/
const editorConfig = useMemo<EnvelopeEditorConfig>(() => {
if (!isCscMode || !providedEditorConfig.recipients) {
return providedEditorConfig;
}
return {
...providedEditorConfig,
recipients: {
...providedEditorConfig.recipients,
allowConfigureSigningOrder: false,
allowConfigureDictateNextSigner: false,
allowAssistantRole: false,
},
};
}, [isCscMode, providedEditorConfig]);
const envelopeRef = useRef(initialEnvelope);
const externalFlushCallbacksRef = useRef<Map<string, () => Promise<void>>>(new Map());
@@ -467,6 +499,7 @@ export const EnvelopeEditorProvider = ({
isEmbedded,
isDocument: envelope.type === EnvelopeType.DOCUMENT,
isTemplate: envelope.type === EnvelopeType.TEMPLATE,
isCscMode,
setLocalEnvelope,
getRecipientColorKey,
updateEnvelope,