From 85182da39f6718dc530c55029ea2f9de5bb85b50 Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Wed, 21 Oct 2026 15:46:25 +1100 Subject: [PATCH] feat: add clientUserId support --- packages/angular/src/sign-document.ts | 13 ++++++++++ packages/mitosis/src/sign-document.lite.tsx | 13 ++++++++++ packages/preact/src/sign-document.tsx | 12 +++++++++ packages/react/src/sign-document.tsx | 12 +++++++++ packages/solid/src/sign-document.tsx | 12 +++++++++ packages/svelte/src/sign-document.svelte | 13 ++++++++++ packages/vue/src/sign-document.vue | 12 +++++++++ packages/webcomponent/src/index.ts | 1 + .../components/embeddings/sign-document.tsx | 26 +++++++++++++++++++ 9 files changed, 114 insertions(+) diff --git a/packages/angular/src/sign-document.ts b/packages/angular/src/sign-document.ts index c1e8b51..c74c290 100644 --- a/packages/angular/src/sign-document.ts +++ b/packages/angular/src/sign-document.ts @@ -8,6 +8,15 @@ export type EmbedSignDocumentProps = { host?: string; token: string; + /** + * Opaque identifier for the signer, used to prefill and persist their signature + * across embeds (Platform Plan). + * + * Sent as a URL query parameter, so it will appear in request logs. Never pass an + * email address or other personally identifiable information here. + */ + clientUserId?: string | undefined; + // @src: /apps/web/src/app/embed/direct/[[...url]]/schema css?: string | undefined; cssVars?: (CssVars & Record) | undefined; @@ -73,6 +82,7 @@ export default class EmbedSignDocument { allowDocumentRejection!: EmbedSignDocumentProps["allowDocumentRejection"]; @Input() additionalProps!: EmbedSignDocumentProps["additionalProps"]; @Input() token!: EmbedSignDocumentProps["token"]; + @Input() clientUserId!: EmbedSignDocumentProps["clientUserId"]; @Input() onDocumentReady!: EmbedSignDocumentProps["onDocumentReady"]; @Input() onDocumentCompleted!: EmbedSignDocumentProps["onDocumentCompleted"]; @Input() onDocumentError!: EmbedSignDocumentProps["onDocumentError"]; @@ -100,6 +110,9 @@ export default class EmbedSignDocument { ) ); const srcUrl = new URL(`/embed/sign/${this.token}`, appHost); + if (this.clientUserId) { + srcUrl.searchParams.set("clientUserId", this.clientUserId); + } return `${srcUrl}#${encodedOptions}`; } get sandbox() { diff --git a/packages/mitosis/src/sign-document.lite.tsx b/packages/mitosis/src/sign-document.lite.tsx index b1c139b..e285b46 100644 --- a/packages/mitosis/src/sign-document.lite.tsx +++ b/packages/mitosis/src/sign-document.lite.tsx @@ -7,6 +7,15 @@ export type EmbedSignDocumentProps = { host?: string; token: string; + /** + * Opaque identifier for the signer, used to prefill and persist their signature + * across embeds (Platform Plan). + * + * Sent as a URL query parameter, so it will appear in request logs. Never pass an + * email address or other personally identifiable information here. + */ + clientUserId?: string | undefined; + // @src: /apps/web/src/app/embed/direct/[[...url]]/schema css?: string | undefined; cssVars?: (CssVars & Record) | undefined; @@ -62,6 +71,10 @@ export default function EmbedSignDocument(props: EmbedSignDocumentProps) { const srcUrl = new URL(`/embed/sign/${props.token}`, appHost); + if (props.clientUserId) { + srcUrl.searchParams.set('clientUserId', props.clientUserId); + } + return `${srcUrl}#${encodedOptions}`; }, diff --git a/packages/preact/src/sign-document.tsx b/packages/preact/src/sign-document.tsx index b185a5a..4cddf34 100644 --- a/packages/preact/src/sign-document.tsx +++ b/packages/preact/src/sign-document.tsx @@ -7,6 +7,15 @@ export type EmbedSignDocumentProps = { host?: string; token: string; + /** + * Opaque identifier for the signer, used to prefill and persist their signature + * across embeds (Platform Plan). + * + * Sent as a URL query parameter, so it will appear in request logs. Never pass an + * email address or other personally identifiable information here. + */ + clientUserId?: string | undefined; + // @src: /apps/web/src/app/embed/direct/[[...url]]/schema css?: string | undefined; cssVars?: (CssVars & Record) | undefined; @@ -58,6 +67,9 @@ function EmbedSignDocument(props: EmbedSignDocumentProps) { ) ); const srcUrl = new URL(`/embed/sign/${props.token}`, appHost); + if (props.clientUserId) { + srcUrl.searchParams.set("clientUserId", props.clientUserId); + } return `${srcUrl}#${encodedOptions}`; } diff --git a/packages/react/src/sign-document.tsx b/packages/react/src/sign-document.tsx index 1b6fdf8..7327ff0 100644 --- a/packages/react/src/sign-document.tsx +++ b/packages/react/src/sign-document.tsx @@ -7,6 +7,15 @@ export type EmbedSignDocumentProps = { host?: string; token: string; + /** + * Opaque identifier for the signer, used to prefill and persist their signature + * across embeds (Platform Plan). + * + * Sent as a URL query parameter, so it will appear in request logs. Never pass an + * email address or other personally identifiable information here. + */ + clientUserId?: string | undefined; + // @src: /apps/web/src/app/embed/direct/[[...url]]/schema css?: string | undefined; cssVars?: (CssVars & Record) | undefined; @@ -58,6 +67,9 @@ function EmbedSignDocument(props: EmbedSignDocumentProps) { ) ); const srcUrl = new URL(`/embed/sign/${props.token}`, appHost); + if (props.clientUserId) { + srcUrl.searchParams.set("clientUserId", props.clientUserId); + } return `${srcUrl}#${encodedOptions}`; } diff --git a/packages/solid/src/sign-document.tsx b/packages/solid/src/sign-document.tsx index 5fbdc37..7731831 100644 --- a/packages/solid/src/sign-document.tsx +++ b/packages/solid/src/sign-document.tsx @@ -5,6 +5,15 @@ export type EmbedSignDocumentProps = { host?: string; token: string; + /** + * Opaque identifier for the signer, used to prefill and persist their signature + * across embeds (Platform Plan). + * + * Sent as a URL query parameter, so it will appear in request logs. Never pass an + * email address or other personally identifiable information here. + */ + clientUserId?: string | undefined; + // @src: /apps/web/src/app/embed/direct/[[...url]]/schema css?: string | undefined; cssVars?: (CssVars & Record) | undefined; @@ -56,6 +65,9 @@ function EmbedSignDocument(props: EmbedSignDocumentProps) { ) ); const srcUrl = new URL(`/embed/sign/${props.token}`, appHost); + if (props.clientUserId) { + srcUrl.searchParams.set("clientUserId", props.clientUserId); + } return `${srcUrl}#${encodedOptions}`; }); diff --git a/packages/svelte/src/sign-document.svelte b/packages/svelte/src/sign-document.svelte index b294ef2..965b6f1 100644 --- a/packages/svelte/src/sign-document.svelte +++ b/packages/svelte/src/sign-document.svelte @@ -4,6 +4,15 @@ host?: string; token: string; + /** + * Opaque identifier for the signer, used to prefill and persist their signature + * across embeds (Platform Plan). + * + * Sent as a URL query parameter, so it will appear in request logs. Never pass an + * email address or other personally identifiable information here. + */ + clientUserId?: string | undefined; + // @src: /apps/web/src/app/embed/direct/[[...url]]/schema css?: string | undefined; cssVars?: (CssVars & Record) | undefined; @@ -54,6 +63,7 @@ export let additionalProps: EmbedSignDocumentProps["additionalProps"] = undefined; export let token: EmbedSignDocumentProps["token"]; + export let clientUserId: EmbedSignDocumentProps["clientUserId"] = undefined; export let onDocumentReady: EmbedSignDocumentProps["onDocumentReady"] = undefined; export let onDocumentCompleted: EmbedSignDocumentProps["onDocumentCompleted"] = @@ -101,6 +111,9 @@ ) ); const srcUrl = new URL(`/embed/sign/${token}`, appHost); + if (clientUserId) { + srcUrl.searchParams.set("clientUserId", clientUserId); + } return `${srcUrl}#${encodedOptions}`; }; $: sandbox = () => { diff --git a/packages/vue/src/sign-document.vue b/packages/vue/src/sign-document.vue index b9d2334..49fe010 100644 --- a/packages/vue/src/sign-document.vue +++ b/packages/vue/src/sign-document.vue @@ -17,6 +17,15 @@ export type EmbedSignDocumentProps = { host?: string; token: string; + /** + * Opaque identifier for the signer, used to prefill and persist their signature + * across embeds (Platform Plan). + * + * Sent as a URL query parameter, so it will appear in request logs. Never pass an + * email address or other personally identifiable information here. + */ + clientUserId?: string | undefined; + // @src: /apps/web/src/app/embed/direct/[[...url]]/schema css?: string | undefined; cssVars?: (CssVars & Record) | undefined; @@ -75,6 +84,9 @@ const src = computed(() => { ) ); const srcUrl = new URL(`/embed/sign/${props.token}`, appHost); + if (props.clientUserId) { + srcUrl.searchParams.set("clientUserId", props.clientUserId); + } return `${srcUrl}#${encodedOptions}`; }); const sandbox = computed(() => { diff --git a/packages/webcomponent/src/index.ts b/packages/webcomponent/src/index.ts index bd9d47e..faad653 100644 --- a/packages/webcomponent/src/index.ts +++ b/packages/webcomponent/src/index.ts @@ -19,6 +19,7 @@ register(EmbedDirectTemplate, 'documenso-embed-direct-template', [ register(EmbedSignDocument, 'documenso-embed-sign-document', [ 'token', 'host', + 'clientUserId', 'css', 'name', 'lockName', diff --git a/playground/src/components/embeddings/sign-document.tsx b/playground/src/components/embeddings/sign-document.tsx index dfbd3d6..a7cc0e1 100644 --- a/playground/src/components/embeddings/sign-document.tsx +++ b/playground/src/components/embeddings/sign-document.tsx @@ -23,6 +23,7 @@ import { EmbedSignDocument } from '@documenso/embed-react'; const formSchema = z.object({ token: z.string().min(1, 'Signing token is required'), + clientUserId: z.string().optional(), email: z.string().email('Must be a valid email').optional().or(z.literal('')), lockEmail: z.boolean().optional(), name: z.string().optional(), @@ -46,6 +47,7 @@ export default function SignDocumentEmbedding() { resolver: zodResolver(formSchema), defaultValues: { token: '', + clientUserId: '', email: '', lockEmail: false, name: '', @@ -105,6 +107,29 @@ export default function SignDocumentEmbedding() { )} /> + ( + + Client User ID (Optional) + + + + + Opaque identifier used to prefill and persist the signer's signature across + embeds (Platform Plan). Sent as a query param, so never use an email or other + PII. + + + + )} + /> +