From 950735d21498ef9fd2b0ac21ed6d0e007e582ef5 Mon Sep 17 00:00:00 2001 From: Thiago Queiroz Date: Sat, 14 Feb 2026 14:09:12 -0300 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20adiciona=20novo=20queryParam=20com?= =?UTF-8?q?=20valor=20base64=20contendo=20configura=C3=A7=C3=B5es=20de=20b?= =?UTF-8?q?rand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/verify/src/embedded.js | 27 +++++++++++- packages/verify/src/embedded.spec.js | 63 +++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/packages/verify/src/embedded.js b/packages/verify/src/embedded.js index 44da1bd..4f674be 100644 --- a/packages/verify/src/embedded.js +++ b/packages/verify/src/embedded.js @@ -7,6 +7,7 @@ export default class AuthSession { this.key = key; this.listen = {}; this.locale = ''; + this.brand = null; this.endpoint = 'https://app.clicksign.com'; this.origin = `${window.location.protocol}://${window.location.host}`; } @@ -56,8 +57,32 @@ export default class AuthSession { return `${this.endpoint}${this.path}${this.params}`; } + // TODO: Definir nome do método combinando com o nome do query param (linha 81) + get data() { + if (!this.brand) return ''; + + return AuthSession.base64EncodeUrl(JSON.stringify({ brand: this.brand })); + } + + static base64EncodeUrl(value) { + let base64; + + if (typeof btoa === 'function') base64 = btoa(value); + else if (typeof Buffer !== 'undefined') base64 = Buffer.from(value, 'utf-8').toString('base64'); + else throw new Error('No base64 encoder available'); + + return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); + } + get params() { - return `?origin=${this.origin}`; + const query = new URLSearchParams({ origin: this.origin }); + + // TODO: Definir nome do query param. Ex.: settings, payload, data, etc. + if (this.data) query.set('data', this.data); + + const queryToString = query.toString(); + + return queryToString ? `?${queryToString}` : ''; } get path() { diff --git a/packages/verify/src/embedded.spec.js b/packages/verify/src/embedded.spec.js index 43bc552..35e31a5 100644 --- a/packages/verify/src/embedded.spec.js +++ b/packages/verify/src/embedded.spec.js @@ -5,11 +5,21 @@ const sessionKey = 'foobar123'; const endpoint = 'https://example.com'; const originUrl = `${window.location.protocol}://${window.location.host}`; -function getSourceUrl(locale = '') { +function getDataParam(brand = null) { + if (!brand) return ''; + + return AuthSession.base64EncodeUrl(JSON.stringify({ brand })); +} + +function getSourceUrl(locale = '', brand = null) { const prefix = `${endpoint}/verify`; const verifyPath = locale ? `${prefix}/${locale}` : prefix; + const query = new URLSearchParams({ origin: originUrl }); + const data = getDataParam(brand); + + if (data) query.set('data', data); - return `${verifyPath}/sessions/${sessionKey}?origin=${originUrl}`; + return `${verifyPath}/sessions/${sessionKey}?${query.toString()}`; } function createContainerElement() { @@ -27,6 +37,8 @@ describe('AuthSession', () => { instance.endpoint = endpoint; instance.origin = originUrl; + instance.locale = ''; + instance.brand = null; instance.listen = {}; }); @@ -39,6 +51,7 @@ describe('AuthSession', () => { expect(instance.origin).toBe(originUrl); expect(instance.endpoint).toBe(endpoint); expect(instance.locale).toBe(''); + expect(instance.brand).toBeNull(); expect(instance.source).toBe(getSourceUrl()); }); @@ -98,6 +111,52 @@ describe('AuthSession', () => { }); }); + describe('Custom Brand', () => { + it('should initialize brand as null by default', () => { + expect(instance.brand).toBeNull(); + }); + + it('should include brand in data query param in the iframe source URL when brand is set', () => { + const customBrand = { + color1: '#123123', + color2: '#000000', + color3: '#fcfcfc', + }; + + instance.brand = customBrand; + instance.start(containerElementId); + + const iframeElement = document.getElementById(containerElementId).children[0]; + const iframeSrcUrl = new URL(iframeElement.src); + + expect(instance.params).toContain('data='); + expect(instance.source).toBe(getSourceUrl('', customBrand)); + expect(iframeSrcUrl.searchParams.get('data')).toBe(getDataParam(customBrand)); + }); + }); + + describe('Query Params', () => { + it('should include origin query param in the iframe source URL', () => { + instance.start(containerElementId); + + const iframeElement = document.getElementById(containerElementId).children[0]; + const iframeSrcUrl = new URL(iframeElement.src); + + expect(instance.params).toBe(`?${new URLSearchParams({ origin: originUrl }).toString()}`); + expect(iframeSrcUrl.searchParams.get('origin')).toBe(originUrl); + }); + + it('should not include data query param when there is no payload', () => { + instance.start(containerElementId); + + const iframeElement = document.getElementById(containerElementId).children[0]; + const iframeSrcUrl = new URL(iframeElement.src); + + expect(instance.params).not.toContain('data='); + expect(iframeSrcUrl.searchParams.get('data')).toBeNull(); + }); + }); + describe('Events', () => { const eventMock = vi.fn(); const events = ['loaded', 'completed', 'error']; From 93dd08d09df619a83cf0e400d4ac7e068ff28f51 Mon Sep 17 00:00:00 2001 From: Thiago Queiroz Date: Sat, 14 Feb 2026 14:57:18 -0300 Subject: [PATCH 2/3] =?UTF-8?q?refac:=20substitui=20abstra=C3=A7=C3=A3o=20?= =?UTF-8?q?de=20brand=20para=20custom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/verify/src/embedded.js | 6 ++--- packages/verify/src/embedded.spec.js | 35 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/verify/src/embedded.js b/packages/verify/src/embedded.js index 4f674be..cbac5bf 100644 --- a/packages/verify/src/embedded.js +++ b/packages/verify/src/embedded.js @@ -7,7 +7,7 @@ export default class AuthSession { this.key = key; this.listen = {}; this.locale = ''; - this.brand = null; + this.custom = null; this.endpoint = 'https://app.clicksign.com'; this.origin = `${window.location.protocol}://${window.location.host}`; } @@ -59,9 +59,9 @@ export default class AuthSession { // TODO: Definir nome do método combinando com o nome do query param (linha 81) get data() { - if (!this.brand) return ''; + if (!this.custom) return ''; - return AuthSession.base64EncodeUrl(JSON.stringify({ brand: this.brand })); + return AuthSession.base64EncodeUrl(JSON.stringify({ custom: this.custom })); } static base64EncodeUrl(value) { diff --git a/packages/verify/src/embedded.spec.js b/packages/verify/src/embedded.spec.js index c635c5d..f9f5dc5 100644 --- a/packages/verify/src/embedded.spec.js +++ b/packages/verify/src/embedded.spec.js @@ -5,17 +5,17 @@ const sessionKey = 'foobar123'; const endpoint = 'https://example.com'; const originUrl = `${window.location.protocol}://${window.location.host}`; -function getDataParam(brand = null) { - if (!brand) return ''; +function getDataParam(custom = null) { + if (!custom) return ''; - return AuthSession.base64EncodeUrl(JSON.stringify({ brand })); + return AuthSession.base64EncodeUrl(JSON.stringify({ custom })); } -function getSourceUrl(locale = '', brand = null) { +function getSourceUrl(locale = '', custom = null) { const prefix = `${endpoint}/verify`; const verifyPath = locale ? `${prefix}/${locale}` : prefix; const query = new URLSearchParams({ origin: originUrl }); - const data = getDataParam(brand); + const data = getDataParam(custom); if (data) query.set('data', data); @@ -38,7 +38,7 @@ describe('AuthSession', () => { instance.endpoint = endpoint; instance.origin = originUrl; instance.locale = ''; - instance.brand = null; + instance.custom = null; instance.listen = {}; }); @@ -51,7 +51,7 @@ describe('AuthSession', () => { expect(instance.origin).toBe(originUrl); expect(instance.endpoint).toBe(endpoint); expect(instance.locale).toBe(''); - expect(instance.brand).toBeNull(); + expect(instance.custom).toBeNull(); expect(instance.source).toBe(getSourceUrl()); }); @@ -115,27 +115,26 @@ describe('AuthSession', () => { }); }); - describe('Custom Brand', () => { - it('should initialize brand as null by default', () => { - expect(instance.brand).toBeNull(); + describe('Customization', () => { + it('should initialize custom as null by default', () => { + expect(instance.custom).toBeNull(); }); - it('should include brand in data query param in the iframe source URL when brand is set', () => { - const customBrand = { - color1: '#123123', - color2: '#000000', - color3: '#fcfcfc', + it('should include custom colors in data query param in the iframe source URL when custom colors is set', () => { + const customColors = { + buttonTextColor: '#ffffff', + buttonBackgroundColor: '#000000', }; - instance.brand = customBrand; + instance.custom = customColors; instance.start(containerElementId); const iframeElement = document.getElementById(containerElementId).children[0]; const iframeSrcUrl = new URL(iframeElement.src); expect(instance.params).toContain('data='); - expect(instance.source).toBe(getSourceUrl('', customBrand)); - expect(iframeSrcUrl.searchParams.get('data')).toBe(getDataParam(customBrand)); + expect(instance.source).toBe(getSourceUrl('', customColors)); + expect(iframeSrcUrl.searchParams.get('data')).toBe(getDataParam(customColors)); }); }); From 8f395471604c7485a601821eddfc0c8d349a9cc7 Mon Sep 17 00:00:00 2001 From: Thiago Queiroz Date: Sat, 14 Feb 2026 15:21:37 -0300 Subject: [PATCH 3/3] =?UTF-8?q?spec:=20corrige=20cen=C3=A1rios=20de=20cust?= =?UTF-8?q?omiza=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/verify/src/embedded.spec.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/verify/src/embedded.spec.js b/packages/verify/src/embedded.spec.js index f9f5dc5..33bbfeb 100644 --- a/packages/verify/src/embedded.spec.js +++ b/packages/verify/src/embedded.spec.js @@ -121,20 +121,22 @@ describe('AuthSession', () => { }); it('should include custom colors in data query param in the iframe source URL when custom colors is set', () => { - const customColors = { - buttonTextColor: '#ffffff', - buttonBackgroundColor: '#000000', + const custom = { + colors: { + buttonTextColor: '#ffffff', + buttonBackgroundColor: '#000000', + }, }; - instance.custom = customColors; + instance.custom = custom; instance.start(containerElementId); const iframeElement = document.getElementById(containerElementId).children[0]; const iframeSrcUrl = new URL(iframeElement.src); expect(instance.params).toContain('data='); - expect(instance.source).toBe(getSourceUrl('', customColors)); - expect(iframeSrcUrl.searchParams.get('data')).toBe(getDataParam(customColors)); + expect(instance.source).toBe(getSourceUrl('', custom)); + expect(iframeSrcUrl.searchParams.get('data')).toBe(getDataParam(custom)); }); });