@exdst-sitecore-content-sdk/astro 0.0.16 → 0.0.19
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/README.md +3 -3
- package/package.json +41 -42
- package/src/client/index.ts +1 -1
- package/src/client/sitecore-astro-client.test.ts +41 -20
- package/src/client/sitecore-astro-client.ts +74 -57
- package/src/components/AstroImage.astro +2 -2
- package/src/components/AstroImage.astro.test.ts +542 -0
- package/src/components/Date.astro +5 -1
- package/src/components/Date.astro.test.ts +197 -0
- package/src/components/DefaultEmptyFieldEditingComponentImage.astro +4 -0
- package/src/components/DefaultEmptyFieldEditingComponentText.astro +4 -0
- package/src/components/EditingScripts.astro +2 -2
- package/src/components/EditingScripts.astro.test.ts +267 -0
- package/src/components/ErrorBoundary.astro +8 -9
- package/src/components/ErrorBoundary.astro.test.ts +252 -0
- package/src/components/ErrorComponent.astro +16 -0
- package/src/components/ErrorComponent.astro.test.ts +31 -0
- package/src/components/FieldMetadata.astro +1 -1
- package/src/components/FieldMetadata.astro.test.ts +40 -0
- package/src/components/File.astro +5 -1
- package/src/components/File.astro.test.ts +68 -0
- package/src/components/HiddenRendering.astro.test.ts +36 -0
- package/src/components/Image.astro +18 -4
- package/src/components/Image.astro.test.ts +438 -0
- package/src/components/Link.astro +13 -1
- package/src/components/Link.astro.test.ts +261 -0
- package/src/components/MissingComponent.astro.test.ts +21 -0
- package/src/components/Placeholder/Placeholder.astro +18 -23
- package/src/components/Placeholder/Placeholder.astro.test.ts +1088 -0
- package/src/components/Placeholder/PlaceholderMetadata.astro +24 -18
- package/src/components/Placeholder/PlaceholderMetadata.astro.test.ts +228 -0
- package/src/components/Placeholder/PlaceholderUtils.astro +21 -40
- package/src/components/Placeholder/PlaceholderUtils.astro.test.ts +149 -0
- package/src/components/Placeholder/models.ts +26 -17
- package/src/components/Placeholder/placeholder-utils.test.ts +153 -6
- package/src/components/Placeholder/placeholder-utils.ts +33 -11
- package/src/components/RichText.astro +9 -1
- package/src/components/RichText.astro.test.ts +205 -0
- package/src/components/Text.astro +15 -3
- package/src/components/Text.astro.test.ts +273 -0
- package/src/config/define-config.test.ts +5 -5
- package/src/config/define-config.ts +22 -42
- package/src/config-cli/define-cli-config.test.ts +5 -12
- package/src/config-cli/define-cli-config.ts +4 -8
- package/src/context.ts +42 -11
- package/src/debug.ts +13 -0
- package/src/editing/editing-config-middleware.test.ts +5 -7
- package/src/editing/editing-config-middleware.ts +11 -7
- package/src/editing/editing-render-middleware.test.ts +366 -24
- package/src/editing/editing-render-middleware.ts +34 -12
- package/src/editing/index.ts +2 -0
- package/src/editing/render-middleware.test.ts +1 -1
- package/src/editing/render-middleware.ts +1 -1
- package/src/editing/types.ts +39 -0
- package/src/editing/utils.test.ts +364 -4
- package/src/editing/utils.ts +82 -24
- package/src/enhancers/WithEmptyFieldEditingComponent.astro +1 -1
- package/src/enhancers/WithEmptyFieldEditingComponent.astro.test.ts +380 -0
- package/src/enhancers/WithFieldMetadata.astro.test.ts +113 -0
- package/src/index.ts +10 -7
- package/src/middleware/index.ts +4 -12
- package/src/middleware/middleware.test.ts +13 -0
- package/src/middleware/middleware.ts +12 -3
- package/src/middleware/multisite-middleware.test.ts +45 -50
- package/src/middleware/multisite-middleware.ts +33 -6
- package/src/middleware/robots-middleware.test.ts +20 -4
- package/src/middleware/robots-middleware.ts +10 -3
- package/src/middleware/sitemap-middleware.test.ts +35 -3
- package/src/middleware/sitemap-middleware.ts +7 -6
- package/src/services/component-props-service.ts +7 -6
- package/src/sharedTypes/component-props.ts +15 -4
- package/src/site/index.ts +1 -1
- package/src/tests/astro-helpers.ts +61 -0
- package/src/tests/test-components/CustomErrorComponent.astro +3 -0
- package/src/tests/test-components/CustomHiddenRendering.astro +10 -0
- package/src/tests/test-components/CustomMissingComponent.astro +9 -0
- package/src/tests/test-components/DownloadCallout.astro +12 -0
- package/src/tests/test-components/EmptyFieldEditingComponent.astro +5 -0
- package/src/tests/test-components/ErrorBoundaryWithError.astro +10 -0
- package/src/tests/test-components/Home.astro +12 -0
- package/src/tests/test-components/SxaRichText.astro +23 -0
- package/src/tests/test-components/SxaRichTextDefault.astro +7 -0
- package/src/tests/test-components/SxaRichTextWithTitle.astro +8 -0
- package/src/tests/test-components/TestComponent.astro +9 -0
- package/src/tests/test-components/TestComponentWithError.astro +4 -0
- package/src/tests/test-components/TestComponentWithField.astro +17 -0
- package/src/tests/test-components/TestHeader.astro +8 -0
- package/src/tests/test-components/TestLogo.astro +5 -0
- package/src/tests/test-components/TestParentWrapperComponent.astro +5 -0
- package/src/tests/test-components/TestWrapperComponent.astro +5 -0
- package/src/tests/test-data/metadata-data.ts +86 -0
- package/src/tests/test-data/normal-mode-data.ts +466 -0
- package/src/tests/vitest.setup.ts +4 -0
- package/src/tools/generate-map.ts +4 -3
- package/src/tools/index.ts +2 -4
- package/src/tools/templating/components.test.ts +100 -87
- package/src/tools/templating/components.ts +2 -1
- package/src/tools/templating/default-component.ts +3 -8
- package/src/utils/utils.ts +20 -2
- /package/src/{test-data → tests}/helpers.ts +0 -0
- /package/src/{test-data → tests}/personalizeData.ts +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/Bar.astro +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/Baz.astro +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/Foo.astro +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/Hero.variant.astro +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/NotComponent.bsx +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/Qux.astro +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/folded/Folded.astro +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/folded/random-file-2.docx +0 -0
- /package/src/{test-data/components → tests/test-components/map-components}/random-file.txt +0 -0
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable no-unused-expressions */
|
|
2
2
|
/* eslint-disable dot-notation */
|
|
3
3
|
import * as chai from 'chai';
|
|
4
4
|
import { use } from 'chai';
|
|
5
5
|
import chaiString from 'chai-string';
|
|
6
6
|
import sinonChai from 'sinon-chai';
|
|
7
7
|
import sinon, { spy } from 'sinon';
|
|
8
|
-
import
|
|
8
|
+
import debug from '../debug';
|
|
9
9
|
|
|
10
10
|
import { MultisiteMiddleware } from './multisite-middleware';
|
|
11
|
-
import { SiteInfo, SiteResolver } from '@sitecore-content-sdk/
|
|
11
|
+
import { SiteInfo, SiteResolver } from '@sitecore-content-sdk/content/site';
|
|
12
12
|
import { APIContext, AstroCookieSetOptions } from 'astro';
|
|
13
13
|
|
|
14
14
|
use(sinonChai);
|
|
15
15
|
const expect = chai.use(chaiString).expect;
|
|
16
16
|
|
|
17
17
|
describe('MultisiteMiddleware', () => {
|
|
18
|
-
let debugSpy
|
|
19
|
-
const validateDebugLog = (message: string, ...params: any) =>
|
|
20
|
-
expect(debugSpy.args.find((log) => log[0] === message)).to.deep.equal([
|
|
18
|
+
let debugSpy!: ReturnType<typeof spy>;
|
|
19
|
+
const validateDebugLog = (message: string, ...params: any[]) =>
|
|
20
|
+
expect(debugSpy.args.find((log: any[]) => log[0] === message)).to.deep.equal([
|
|
21
|
+
message,
|
|
22
|
+
...params,
|
|
23
|
+
]);
|
|
21
24
|
const validateEndMessageDebugLog = (message: string, params: any) => {
|
|
22
|
-
const logParams = debugSpy.args.find((log) => log[0] === message) as Array<unknown>;
|
|
25
|
+
const logParams = debugSpy.args.find((log: any[]) => log[0] === message) as Array<unknown>;
|
|
23
26
|
|
|
24
27
|
expect(logParams[2]).to.deep.include(params);
|
|
25
28
|
};
|
|
@@ -47,7 +50,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
47
50
|
return headers[key];
|
|
48
51
|
},
|
|
49
52
|
append(key: string, value: string | Record<string, any>) {
|
|
50
|
-
context.request.headers
|
|
53
|
+
context.request.headers.set(key, value as string);
|
|
51
54
|
},
|
|
52
55
|
...props.headers,
|
|
53
56
|
},
|
|
@@ -62,7 +65,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
62
65
|
value: string | Record<string, any>,
|
|
63
66
|
options?: AstroCookieSetOptions
|
|
64
67
|
) {
|
|
65
|
-
context.cookies
|
|
68
|
+
context.cookies.set(cookieName, value as string, options);
|
|
66
69
|
},
|
|
67
70
|
...props?.cookies,
|
|
68
71
|
...props.cookieValues,
|
|
@@ -98,9 +101,9 @@ describe('MultisiteMiddleware', () => {
|
|
|
98
101
|
|
|
99
102
|
Object.defineProperties(response.headers, {
|
|
100
103
|
forEach: {
|
|
101
|
-
value: (cb) => {
|
|
104
|
+
value: (cb: any) => {
|
|
102
105
|
Object.keys(response.headers).forEach((key) =>
|
|
103
|
-
cb(response.headers
|
|
106
|
+
cb(response.headers.get(key), key, response.headers)
|
|
104
107
|
);
|
|
105
108
|
},
|
|
106
109
|
enumerable: false,
|
|
@@ -276,7 +279,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
276
279
|
rewritePath: '/_site_foobar/styleguide',
|
|
277
280
|
siteName: 'foobar',
|
|
278
281
|
headers: {
|
|
279
|
-
...finalRes.headers,
|
|
282
|
+
...(finalRes as Response).headers,
|
|
280
283
|
'x-sc-rewrite': '/_site_foobar/styleguide',
|
|
281
284
|
},
|
|
282
285
|
cookies: 'sc_site=foobar; HttpOnly; Secure; SameSite=None',
|
|
@@ -315,7 +318,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
315
318
|
rewritePath: '/_site_foobar/styleguide',
|
|
316
319
|
siteName: 'foobar',
|
|
317
320
|
headers: {
|
|
318
|
-
...finalRes.headers,
|
|
321
|
+
...(finalRes as Response).headers,
|
|
319
322
|
'x-sc-rewrite': '/_site_foobar/styleguide',
|
|
320
323
|
},
|
|
321
324
|
cookies: 'sc_site=foobar; HttpOnly; Secure; SameSite=None',
|
|
@@ -356,7 +359,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
356
359
|
rewritePath: '/_site_foo/styleguide',
|
|
357
360
|
siteName: 'foo',
|
|
358
361
|
headers: {
|
|
359
|
-
...finalRes.headers,
|
|
362
|
+
...(finalRes as Response).headers,
|
|
360
363
|
'x-sc-rewrite': '/_site_foo/styleguide',
|
|
361
364
|
},
|
|
362
365
|
cookies: 'sc_site=foo; HttpOnly; Secure; SameSite=None',
|
|
@@ -392,7 +395,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
392
395
|
rewritePath: '/_site_foo/styleguide',
|
|
393
396
|
siteName: 'foo',
|
|
394
397
|
headers: {
|
|
395
|
-
...finalRes.headers,
|
|
398
|
+
...(finalRes as Response).headers,
|
|
396
399
|
'x-sc-rewrite': '/_site_foo/styleguide',
|
|
397
400
|
},
|
|
398
401
|
cookies: 'sc_site=foo; HttpOnly; Secure; SameSite=None',
|
|
@@ -426,7 +429,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
426
429
|
rewritePath: '/_site_foo/styleguide',
|
|
427
430
|
siteName: 'foo',
|
|
428
431
|
headers: {
|
|
429
|
-
...finalRes.headers,
|
|
432
|
+
...(finalRes as Response).headers,
|
|
430
433
|
'x-sc-rewrite': '/_site_foo/styleguide',
|
|
431
434
|
},
|
|
432
435
|
cookies: 'sc_site=foo; HttpOnly; Secure; SameSite=None',
|
|
@@ -460,7 +463,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
460
463
|
rewritePath: '/_site_foo/styleguide',
|
|
461
464
|
siteName: 'foo',
|
|
462
465
|
headers: {
|
|
463
|
-
...finalRes.headers,
|
|
466
|
+
...(finalRes as Response).headers,
|
|
464
467
|
'x-sc-rewrite': '/_site_foo/styleguide',
|
|
465
468
|
},
|
|
466
469
|
cookies: 'sc_site=foo; HttpOnly; Secure; SameSite=None',
|
|
@@ -498,7 +501,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
498
501
|
rewritePath: '/_site_qsFoo/styleguide',
|
|
499
502
|
siteName: 'qsFoo',
|
|
500
503
|
headers: {
|
|
501
|
-
...finalRes.headers,
|
|
504
|
+
...(finalRes as Response).headers,
|
|
502
505
|
'x-sc-rewrite': '/_site_qsFoo/styleguide',
|
|
503
506
|
},
|
|
504
507
|
cookies: 'sc_site=qsFoo; HttpOnly; Secure; SameSite=None',
|
|
@@ -537,7 +540,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
537
540
|
rewritePath: '/_site_qsFoo/styleguide',
|
|
538
541
|
siteName: 'qsFoo',
|
|
539
542
|
headers: {
|
|
540
|
-
...finalRes.headers,
|
|
543
|
+
...(finalRes as Response).headers,
|
|
541
544
|
'x-sc-rewrite': '/_site_qsFoo/styleguide',
|
|
542
545
|
},
|
|
543
546
|
cookies: 'sc_site=qsFoo; HttpOnly; Secure; SameSite=None',
|
|
@@ -576,7 +579,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
576
579
|
rewritePath: '/_site_foobar/styleguide',
|
|
577
580
|
siteName: 'foobar',
|
|
578
581
|
headers: {
|
|
579
|
-
...finalRes.headers,
|
|
582
|
+
...(finalRes as Response).headers,
|
|
580
583
|
'x-sc-rewrite': '/_site_foobar/styleguide',
|
|
581
584
|
},
|
|
582
585
|
cookies: 'sc_site=foobar; HttpOnly; Secure; SameSite=None',
|
|
@@ -613,7 +616,7 @@ describe('MultisiteMiddleware', () => {
|
|
|
613
616
|
rewritePath: '/_site_foo/styleguide',
|
|
614
617
|
siteName: 'foo',
|
|
615
618
|
headers: {
|
|
616
|
-
...finalRes.headers,
|
|
619
|
+
...(finalRes as Response).headers,
|
|
617
620
|
'x-sc-rewrite': '/_site_foo/styleguide',
|
|
618
621
|
},
|
|
619
622
|
cookies: 'sc_site=foo; HttpOnly; Secure; SameSite=None',
|
|
@@ -629,44 +632,36 @@ describe('MultisiteMiddleware', () => {
|
|
|
629
632
|
const context = createContext();
|
|
630
633
|
const res = createResponse();
|
|
631
634
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
before(() => {
|
|
635
|
-
errorSpy = spy(console, 'log');
|
|
636
|
-
});
|
|
637
|
-
|
|
638
|
-
beforeEach(() => {
|
|
639
|
-
errorSpy.resetHistory();
|
|
640
|
-
});
|
|
635
|
+
it('should handle error', async () => {
|
|
636
|
+
const errorSpy = sinon.stub(console, 'log');
|
|
641
637
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
});
|
|
638
|
+
try {
|
|
639
|
+
const error = new Error('Custom error');
|
|
645
640
|
|
|
646
|
-
|
|
647
|
-
|
|
641
|
+
class SampleSiteResolver extends SiteResolver {
|
|
642
|
+
constructor(sites: SiteInfo[]) {
|
|
643
|
+
super(sites);
|
|
644
|
+
}
|
|
648
645
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
646
|
+
getByHost = () => {
|
|
647
|
+
throw error;
|
|
648
|
+
};
|
|
652
649
|
}
|
|
653
650
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
const middleware = new MultisiteMiddleware({ ...defaultConfig });
|
|
660
|
-
middleware['siteResolver'] = new SampleSiteResolver([]);
|
|
651
|
+
const middleware = new MultisiteMiddleware({ ...defaultConfig });
|
|
652
|
+
middleware['siteResolver'] = new SampleSiteResolver([]);
|
|
661
653
|
|
|
662
|
-
|
|
654
|
+
const mockNext = sinon.stub().returns(res);
|
|
663
655
|
|
|
664
|
-
|
|
656
|
+
const finalRes = await middleware.handle(context, mockNext);
|
|
665
657
|
|
|
666
|
-
|
|
667
|
-
|
|
658
|
+
expect(errorSpy.getCall(0).calledWith('Multisite middleware failed:')).to.be.true;
|
|
659
|
+
expect(errorSpy.getCall(1).calledWith(error)).to.be.true;
|
|
668
660
|
|
|
669
|
-
|
|
661
|
+
expect(finalRes).to.deep.equal(res);
|
|
662
|
+
} finally {
|
|
663
|
+
errorSpy.restore();
|
|
664
|
+
}
|
|
670
665
|
});
|
|
671
666
|
});
|
|
672
667
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import { getSiteRewrite, SITE_KEY } from '@sitecore-content-sdk/
|
|
3
|
-
import
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */
|
|
2
|
+
import { getSiteRewrite, SITE_KEY } from '@sitecore-content-sdk/content/site';
|
|
3
|
+
import debug from '../debug';
|
|
4
4
|
import { MiddlewareBase, MiddlewareBaseConfig } from './middleware';
|
|
5
5
|
import { SitecoreConfig } from '../config';
|
|
6
|
-
import { PREVIEW_KEY } from '@sitecore-content-sdk/
|
|
6
|
+
import { PREVIEW_KEY } from '@sitecore-content-sdk/content/editing';
|
|
7
7
|
import { APIContext, MiddlewareHandler, MiddlewareNext } from 'astro';
|
|
8
8
|
import * as cookie from 'cookie';
|
|
9
9
|
|
|
@@ -22,10 +22,15 @@ export type CookieAttributes = {
|
|
|
22
22
|
sameSite?: true | false | 'lax' | 'strict' | 'none' | undefined;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* The interface for the MultisiteMiddleware configuration.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
25
29
|
export type MultisiteMiddlewareConfig = MiddlewareBaseConfig & SitecoreConfig['multisite'];
|
|
26
30
|
|
|
27
31
|
/**
|
|
28
32
|
* Middleware / handler for multisite support
|
|
33
|
+
* @public
|
|
29
34
|
*/
|
|
30
35
|
export class MultisiteMiddleware extends MiddlewareBase {
|
|
31
36
|
/**
|
|
@@ -66,8 +71,12 @@ export class MultisiteMiddleware extends MiddlewareBase {
|
|
|
66
71
|
|
|
67
72
|
if (!isSitecorePreview) {
|
|
68
73
|
if (!this.config.enabled) {
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
this.shouldWarnWhenDisabled(context);
|
|
75
|
+
|
|
76
|
+
if (this.shouldSkipWhenDisabled()) {
|
|
77
|
+
debug.multisite('skipped (multisite middleware is disabled globally)');
|
|
78
|
+
return next();
|
|
79
|
+
}
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
if (this.disabled(context)) {
|
|
@@ -133,6 +142,24 @@ export class MultisiteMiddleware extends MiddlewareBase {
|
|
|
133
142
|
return context.url.pathname.includes('.') || super.disabled(context);
|
|
134
143
|
}
|
|
135
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Called when multisite is disabled. Override this method in subclasses to show router-specific warnings.
|
|
147
|
+
* @param {APIContext} context context
|
|
148
|
+
*/
|
|
149
|
+
protected shouldWarnWhenDisabled(context: APIContext): void {
|
|
150
|
+
void context;
|
|
151
|
+
// Base implementation does nothing - subclasses can override to show warnings
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Determines if middleware should be skipped when multisite is disabled.
|
|
156
|
+
* Override in subclasses to provide router-specific behavior.
|
|
157
|
+
* @returns {boolean} true if middleware should be skipped when disabled
|
|
158
|
+
*/
|
|
159
|
+
protected shouldSkipWhenDisabled(): boolean {
|
|
160
|
+
return true; // Base class skips when disabled
|
|
161
|
+
}
|
|
162
|
+
|
|
136
163
|
/**
|
|
137
164
|
* Generates a site-specific rewrite path based on the provided pathname and site name.
|
|
138
165
|
* @param {string} pathname - The pathname to be rewritten.
|
|
@@ -3,9 +3,12 @@ import { expect } from 'chai';
|
|
|
3
3
|
import sinon from 'sinon';
|
|
4
4
|
import sinonChai from 'sinon-chai';
|
|
5
5
|
import { RobotsMiddleware } from './robots-middleware';
|
|
6
|
-
import { SitecoreClient } from '@sitecore-content-sdk/
|
|
7
|
-
import { SiteInfo } from '@sitecore-content-sdk/
|
|
8
|
-
import { mockRequest } from '../
|
|
6
|
+
import { SitecoreClient } from '@sitecore-content-sdk/content/client';
|
|
7
|
+
import { SiteInfo } from '@sitecore-content-sdk/content/site';
|
|
8
|
+
import { mockRequest } from '../tests/helpers';
|
|
9
|
+
import { constants } from '@sitecore-content-sdk/core';
|
|
10
|
+
|
|
11
|
+
const { ERROR_MESSAGES } = constants;
|
|
9
12
|
|
|
10
13
|
chai.use(sinonChai);
|
|
11
14
|
|
|
@@ -94,7 +97,7 @@ describe('RobotsMiddleware', () => {
|
|
|
94
97
|
|
|
95
98
|
const body = await res.text();
|
|
96
99
|
expect(res.status).to.equal(500);
|
|
97
|
-
expect(body).to.deep.equal(
|
|
100
|
+
expect(body).to.deep.equal(`Internal Server Error. ${ERROR_MESSAGES.CONTACT_SUPPORT}`);
|
|
98
101
|
});
|
|
99
102
|
|
|
100
103
|
it('should use "localhost" as fallback when host header is missing', async () => {
|
|
@@ -110,4 +113,17 @@ describe('RobotsMiddleware', () => {
|
|
|
110
113
|
expect(res.status).to.equal(200);
|
|
111
114
|
expect(body).to.deep.equal('User-agent: *\nDisallow: /');
|
|
112
115
|
});
|
|
116
|
+
|
|
117
|
+
it('should use x-forwarded-host header when present', async () => {
|
|
118
|
+
req = mockRequest({
|
|
119
|
+
headers: {
|
|
120
|
+
'x-forwarded-host': 'proxy.forwarded.com',
|
|
121
|
+
host: 'localhost:3000',
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await middleware.getHandler()(req as Request);
|
|
126
|
+
|
|
127
|
+
expect(siteResolverStub.getByHost).to.have.been.calledWith('proxy.forwarded.com');
|
|
128
|
+
});
|
|
113
129
|
});
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { SitecoreClient } from '@sitecore-content-sdk/
|
|
1
|
+
import { SitecoreClient } from '@sitecore-content-sdk/content/client';
|
|
2
|
+
import { constants } from '@sitecore-content-sdk/core';
|
|
2
3
|
import { SiteInfo, SiteResolver } from '../site';
|
|
3
4
|
|
|
5
|
+
const { ERROR_MESSAGES } = constants;
|
|
6
|
+
|
|
4
7
|
/**
|
|
5
8
|
* Middleware for handling robots.txt requests.
|
|
9
|
+
* @public
|
|
6
10
|
*/
|
|
7
11
|
export class RobotsMiddleware {
|
|
8
12
|
private client: SitecoreClient;
|
|
@@ -21,7 +25,10 @@ export class RobotsMiddleware {
|
|
|
21
25
|
const _res = new Response();
|
|
22
26
|
_res.headers.append('content-type', 'text/plain');
|
|
23
27
|
|
|
24
|
-
const hostName =
|
|
28
|
+
const hostName =
|
|
29
|
+
_req.headers.get('x-forwarded-host') ||
|
|
30
|
+
_req.headers.get('host')?.split(':')[0] ||
|
|
31
|
+
'localhost';
|
|
25
32
|
const site = this.siteResolver.getByHost(hostName);
|
|
26
33
|
|
|
27
34
|
try {
|
|
@@ -38,7 +45,7 @@ export class RobotsMiddleware {
|
|
|
38
45
|
headers: _res.headers,
|
|
39
46
|
});
|
|
40
47
|
} catch {
|
|
41
|
-
return new Response(
|
|
48
|
+
return new Response(`Internal Server Error. ${ERROR_MESSAGES.CONTACT_SUPPORT}`, {
|
|
42
49
|
status: 500,
|
|
43
50
|
headers: _res.headers,
|
|
44
51
|
});
|
|
@@ -4,8 +4,11 @@ import { expect } from 'chai';
|
|
|
4
4
|
import sinon from 'sinon';
|
|
5
5
|
import sinonChai from 'sinon-chai';
|
|
6
6
|
import { SitemapMiddleware } from './sitemap-middleware';
|
|
7
|
-
import { SitecoreClient } from '@sitecore-content-sdk/
|
|
8
|
-
import {
|
|
7
|
+
import { SitecoreClient } from '@sitecore-content-sdk/content/client';
|
|
8
|
+
import { constants } from '@sitecore-content-sdk/core';
|
|
9
|
+
import { mockRequest } from '../tests/helpers';
|
|
10
|
+
|
|
11
|
+
const { ERROR_MESSAGES } = constants;
|
|
9
12
|
|
|
10
13
|
chai.use(sinonChai);
|
|
11
14
|
|
|
@@ -123,6 +126,35 @@ describe('SitemapMiddleware', () => {
|
|
|
123
126
|
});
|
|
124
127
|
});
|
|
125
128
|
|
|
129
|
+
it('should use x-forwarded-host header when present', async () => {
|
|
130
|
+
req = mockRequest({
|
|
131
|
+
headers: {
|
|
132
|
+
'x-forwarded-host': 'example.com',
|
|
133
|
+
host: 'localhost:3000',
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await middleware.getHandler()(req as Request);
|
|
138
|
+
|
|
139
|
+
expect(siteResolverStub.getByHost).to.have.been.calledWith('example.com');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should use empty string when both x-forwarded-host and host headers are missing', async () => {
|
|
143
|
+
req.headers?.delete('host');
|
|
144
|
+
const xmlContent = '<sitemapindex>...</sitemapindex>';
|
|
145
|
+
|
|
146
|
+
siteResolverStub.getByHost.withArgs('').returns(sites[1]);
|
|
147
|
+
|
|
148
|
+
sitecoreClientStub.getSiteMap.resolves(xmlContent);
|
|
149
|
+
|
|
150
|
+
await middleware.getHandler()(req as Request);
|
|
151
|
+
|
|
152
|
+
expect(sitecoreClientStub.getSiteMap.firstCall.args[0]).to.deep.include({
|
|
153
|
+
reqHost: '',
|
|
154
|
+
reqProtocol: 'https',
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
126
158
|
it('should redirect to 404 when REDIRECT_404 error is thrown', async () => {
|
|
127
159
|
const error = new Error('REDIRECT_404');
|
|
128
160
|
|
|
@@ -146,7 +178,7 @@ describe('SitemapMiddleware', () => {
|
|
|
146
178
|
|
|
147
179
|
const body = await res.text();
|
|
148
180
|
expect(res.status).to.equal(500);
|
|
149
|
-
expect(body).to.equal(
|
|
181
|
+
expect(body).to.equal(`Internal Server Error. ${ERROR_MESSAGES.CONTACT_SUPPORT}`);
|
|
150
182
|
});
|
|
151
183
|
});
|
|
152
184
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
SitemapXmlOptions,
|
|
4
|
-
} from '@sitecore-content-sdk/core/client';
|
|
1
|
+
import { SitecoreClient, SitemapXmlOptions } from '@sitecore-content-sdk/content/client';
|
|
2
|
+
import { constants } from '@sitecore-content-sdk/core';
|
|
5
3
|
import { SiteInfo, SiteResolver } from '../site';
|
|
6
4
|
|
|
5
|
+
const { ERROR_MESSAGES } = constants;
|
|
6
|
+
|
|
7
7
|
/**
|
|
8
8
|
* Middleware for handling sitemap requests.
|
|
9
9
|
* Encapsulates all HTTP-related logic for sitemap generation and delivery.
|
|
10
|
+
* @public
|
|
10
11
|
*/
|
|
11
12
|
export class SitemapMiddleware {
|
|
12
13
|
private client: SitecoreClient;
|
|
@@ -28,7 +29,7 @@ export class SitemapMiddleware {
|
|
|
28
29
|
const idMatch = segments[1].match(/(\d+)(?=\.xml$)/);
|
|
29
30
|
const id = idMatch ? idMatch[1] : '';
|
|
30
31
|
|
|
31
|
-
const reqHost = _req.headers.get('host') || '';
|
|
32
|
+
const reqHost = _req.headers.get('x-forwarded-host') || _req.headers.get('host') || '';
|
|
32
33
|
const reqProtocol = _req.headers.get('x-forwarded-proto') || 'https';
|
|
33
34
|
const site = this.siteResolver.getByHost(reqHost);
|
|
34
35
|
|
|
@@ -56,7 +57,7 @@ export class SitemapMiddleware {
|
|
|
56
57
|
},
|
|
57
58
|
});
|
|
58
59
|
} else {
|
|
59
|
-
return new Response(
|
|
60
|
+
return new Response(`Internal Server Error. ${ERROR_MESSAGES.CONTACT_SUPPORT}`, {
|
|
60
61
|
status: 500,
|
|
61
62
|
});
|
|
62
63
|
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
LayoutServiceData,
|
|
4
4
|
ComponentRendering,
|
|
5
5
|
PlaceholdersData,
|
|
6
|
-
} from '@sitecore-content-sdk/
|
|
6
|
+
} from '@sitecore-content-sdk/content/layout';
|
|
7
7
|
import {
|
|
8
8
|
AstroContentSdkComponent,
|
|
9
9
|
ComponentMap,
|
|
@@ -23,6 +23,10 @@ export type ComponentPropsRequest = {
|
|
|
23
23
|
// context: NextContext;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* The service for fetching component props.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
26
30
|
export class ComponentPropsService {
|
|
27
31
|
async fetchComponentProps(
|
|
28
32
|
params: FetchComponentPropsArguments
|
|
@@ -67,7 +71,7 @@ export class ComponentPropsService {
|
|
|
67
71
|
// const fetchFunc = (await this.getModule(components, r.componentName))
|
|
68
72
|
// ?.getComponentServerProps;
|
|
69
73
|
|
|
70
|
-
const fetchFunc =
|
|
74
|
+
const fetchFunc = ''; // getModule
|
|
71
75
|
|
|
72
76
|
if (fetchFunc) {
|
|
73
77
|
params.requests &&
|
|
@@ -113,7 +117,6 @@ export class ComponentPropsService {
|
|
|
113
117
|
return;
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
|
|
117
120
|
// return req
|
|
118
121
|
// .fetch(req.rendering, req.layoutData /*, req.context*/)
|
|
119
122
|
// .then((result) => {
|
|
@@ -153,9 +156,7 @@ export class ComponentPropsService {
|
|
|
153
156
|
* @param {PlaceholdersData} placeholders placeholders
|
|
154
157
|
* @returns {ComponentRendering[]} renderings
|
|
155
158
|
*/
|
|
156
|
-
protected flatRenderings(
|
|
157
|
-
placeholders: PlaceholdersData
|
|
158
|
-
): ComponentRendering[] {
|
|
159
|
+
protected flatRenderings(placeholders: PlaceholdersData): ComponentRendering[] {
|
|
159
160
|
const allComponentRenderings: ComponentRendering[] = [];
|
|
160
161
|
const placeholdersArr = Object.values(placeholders);
|
|
161
162
|
|
|
@@ -2,16 +2,27 @@ export type ComponentPropsError = { error: string; componentName: string };
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Shape of component props storage
|
|
5
|
+
* @public
|
|
5
6
|
*/
|
|
6
7
|
export type ComponentPropsCollection = {
|
|
7
8
|
[componentUid: string]: unknown | ComponentPropsError;
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Represents an Astro component import
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
10
15
|
export type AstroContentSdkComponent = (_props: Record<string, any>) => any;
|
|
11
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Represents PreviewData type
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
12
21
|
export type PreviewData = string | false | object | undefined;
|
|
13
22
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Represents component map type
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export type ComponentMap<TComponent extends AstroContentSdkComponent = AstroContentSdkComponent> =
|
|
28
|
+
Map<string, TComponent>;
|
package/src/site/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { SiteResolver, SiteInfo } from '@sitecore-content-sdk/
|
|
1
|
+
export { SiteResolver, SiteInfo, SITE_PREFIX } from '@sitecore-content-sdk/content/site';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ComponentProps } from 'astro/types';
|
|
2
|
+
import {
|
|
3
|
+
experimental_AstroContainer as AstroContainer,
|
|
4
|
+
type ContainerRenderOptions,
|
|
5
|
+
} from 'astro/container';
|
|
6
|
+
import { Page } from '@sitecore-content-sdk/content/client';
|
|
7
|
+
import { ComponentMap } from '../sharedTypes/component-props';
|
|
8
|
+
import { vi } from 'vitest';
|
|
9
|
+
import { SitecoreContext } from '../context';
|
|
10
|
+
|
|
11
|
+
type AstroComponentFactory = Parameters<AstroContainer['renderToString']>[0];
|
|
12
|
+
|
|
13
|
+
type ComponentContainerRenderOptions<T extends AstroComponentFactory> = Omit<
|
|
14
|
+
ContainerRenderOptions,
|
|
15
|
+
'props'
|
|
16
|
+
> & {
|
|
17
|
+
// @ts-expect-error
|
|
18
|
+
props?: ComponentProps<T>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Renders an Astro component to a DOM element for tests.
|
|
23
|
+
* @param {AstroComponentFactory} Component - The Astro component to render.
|
|
24
|
+
* @param {ComponentContainerRenderOptions<T>} options - Container render options, including component props.
|
|
25
|
+
* @returns A `div` whose `innerHTML` is the rendered markup (Astro attributes stripped).
|
|
26
|
+
*/
|
|
27
|
+
export async function renderAstroComponent<T extends AstroComponentFactory>(
|
|
28
|
+
Component: T,
|
|
29
|
+
options: ComponentContainerRenderOptions<T> = {}
|
|
30
|
+
) {
|
|
31
|
+
const container = await AstroContainer.create();
|
|
32
|
+
const result = await container.renderToString(Component, options);
|
|
33
|
+
|
|
34
|
+
const html = removeAstroAttributes(result);
|
|
35
|
+
|
|
36
|
+
const div = document.createElement('div');
|
|
37
|
+
div.innerHTML = html;
|
|
38
|
+
|
|
39
|
+
return div;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const mockSitecoreContext = (page?: Page, map?: ComponentMap, api?: any) => {
|
|
43
|
+
const getMock = vi.fn();
|
|
44
|
+
|
|
45
|
+
getMock.mockReturnValue({
|
|
46
|
+
page: page,
|
|
47
|
+
componentMap: map,
|
|
48
|
+
api: api,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
SitecoreContext.get = getMock;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Removes Astro-specific data attributes (data-astro-*)
|
|
56
|
+
* and whitespaces between HTML tags from a given HTML string.
|
|
57
|
+
* @param {string} html - Raw HTML string from Astro rendering.
|
|
58
|
+
*/
|
|
59
|
+
const removeAstroAttributes = (html: string) => {
|
|
60
|
+
return html.replace(/\s*data-astro-[a-zA-Z0-9-]+=(\"|\').*?\1\s*/g, '').replace(/>\s+</g, '><');
|
|
61
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
const props = Astro.props as {
|
|
3
|
+
[prop: string]: unknown;
|
|
4
|
+
fields?: { message?: { value?: string } };
|
|
5
|
+
extraDiv?: boolean;
|
|
6
|
+
};
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<div class="download-callout-mock">
|
|
10
|
+
{props.fields?.message ? props.fields.message.value : ''}
|
|
11
|
+
{props.extraDiv ? <div class="extra">extra!</div> : null}
|
|
12
|
+
</div>
|