diff --git a/src/facade/contentFetcherFacade.ts b/src/facade/contentFetcherFacade.ts
index 075652f7..6d1a7834 100644
--- a/src/facade/contentFetcherFacade.ts
+++ b/src/facade/contentFetcherFacade.ts
@@ -21,7 +21,11 @@ function validate(options: unknown): asserts options is FetchOptions {
}
}
-export type Configuration = {
+type Options = {
+ preferredLocale?: string,
+};
+
+export type Configuration = Options & {
contentFetcher: ContentFetcher,
contextFactory: ContextFactory,
previewTokenProvider: TokenProvider,
@@ -40,12 +44,17 @@ export class ContentFetcherFacade {
private readonly cidAssigner: CidAssigner;
+ private readonly options: Options;
+
public constructor(configuration: Configuration) {
this.fetcher = configuration.contentFetcher;
this.previewTokenProvider = configuration.previewTokenProvider;
this.userTokenProvider = configuration.userTokenProvider;
this.cidAssigner = configuration.cidAssigner;
this.contextFactory = configuration.contextFactory;
+ this.options = {
+ preferredLocale: configuration.preferredLocale,
+ };
}
public async fetch
(slotId: string, options: FetchOptions = {}): Promise> {
@@ -61,9 +70,9 @@ export class ContentFetcherFacade {
userToken: this.userTokenProvider.getToken() ?? undefined,
previewToken: this.previewTokenProvider.getToken() ?? undefined,
version: options.version,
- preferredLocale: options.preferredLocale,
context: this.contextFactory.createContext(options.attributes),
timeout: options.timeout,
+ preferredLocale: options.preferredLocale ?? this.options.preferredLocale,
});
}
}
diff --git a/src/facade/sdkFacade.ts b/src/facade/sdkFacade.ts
index 009c1312..e260e5fc 100644
--- a/src/facade/sdkFacade.ts
+++ b/src/facade/sdkFacade.ts
@@ -15,7 +15,11 @@ import {PartialTrackingEvent} from '../trackingEvents';
import {UrlSanitizer} from '../tab';
import {ContentFetcherFacade} from './contentFetcherFacade';
-export type Configuration = {
+type Options = {
+ preferredLocale?: string,
+};
+
+export type Configuration = Options & {
appId: string,
tokenScope?: TokenScope,
debug?: boolean,
@@ -53,14 +57,17 @@ export class SdkFacade {
private contentFetcherFacade?: ContentFetcherFacade;
- private constructor(sdk: Sdk) {
+ private readonly options: Options;
+
+ private constructor(sdk: Sdk, options: Options = {}) {
this.sdk = sdk;
+ this.options = options;
}
public static init(configuration: Configuration): SdkFacade {
validateConfiguration(configuration);
- const {track = true, userId, token, ...containerConfiguration} = configuration;
+ const {track = true, userId, token, preferredLocale, ...containerConfiguration} = configuration;
if (userId !== undefined && token !== undefined) {
throw new Error('Either the user ID or token can be specified, but not both.');
@@ -74,6 +81,9 @@ export class SdkFacade {
test: containerConfiguration.test ?? false,
disableCidMirroring: containerConfiguration.disableCidMirroring ?? false,
}),
+ {
+ preferredLocale: preferredLocale,
+ },
);
if (userId !== undefined) {
@@ -166,6 +176,7 @@ export class SdkFacade {
cidAssigner: this.sdk.cidAssigner,
previewTokenProvider: this.sdk.previewTokenStore,
userTokenProvider: this.sdk.userTokenStore,
+ preferredLocale: this.options.preferredLocale,
});
}
diff --git a/src/schema/sdkFacadeSchemas.ts b/src/schema/sdkFacadeSchemas.ts
index 130430ff..13bc5dd5 100644
--- a/src/schema/sdkFacadeSchemas.ts
+++ b/src/schema/sdkFacadeSchemas.ts
@@ -38,5 +38,8 @@ export const sdkFacadeConfigurationSchema = new ObjectType({
cidAssignerEndpointUrl: new StringType({
format: 'url',
}),
+ preferredLocale: new StringType({
+ pattern: /^[a-z]{2,3}([-_][a-z]{2,3})?$/i,
+ }),
},
});
diff --git a/test/facade/contentFecherFacade.test.ts b/test/facade/contentFecherFacade.test.ts
index eea66eb9..0de8da2a 100644
--- a/test/facade/contentFecherFacade.test.ts
+++ b/test/facade/contentFecherFacade.test.ts
@@ -94,12 +94,13 @@ describe('A content fetcher facade', () => {
const userToken = Token.issue('00000000-0000-0000-0000-000000000000', 'foo', Date.now());
const previewToken = Token.issue('11111111-1111-1111-1111-111111111111', 'bar', Date.now());
- const evaluationFacade = new ContentFetcherFacade({
+ const fetcherFacade = new ContentFetcherFacade({
contentFetcher: fetcher,
cidAssigner: new FixedAssigner(clientId),
userTokenProvider: new FixedTokenProvider(userToken),
previewTokenProvider: new FixedTokenProvider(previewToken),
contextFactory: new TabContextFactory(tab),
+ preferredLocale: 'pt-br',
});
const options: FetchOptions = {
@@ -109,7 +110,6 @@ describe('A content fetcher facade', () => {
previewToken: previewToken,
timeout: 5,
version: 1,
- preferredLocale: 'en-US',
context: {
attributes: {
foo: 'bar',
@@ -125,13 +125,27 @@ describe('A content fetcher facade', () => {
const slotId = 'home-banner';
- await evaluationFacade.fetch(slotId, {
+ await fetcherFacade.fetch(slotId, {
timeout: options.timeout,
version: options.version,
- preferredLocale: options.preferredLocale,
attributes: options?.context?.attributes,
});
- expect(fetcher.fetch).toHaveBeenNthCalledWith(1, slotId, options);
+ expect(fetcher.fetch).toHaveBeenNthCalledWith(1, slotId, {
+ ...options,
+ preferredLocale: 'pt-br',
+ });
+
+ await fetcherFacade.fetch(slotId, {
+ timeout: options.timeout,
+ version: options.version,
+ attributes: options?.context?.attributes,
+ preferredLocale: 'en-us',
+ });
+
+ expect(fetcher.fetch).toHaveBeenNthCalledWith(2, slotId, {
+ ...options,
+ preferredLocale: 'en-us',
+ });
});
});
diff --git a/test/facade/sdkFacade.test.ts b/test/facade/sdkFacade.test.ts
index 40a87d01..ce42b95d 100644
--- a/test/facade/sdkFacade.test.ts
+++ b/test/facade/sdkFacade.test.ts
@@ -381,17 +381,27 @@ describe('A SDK facade', () => {
return sdk;
});
+ const slotId = 'home-banner';
+ const preferredLocale = 'en-us';
+
const sdkFacade = SdkFacade.init({
appId: appId,
track: false,
+ preferredLocale: preferredLocale,
});
- const slotId = 'home-banner';
- const options: FetchOptions = {timeout: 5};
+ const options: FetchOptions = {
+ timeout: 5,
+ };
+
+ const expectedOptions: FetchOptions = {
+ ...options,
+ preferredLocale: preferredLocale,
+ };
await expect(sdkFacade.contentFetcher.fetch(slotId, options)).resolves.toBe(result);
- expect(fetcher.fetch).toHaveBeenCalledWith(slotId, expect.objectContaining(options));
+ expect(fetcher.fetch).toHaveBeenCalledWith(slotId, expect.objectContaining(expectedOptions));
expect(fetcher.fetch).toHaveBeenCalledTimes(1);
});
diff --git a/test/schemas/sdkFacadeSchemas.test.ts b/test/schemas/sdkFacadeSchemas.test.ts
index d2322e28..6ec084bf 100644
--- a/test/schemas/sdkFacadeSchemas.test.ts
+++ b/test/schemas/sdkFacadeSchemas.test.ts
@@ -22,6 +22,30 @@ describe('The SDK facade configuration schema', () => {
appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
userId: null,
}],
+ [{
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'pt',
+ }],
+ [{
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'pt_br',
+ }],
+ [{
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'pt_BR',
+ }],
+ [{
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'pt-br',
+ }],
+ [{
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'pt-BR',
+ }],
+ [{
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'abc_cde',
+ }],
[{
appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
baseEndpointUrl: 'https://api.croct.io/',
@@ -54,57 +78,124 @@ describe('The SDK facade configuration schema', () => {
"Missing property '/appId'.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', clientId: '7e9d59a9'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ clientId: '7e9d59a9',
+ },
"Invalid format at path '/clientId'.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', cidAssignerEndpointUrl: 'x'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ cidAssignerEndpointUrl: 'x',
+ },
"Invalid url format at path '/cidAssignerEndpointUrl'.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', baseEndpointUrl: 'x'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ baseEndpointUrl: 'x',
+ },
"Invalid url format at path '/baseEndpointUrl'.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', tokenScope: 'x'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ tokenScope: 'x',
+ },
"Unexpected value at path '/tokenScope', expecting 'global', 'contextual' or 'isolated', found 'x'.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', userId: ''},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ userId: '',
+ },
"Expected at least 1 character at path '/userId', actual 0.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', userId: 1},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ userId: 1,
+ },
"Expected value of type string or null at path '/userId', actual integer.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', token: 'foo'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ token: 'foo',
+ },
"Invalid format at path '/token'.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', token: 1},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ token: 1,
+ },
"Expected value of type string or null at path '/token', actual integer.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', debug: 'foo'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ debug: 'foo',
+ },
"Expected value of type boolean at path '/debug', actual string.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', test: 'foo'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ test: 'foo',
+ },
"Expected value of type boolean at path '/test', actual string.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', track: 'foo'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ track: 'foo',
+ },
"Expected value of type boolean at path '/track', actual string.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', disableCidMirroring: 'foo'},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ disableCidMirroring: 'foo',
+ },
"Expected value of type boolean at path '/disableCidMirroring', actual string.",
],
[
- {appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a', logger: null},
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ logger: null,
+ },
"Expected value of type object at path '/logger', actual null.",
],
+ [
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: '',
+ },
+ "Invalid format at path '/preferredLocale'.",
+ ],
+ [
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'fooo',
+ },
+ 'Invalid format at path \'/preferredLocale\'.',
+ ],
+ [
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'foo-baar',
+ },
+ 'Invalid format at path \'/preferredLocale\'.',
+ ],
+ [
+ {
+ appId: '7e9d59a9-e4b3-45d4-b1c7-48287f1e5e8a',
+ preferredLocale: 'foo_baar',
+ },
+ 'Invalid format at path \'/preferredLocale\'.',
+ ],
])('should not allow %s', (value: Record, message: string) => {
function validate(): void {
sdkFacadeConfigurationSchema.validate(value);