@controleonline/ui-common 1.2.104 → 1.2.105

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@controleonline/ui-common",
3
- "version": "1.2.104",
3
+ "version": "1.2.105",
4
4
  "author": "ControleOnline",
5
5
  "description": "ControleOnline Common Quasar UI Component",
6
6
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  import {env as APP_ENV} from '@env';
2
- import {filterApiHeaders} from '../../utils/trustedApiUrl';
2
+ import {filterApiHeaders, isTrustedApiUrl} from '../../utils/trustedApiUrl';
3
3
  import {buildAssetUrl} from '@controleonline/../../src/styles/branding';
4
4
  import {
5
5
  resolveAppDomain,
@@ -79,16 +79,11 @@ const ensureAbsoluteUrl = url => {
79
79
  const resolveDownloadHost = ({company = null, appDomain = ''} = {}) => {
80
80
  const fallbackDomain =
81
81
  normalizeText(appDomain) || resolveAppDomain(APP_ENV?.DOMAIN);
82
- return resolveCompanyDomain(company, fallbackDomain);
82
+ const companyDomain = resolveCompanyDomain(company, fallbackDomain);
83
+ // FileService may return the API authority instead of an application domain.
84
+ return isApiEntrypointHost(companyDomain) ? fallbackDomain : companyDomain;
83
85
  };
84
86
 
85
- /**
86
- * Environment / platform hosts (staging, dev, localhost) are not tenant domains.
87
- * Injecting them into /{host}/files/{id}/download produces URLs like
88
- * https://s.controleonline.com/staging.controleonline.com/files/... → 403.
89
- * Keep app-domain header only; do not path-inject environment hosts.
90
- * app-community#432
91
- */
92
87
  const resolveApiEntrypointHost = () => {
93
88
  const entry = normalizeText(APP_ENV?.API_ENTRYPOINT);
94
89
  if (!entry) {
@@ -216,11 +211,10 @@ const buildTenantDownloadUrl = (url, host) => {
216
211
  return absoluteUrl;
217
212
  }
218
213
 
219
- // Do not path-inject environment/platform hosts (app-community#432).
220
- // Bare /files/{id}/download remains for staging/manager/dev; tenant hosts
221
- // (erp.jaguncos.com.br, loja..., etc.) still get /{appDomain}/files/... .
222
- // Never path-inject the API entrypoint host (app-community#1160).
223
- if (isEnvironmentLikeHost(normalizedHost) || isApiEntrypointHost(normalizedHost)) {
214
+ // Public file routes require the application domain, including registered
215
+ // staging/dev/platform domains. Never use the API authority as that domain.
216
+ if (isApiEntrypointHost(normalizedHost) ||
217
+ !isTrustedApiUrl(absoluteUrl, APP_ENV?.API_ENTRYPOINT)) {
224
218
  return absoluteUrl;
225
219
  }
226
220
 
@@ -377,8 +371,11 @@ const resolveFileSource = (
377
371
  isDownloadLikeUrl(normalizedFile?.uri) ||
378
372
  isDownloadLikeUrl(normalizedFile?.url) ||
379
373
  isDownloadLikeUrl(normalizedFile?.path);
374
+ const rawUrl = normalizedFile.url || normalizedFile.path || normalizedFile.uri;
375
+ // Relative backend paths belong to API_ENTRYPOINT. File.domain selects the
376
+ // route's tenant segment, not a new server origin.
380
377
  const uriBase =
381
- directUrl ||
378
+ (isDownloadLikeUrl(rawUrl) ? rawUrl : directUrl) ||
382
379
  (fileId ? buildBackendDownloadUrl(fileId, {company, appDomain}) : '');
383
380
 
384
381
  if (!uriBase) {
@@ -14,6 +14,28 @@ const {
14
14
  } = require('../../../react/utils/fileUrl');
15
15
 
16
16
  describe('fileUrl helpers', () => {
17
+ it.each([
18
+ 'staging.controleonline.com', 'dev.controleonline.com',
19
+ 'admin.controleonline.com', 'manager.controleonline.com',
20
+ 'pos.lave-go.com', 'shop.lave-go.com', 'delivery.controleonline.com',
21
+ 'crm.controleonline.com', 'ppc.controleonline.com', 'service.controleonline.com',
22
+ 'localhost:8081',
23
+ ])('resolves shared file shapes on the application route for %s', appDomain => {
24
+ for (const file of [6042, '/files/6042', '/files/6042/download',
25
+ {id: 6042, domain: 'api.controleonline.com', url: '/api.controleonline.com/files/6042/download'},
26
+ {file: {id: 6042, url: '/files/6042/download'}}]) {
27
+ const source = resolveDefaultFileSource(file, {appDomain, headers: {'API-TOKEN': 'session'}});
28
+ expect(source.uri).toBe(`https://api.controleonline.com/${encodeURIComponent(appDomain)}/files/6042/download`);
29
+ expect(source.headers).toEqual({'API-TOKEN': 'session', 'app-domain': appDomain});
30
+ }
31
+ });
32
+
33
+ it('preserves URL parameters and fragments while replacing an infrastructure prefix', () => {
34
+ expect(resolveFileImageUrl('/api.controleonline.com/files/6042/download?size=48&app-domain=old#image', {
35
+ appDomain: 'staging.controleonline.com',
36
+ })).toBe('https://api.controleonline.com/staging.controleonline.com/files/6042/download?size=48#image');
37
+ });
38
+
17
39
  it('uses path app-domain for backend download urls and keeps headers', () => {
18
40
  const company = {
19
41
  domain: 'maincompany.controleonline.com',
@@ -108,6 +130,7 @@ describe('file authentication origin boundary', () => {
108
130
  expect(source.headers).not.toHaveProperty('Authorization');
109
131
  expect(source.headers).not.toHaveProperty('App-Domain');
110
132
  expect(source.headers.Accept).toBe('image/*');
133
+ expect(source.uri).toBe(uri);
111
134
  }
112
135
  });
113
136
  it('preserves authentication on the configured API download', () => {