@croct/sdk 0.19.1 → 0.20.1
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/cache/cookieCache.cjs +31 -0
- package/cache/cookieCache.d.cts +8 -2
- package/cache/cookieCache.d.ts +8 -2
- package/cache/cookieCache.js +31 -0
- package/channel/encodedChannel.cjs +1 -1
- package/channel/encodedChannel.js +1 -1
- package/constants.cjs +1 -1
- package/constants.d.cts +2 -2
- package/constants.d.ts +2 -2
- package/constants.js +1 -1
- package/container.cjs +2 -0
- package/container.d.cts +2 -1
- package/container.d.ts +2 -1
- package/container.js +3 -7
- package/contentFetcher.cjs +7 -4
- package/contentFetcher.d.cts +26 -4
- package/contentFetcher.d.ts +26 -4
- package/contentFetcher.js +7 -4
- package/facade/contentFetcherFacade.cjs +9 -6
- package/facade/contentFetcherFacade.d.cts +4 -3
- package/facade/contentFetcherFacade.d.ts +4 -3
- package/facade/contentFetcherFacade.js +9 -6
- package/facade/index.d.cts +1 -0
- package/facade/index.d.ts +1 -0
- package/facade/sdkFacade.d.cts +1 -0
- package/facade/sdkFacade.d.ts +1 -0
- package/index.d.cts +1 -0
- package/index.d.ts +1 -0
- package/package.json +10 -7
- package/schema/contentFetcherSchemas.cjs +1 -0
- package/schema/contentFetcherSchemas.js +2 -1
- package/sdk.d.cts +1 -0
- package/sdk.d.ts +1 -0
- package/token/cachedTokenStore.cjs +1 -1
- package/token/cachedTokenStore.js +1 -1
- package/token/token.cjs +1 -1
- package/token/token.js +1 -1
- package/tracker.d.cts +2 -2
- package/tracker.d.ts +2 -2
- package/tracker.js +1 -4
package/cache/cookieCache.cjs
CHANGED
|
@@ -22,6 +22,7 @@ __export(cookieCache_exports, {
|
|
|
22
22
|
module.exports = __toCommonJS(cookieCache_exports);
|
|
23
23
|
class CookieCache {
|
|
24
24
|
constructor(config, defaultSecure = window.location.protocol === "https:") {
|
|
25
|
+
this.listeners = [];
|
|
25
26
|
this.config = {
|
|
26
27
|
...config,
|
|
27
28
|
path: config.path ?? "/"
|
|
@@ -52,6 +53,36 @@ class CookieCache {
|
|
|
52
53
|
maxAge: 0
|
|
53
54
|
});
|
|
54
55
|
}
|
|
56
|
+
static autoSync(cache) {
|
|
57
|
+
if (typeof window.cookieStore === "undefined") {
|
|
58
|
+
return () => {
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const listener = cache.sync.bind(cache);
|
|
62
|
+
window.cookieStore.addEventListener("change", listener);
|
|
63
|
+
return () => window.cookieStore.removeEventListener("change", listener);
|
|
64
|
+
}
|
|
65
|
+
addListener(listener) {
|
|
66
|
+
if (!this.listeners.includes(listener)) {
|
|
67
|
+
this.listeners.push(listener);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
removeListener(listener) {
|
|
71
|
+
const index = this.listeners.indexOf(listener);
|
|
72
|
+
if (index > -1) {
|
|
73
|
+
this.listeners.splice(index, 1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
sync(event) {
|
|
77
|
+
const isRelevant = [...event.changed, ...event.deleted].some((cookie) => cookie.name !== void 0 && CookieCache.decode(cookie.name) === this.config.name);
|
|
78
|
+
if (!isRelevant) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.notifyChange(this.get());
|
|
82
|
+
}
|
|
83
|
+
notifyChange(value) {
|
|
84
|
+
this.listeners.forEach((listener) => listener(value));
|
|
85
|
+
}
|
|
55
86
|
static serializeCookie(value, config) {
|
|
56
87
|
const cookie = [`${CookieCache.encode(config.name)}=${CookieCache.encode(value)}`];
|
|
57
88
|
if (config.maxAge !== void 0) {
|
package/cache/cookieCache.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ObservableCache, CacheListener } from './cache.cjs';
|
|
2
2
|
|
|
3
3
|
type CookieCacheConfiguration = {
|
|
4
4
|
name: string;
|
|
@@ -8,12 +8,18 @@ type CookieCacheConfiguration = {
|
|
|
8
8
|
path?: string;
|
|
9
9
|
sameSite?: 'strict' | 'lax' | 'none';
|
|
10
10
|
};
|
|
11
|
-
declare class CookieCache implements
|
|
11
|
+
declare class CookieCache implements ObservableCache {
|
|
12
12
|
private readonly config;
|
|
13
|
+
private readonly listeners;
|
|
13
14
|
constructor(config: CookieCacheConfiguration, defaultSecure?: boolean);
|
|
14
15
|
get(): string | null;
|
|
15
16
|
put(value: string): void;
|
|
16
17
|
clear(): void;
|
|
18
|
+
static autoSync(cache: CookieCache): () => void;
|
|
19
|
+
addListener(listener: CacheListener): void;
|
|
20
|
+
removeListener(listener: CacheListener): void;
|
|
21
|
+
private sync;
|
|
22
|
+
private notifyChange;
|
|
17
23
|
private static serializeCookie;
|
|
18
24
|
private static encode;
|
|
19
25
|
private static decode;
|
package/cache/cookieCache.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ObservableCache, CacheListener } from './cache.js';
|
|
2
2
|
|
|
3
3
|
type CookieCacheConfiguration = {
|
|
4
4
|
name: string;
|
|
@@ -8,12 +8,18 @@ type CookieCacheConfiguration = {
|
|
|
8
8
|
path?: string;
|
|
9
9
|
sameSite?: 'strict' | 'lax' | 'none';
|
|
10
10
|
};
|
|
11
|
-
declare class CookieCache implements
|
|
11
|
+
declare class CookieCache implements ObservableCache {
|
|
12
12
|
private readonly config;
|
|
13
|
+
private readonly listeners;
|
|
13
14
|
constructor(config: CookieCacheConfiguration, defaultSecure?: boolean);
|
|
14
15
|
get(): string | null;
|
|
15
16
|
put(value: string): void;
|
|
16
17
|
clear(): void;
|
|
18
|
+
static autoSync(cache: CookieCache): () => void;
|
|
19
|
+
addListener(listener: CacheListener): void;
|
|
20
|
+
removeListener(listener: CacheListener): void;
|
|
21
|
+
private sync;
|
|
22
|
+
private notifyChange;
|
|
17
23
|
private static serializeCookie;
|
|
18
24
|
private static encode;
|
|
19
25
|
private static decode;
|
package/cache/cookieCache.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
class CookieCache {
|
|
2
2
|
constructor(config, defaultSecure = window.location.protocol === "https:") {
|
|
3
|
+
this.listeners = [];
|
|
3
4
|
this.config = {
|
|
4
5
|
...config,
|
|
5
6
|
path: config.path ?? "/"
|
|
@@ -30,6 +31,36 @@ class CookieCache {
|
|
|
30
31
|
maxAge: 0
|
|
31
32
|
});
|
|
32
33
|
}
|
|
34
|
+
static autoSync(cache) {
|
|
35
|
+
if (typeof window.cookieStore === "undefined") {
|
|
36
|
+
return () => {
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const listener = cache.sync.bind(cache);
|
|
40
|
+
window.cookieStore.addEventListener("change", listener);
|
|
41
|
+
return () => window.cookieStore.removeEventListener("change", listener);
|
|
42
|
+
}
|
|
43
|
+
addListener(listener) {
|
|
44
|
+
if (!this.listeners.includes(listener)) {
|
|
45
|
+
this.listeners.push(listener);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
removeListener(listener) {
|
|
49
|
+
const index = this.listeners.indexOf(listener);
|
|
50
|
+
if (index > -1) {
|
|
51
|
+
this.listeners.splice(index, 1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
sync(event) {
|
|
55
|
+
const isRelevant = [...event.changed, ...event.deleted].some((cookie) => cookie.name !== void 0 && CookieCache.decode(cookie.name) === this.config.name);
|
|
56
|
+
if (!isRelevant) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.notifyChange(this.get());
|
|
60
|
+
}
|
|
61
|
+
notifyChange(value) {
|
|
62
|
+
this.listeners.forEach((listener) => listener(value));
|
|
63
|
+
}
|
|
33
64
|
static serializeCookie(value, config) {
|
|
34
65
|
const cookie = [`${CookieCache.encode(config.name)}=${CookieCache.encode(value)}`];
|
|
35
66
|
if (config.maxAge !== void 0) {
|
|
@@ -26,7 +26,7 @@ class EncodedChannel {
|
|
|
26
26
|
this.encode = encoder;
|
|
27
27
|
}
|
|
28
28
|
publish(message) {
|
|
29
|
-
return this.encode(message).then((result) => this.channel.publish(result));
|
|
29
|
+
return this.encode(message).then(((result) => this.channel.publish(result)));
|
|
30
30
|
}
|
|
31
31
|
close() {
|
|
32
32
|
return this.channel.close();
|
|
@@ -4,7 +4,7 @@ class EncodedChannel {
|
|
|
4
4
|
this.encode = encoder;
|
|
5
5
|
}
|
|
6
6
|
publish(message) {
|
|
7
|
-
return this.encode(message).then((result) => this.channel.publish(result));
|
|
7
|
+
return this.encode(message).then(((result) => this.channel.publish(result)));
|
|
8
8
|
}
|
|
9
9
|
close() {
|
|
10
10
|
return this.channel.close();
|
package/constants.cjs
CHANGED
|
@@ -25,7 +25,7 @@ __export(constants_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(constants_exports);
|
|
26
26
|
const BASE_ENDPOINT_URL = "https://api.croct.io";
|
|
27
27
|
const MAX_QUERY_LENGTH = parseInt("<@maxQueryLength@>", 10);
|
|
28
|
-
const VERSION = "0.
|
|
28
|
+
const VERSION = "0.20.1";
|
|
29
29
|
const CLIENT_LIBRARY = `Croct SDK JS v${VERSION}`;
|
|
30
30
|
// Annotate the CommonJS export names for ESM import in node:
|
|
31
31
|
0 && (module.exports = {
|
package/constants.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare const BASE_ENDPOINT_URL = "https://api.croct.io";
|
|
2
2
|
declare const MAX_QUERY_LENGTH: number;
|
|
3
|
-
declare const VERSION = "0.
|
|
4
|
-
declare const CLIENT_LIBRARY = "Croct SDK JS v0.
|
|
3
|
+
declare const VERSION = "0.20.1";
|
|
4
|
+
declare const CLIENT_LIBRARY = "Croct SDK JS v0.20.1";
|
|
5
5
|
|
|
6
6
|
export { BASE_ENDPOINT_URL, CLIENT_LIBRARY, MAX_QUERY_LENGTH, VERSION };
|
package/constants.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare const BASE_ENDPOINT_URL = "https://api.croct.io";
|
|
2
2
|
declare const MAX_QUERY_LENGTH: number;
|
|
3
|
-
declare const VERSION = "0.
|
|
4
|
-
declare const CLIENT_LIBRARY = "Croct SDK JS v0.
|
|
3
|
+
declare const VERSION = "0.20.1";
|
|
4
|
+
declare const CLIENT_LIBRARY = "Croct SDK JS v0.20.1";
|
|
5
5
|
|
|
6
6
|
export { BASE_ENDPOINT_URL, CLIENT_LIBRARY, MAX_QUERY_LENGTH, VERSION };
|
package/constants.js
CHANGED
package/container.cjs
CHANGED
|
@@ -129,6 +129,8 @@ const _Container = class _Container {
|
|
|
129
129
|
const tabStorage = this.getSessionStorage();
|
|
130
130
|
if (browserCache instanceof import_cache.LocalStorageCache) {
|
|
131
131
|
this.removeTokenSyncListener = import_cache.LocalStorageCache.autoSync(browserCache);
|
|
132
|
+
} else if (browserCache instanceof import_cookieCache.CookieCache) {
|
|
133
|
+
this.removeTokenSyncListener = import_cookieCache.CookieCache.autoSync(browserCache);
|
|
132
134
|
}
|
|
133
135
|
return import_context.Context.load({
|
|
134
136
|
tokenScope: this.configuration.tokenScope,
|
package/container.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { Logger } from './logging/logger.cjs';
|
|
|
2
2
|
import { TokenScope, Context } from './context.cjs';
|
|
3
3
|
import { MonitoredQueue } from './queue/monitoredQueue.cjs';
|
|
4
4
|
import { TokenStore } from './token/token.cjs';
|
|
5
|
-
import {
|
|
5
|
+
import { Tracker, TrackingEventProcessor } from './tracker.cjs';
|
|
6
6
|
import { Evaluator } from './evaluator.cjs';
|
|
7
7
|
import { CidAssigner } from './cid/assigner.cjs';
|
|
8
8
|
import { EventManager } from './eventManager.cjs';
|
|
@@ -20,6 +20,7 @@ import './trackingEvents.cjs';
|
|
|
20
20
|
import './patch.cjs';
|
|
21
21
|
import './utilityTypes.cjs';
|
|
22
22
|
import './sourceLocation.cjs';
|
|
23
|
+
import '@croct/content-model/definition';
|
|
23
24
|
|
|
24
25
|
type DependencyResolver<T> = (container: Container) => T;
|
|
25
26
|
type Configuration = {
|
package/container.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Logger } from './logging/logger.js';
|
|
|
2
2
|
import { TokenScope, Context } from './context.js';
|
|
3
3
|
import { MonitoredQueue } from './queue/monitoredQueue.js';
|
|
4
4
|
import { TokenStore } from './token/token.js';
|
|
5
|
-
import {
|
|
5
|
+
import { Tracker, TrackingEventProcessor } from './tracker.js';
|
|
6
6
|
import { Evaluator } from './evaluator.js';
|
|
7
7
|
import { CidAssigner } from './cid/assigner.js';
|
|
8
8
|
import { EventManager } from './eventManager.js';
|
|
@@ -20,6 +20,7 @@ import './trackingEvents.js';
|
|
|
20
20
|
import './patch.js';
|
|
21
21
|
import './utilityTypes.js';
|
|
22
22
|
import './sourceLocation.js';
|
|
23
|
+
import '@croct/content-model/definition';
|
|
23
24
|
|
|
24
25
|
type DependencyResolver<T> = (container: Container) => T;
|
|
25
26
|
type Configuration = {
|
package/container.js
CHANGED
|
@@ -11,13 +11,7 @@ import { CachedAssigner, RemoteAssigner, FixedAssigner } from "./cid/index.js";
|
|
|
11
11
|
import { SynchronousEventManager } from "./eventManager.js";
|
|
12
12
|
import { LocalStorageCache } from "./cache/index.js";
|
|
13
13
|
import { TimeStamper } from "./channel/guaranteedChannel.js";
|
|
14
|
-
import {
|
|
15
|
-
QueuedChannel,
|
|
16
|
-
RetryChannel,
|
|
17
|
-
GuaranteedChannel,
|
|
18
|
-
EncodedChannel,
|
|
19
|
-
SandboxChannel
|
|
20
|
-
} from "./channel/index.js";
|
|
14
|
+
import { QueuedChannel, RetryChannel, GuaranteedChannel, EncodedChannel, SandboxChannel } from "./channel/index.js";
|
|
21
15
|
import { ContentFetcher } from "./contentFetcher.js";
|
|
22
16
|
import { CookieCache } from "./cache/cookieCache.js";
|
|
23
17
|
import { FilteredLogger } from "./logging/filteredLogger.js";
|
|
@@ -113,6 +107,8 @@ const _Container = class _Container {
|
|
|
113
107
|
const tabStorage = this.getSessionStorage();
|
|
114
108
|
if (browserCache instanceof LocalStorageCache) {
|
|
115
109
|
this.removeTokenSyncListener = LocalStorageCache.autoSync(browserCache);
|
|
110
|
+
} else if (browserCache instanceof CookieCache) {
|
|
111
|
+
this.removeTokenSyncListener = CookieCache.autoSync(browserCache);
|
|
116
112
|
}
|
|
117
113
|
return Context.load({
|
|
118
114
|
tokenScope: this.configuration.tokenScope,
|
package/contentFetcher.cjs
CHANGED
|
@@ -57,13 +57,13 @@ class ContentFetcher {
|
|
|
57
57
|
defaultPreferredLocale: configuration.defaultPreferredLocale
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
fetch(slotId, options
|
|
61
|
-
if (options
|
|
60
|
+
fetch(slotId, options) {
|
|
61
|
+
if (options?.static === true && this.configuration.apiKey === void 0) {
|
|
62
62
|
throw new Error("The API key must be provided to fetch static content.");
|
|
63
63
|
}
|
|
64
64
|
return new Promise((resolve, reject) => {
|
|
65
65
|
const abortController = new AbortController();
|
|
66
|
-
const timeout = options
|
|
66
|
+
const timeout = options?.timeout ?? this.configuration.defaultTimeout;
|
|
67
67
|
let timer;
|
|
68
68
|
if (timeout !== void 0) {
|
|
69
69
|
timer = setTimeout(
|
|
@@ -82,7 +82,7 @@ class ContentFetcher {
|
|
|
82
82
|
timeout
|
|
83
83
|
);
|
|
84
84
|
}
|
|
85
|
-
this.load(slotId, abortController.signal, options).finally(() => clearTimeout(timer)).then((response) => {
|
|
85
|
+
this.load(slotId, abortController.signal, options ?? {}).finally(() => clearTimeout(timer)).then((response) => {
|
|
86
86
|
const region = response.headers.get("X-Croct-Region");
|
|
87
87
|
const timing = response.headers.get("X-Croct-Timing");
|
|
88
88
|
this.logger.debug(`Content for slot '${slotId}' processed by region ${region} in ${timing}.`);
|
|
@@ -136,6 +136,9 @@ class ContentFetcher {
|
|
|
136
136
|
const payload = {
|
|
137
137
|
slotId
|
|
138
138
|
};
|
|
139
|
+
if (options.includeSchema === true) {
|
|
140
|
+
payload.includeSchema = true;
|
|
141
|
+
}
|
|
139
142
|
if (options.version !== void 0) {
|
|
140
143
|
payload.version = `${options.version}`;
|
|
141
144
|
}
|
package/contentFetcher.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { JsonObject } from '@croct/json';
|
|
2
|
+
import { ContentDefinitionBundle } from '@croct/content-model/definition';
|
|
2
3
|
import { EvaluationContext } from './evaluator.cjs';
|
|
3
4
|
import { Token } from './token/token.cjs';
|
|
4
5
|
import { Logger } from './logging/logger.cjs';
|
|
@@ -20,7 +21,10 @@ declare class ContentError<T extends ErrorResponse = ErrorResponse> extends Erro
|
|
|
20
21
|
readonly response: T;
|
|
21
22
|
constructor(response: T);
|
|
22
23
|
}
|
|
23
|
-
type
|
|
24
|
+
type FetchResponseOptions = {
|
|
25
|
+
includeSchema?: boolean;
|
|
26
|
+
};
|
|
27
|
+
type BasicOptions = FetchResponseOptions & {
|
|
24
28
|
version?: `${number}` | number;
|
|
25
29
|
preferredLocale?: string;
|
|
26
30
|
timeout?: number;
|
|
@@ -43,7 +47,25 @@ type ExtraFetchOptions<T extends keyof RequestInit = AllowedFetchOptions> = Pick
|
|
|
43
47
|
[key in Exclude<keyof RequestInit, T>]?: never;
|
|
44
48
|
} & Record<string, any>;
|
|
45
49
|
type FetchOptions = StaticContentOptions | DynamicContentOptions;
|
|
46
|
-
type
|
|
50
|
+
type With<T, K extends keyof T> = T & {
|
|
51
|
+
[P in K]-?: T[P];
|
|
52
|
+
};
|
|
53
|
+
type SlotMetadata = {
|
|
54
|
+
version: string;
|
|
55
|
+
schema?: ContentDefinitionBundle;
|
|
56
|
+
experience?: {
|
|
57
|
+
experienceId: string;
|
|
58
|
+
audienceId: string;
|
|
59
|
+
experiment?: {
|
|
60
|
+
experimentId: string;
|
|
61
|
+
variantId: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
type FetchResponse<P = JsonObject, O = FetchResponseOptions> = {
|
|
66
|
+
metadata: With<SlotMetadata, O extends {
|
|
67
|
+
includeSchema: true;
|
|
68
|
+
} ? 'schema' : never>;
|
|
47
69
|
content: P;
|
|
48
70
|
};
|
|
49
71
|
type Configuration = {
|
|
@@ -60,11 +82,11 @@ declare class ContentFetcher {
|
|
|
60
82
|
private readonly staticEndpoint;
|
|
61
83
|
private readonly logger;
|
|
62
84
|
constructor(configuration: Configuration);
|
|
63
|
-
fetch<P extends JsonObject>(slotId: string, options?: FetchOptions): Promise<FetchResponse<P>>;
|
|
85
|
+
fetch<P extends JsonObject, O extends FetchResponseOptions>(slotId: string, options?: O & FetchOptions): Promise<FetchResponse<P, O>>;
|
|
64
86
|
private load;
|
|
65
87
|
private logHelp;
|
|
66
88
|
private static isDynamicContent;
|
|
67
89
|
toJSON(): never;
|
|
68
90
|
}
|
|
69
91
|
|
|
70
|
-
export { type Configuration, ContentError, ContentErrorType, ContentFetcher, type DynamicContentOptions, type ErrorResponse, type FetchOptions, type FetchResponse, type StaticContentOptions };
|
|
92
|
+
export { type Configuration, ContentError, ContentErrorType, ContentFetcher, type DynamicContentOptions, type ErrorResponse, type FetchOptions, type FetchResponse, type FetchResponseOptions, type SlotMetadata, type StaticContentOptions };
|
package/contentFetcher.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { JsonObject } from '@croct/json';
|
|
2
|
+
import { ContentDefinitionBundle } from '@croct/content-model/definition';
|
|
2
3
|
import { EvaluationContext } from './evaluator.js';
|
|
3
4
|
import { Token } from './token/token.js';
|
|
4
5
|
import { Logger } from './logging/logger.js';
|
|
@@ -20,7 +21,10 @@ declare class ContentError<T extends ErrorResponse = ErrorResponse> extends Erro
|
|
|
20
21
|
readonly response: T;
|
|
21
22
|
constructor(response: T);
|
|
22
23
|
}
|
|
23
|
-
type
|
|
24
|
+
type FetchResponseOptions = {
|
|
25
|
+
includeSchema?: boolean;
|
|
26
|
+
};
|
|
27
|
+
type BasicOptions = FetchResponseOptions & {
|
|
24
28
|
version?: `${number}` | number;
|
|
25
29
|
preferredLocale?: string;
|
|
26
30
|
timeout?: number;
|
|
@@ -43,7 +47,25 @@ type ExtraFetchOptions<T extends keyof RequestInit = AllowedFetchOptions> = Pick
|
|
|
43
47
|
[key in Exclude<keyof RequestInit, T>]?: never;
|
|
44
48
|
} & Record<string, any>;
|
|
45
49
|
type FetchOptions = StaticContentOptions | DynamicContentOptions;
|
|
46
|
-
type
|
|
50
|
+
type With<T, K extends keyof T> = T & {
|
|
51
|
+
[P in K]-?: T[P];
|
|
52
|
+
};
|
|
53
|
+
type SlotMetadata = {
|
|
54
|
+
version: string;
|
|
55
|
+
schema?: ContentDefinitionBundle;
|
|
56
|
+
experience?: {
|
|
57
|
+
experienceId: string;
|
|
58
|
+
audienceId: string;
|
|
59
|
+
experiment?: {
|
|
60
|
+
experimentId: string;
|
|
61
|
+
variantId: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
type FetchResponse<P = JsonObject, O = FetchResponseOptions> = {
|
|
66
|
+
metadata: With<SlotMetadata, O extends {
|
|
67
|
+
includeSchema: true;
|
|
68
|
+
} ? 'schema' : never>;
|
|
47
69
|
content: P;
|
|
48
70
|
};
|
|
49
71
|
type Configuration = {
|
|
@@ -60,11 +82,11 @@ declare class ContentFetcher {
|
|
|
60
82
|
private readonly staticEndpoint;
|
|
61
83
|
private readonly logger;
|
|
62
84
|
constructor(configuration: Configuration);
|
|
63
|
-
fetch<P extends JsonObject>(slotId: string, options?: FetchOptions): Promise<FetchResponse<P>>;
|
|
85
|
+
fetch<P extends JsonObject, O extends FetchResponseOptions>(slotId: string, options?: O & FetchOptions): Promise<FetchResponse<P, O>>;
|
|
64
86
|
private load;
|
|
65
87
|
private logHelp;
|
|
66
88
|
private static isDynamicContent;
|
|
67
89
|
toJSON(): never;
|
|
68
90
|
}
|
|
69
91
|
|
|
70
|
-
export { type Configuration, ContentError, ContentErrorType, ContentFetcher, type DynamicContentOptions, type ErrorResponse, type FetchOptions, type FetchResponse, type StaticContentOptions };
|
|
92
|
+
export { type Configuration, ContentError, ContentErrorType, ContentFetcher, type DynamicContentOptions, type ErrorResponse, type FetchOptions, type FetchResponse, type FetchResponseOptions, type SlotMetadata, type StaticContentOptions };
|
package/contentFetcher.js
CHANGED
|
@@ -33,13 +33,13 @@ class ContentFetcher {
|
|
|
33
33
|
defaultPreferredLocale: configuration.defaultPreferredLocale
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
fetch(slotId, options
|
|
37
|
-
if (options
|
|
36
|
+
fetch(slotId, options) {
|
|
37
|
+
if (options?.static === true && this.configuration.apiKey === void 0) {
|
|
38
38
|
throw new Error("The API key must be provided to fetch static content.");
|
|
39
39
|
}
|
|
40
40
|
return new Promise((resolve, reject) => {
|
|
41
41
|
const abortController = new AbortController();
|
|
42
|
-
const timeout = options
|
|
42
|
+
const timeout = options?.timeout ?? this.configuration.defaultTimeout;
|
|
43
43
|
let timer;
|
|
44
44
|
if (timeout !== void 0) {
|
|
45
45
|
timer = setTimeout(
|
|
@@ -58,7 +58,7 @@ class ContentFetcher {
|
|
|
58
58
|
timeout
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
|
-
this.load(slotId, abortController.signal, options).finally(() => clearTimeout(timer)).then((response) => {
|
|
61
|
+
this.load(slotId, abortController.signal, options ?? {}).finally(() => clearTimeout(timer)).then((response) => {
|
|
62
62
|
const region = response.headers.get("X-Croct-Region");
|
|
63
63
|
const timing = response.headers.get("X-Croct-Timing");
|
|
64
64
|
this.logger.debug(`Content for slot '${slotId}' processed by region ${region} in ${timing}.`);
|
|
@@ -112,6 +112,9 @@ class ContentFetcher {
|
|
|
112
112
|
const payload = {
|
|
113
113
|
slotId
|
|
114
114
|
};
|
|
115
|
+
if (options.includeSchema === true) {
|
|
116
|
+
payload.includeSchema = true;
|
|
117
|
+
}
|
|
115
118
|
if (options.version !== void 0) {
|
|
116
119
|
payload.version = `${options.version}`;
|
|
117
120
|
}
|
|
@@ -37,20 +37,23 @@ class ContentFetcherFacade {
|
|
|
37
37
|
this.cidAssigner = configuration.cidAssigner;
|
|
38
38
|
this.contextFactory = configuration.contextFactory;
|
|
39
39
|
}
|
|
40
|
-
async fetch(slotId, options
|
|
40
|
+
async fetch(slotId, options) {
|
|
41
41
|
if (typeof slotId !== "string" || slotId.length === 0) {
|
|
42
42
|
throw new Error("The slot ID must be a non-empty string.");
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
if (options !== void 0) {
|
|
45
|
+
validate(options);
|
|
46
|
+
}
|
|
45
47
|
return this.fetcher.fetch(slotId, {
|
|
46
48
|
static: false,
|
|
47
49
|
clientId: await this.cidAssigner.assignCid(),
|
|
48
50
|
userToken: this.userTokenProvider.getToken() ?? void 0,
|
|
49
51
|
previewToken: this.previewTokenProvider.getToken() ?? void 0,
|
|
50
|
-
version: options
|
|
51
|
-
context: this.contextFactory.createContext(options
|
|
52
|
-
timeout: options
|
|
53
|
-
preferredLocale: options
|
|
52
|
+
version: options?.version,
|
|
53
|
+
context: this.contextFactory.createContext(options?.attributes),
|
|
54
|
+
timeout: options?.timeout,
|
|
55
|
+
preferredLocale: options?.preferredLocale,
|
|
56
|
+
includeSchema: options?.includeSchema
|
|
54
57
|
});
|
|
55
58
|
}
|
|
56
59
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { JsonObject } from '@croct/json';
|
|
2
|
-
import { ContentFetcher, FetchResponse } from '../contentFetcher.cjs';
|
|
2
|
+
import { ContentFetcher, FetchResponseOptions, FetchResponse } from '../contentFetcher.cjs';
|
|
3
3
|
import { ContextFactory } from './evaluatorFacade.cjs';
|
|
4
4
|
import { TokenProvider } from '../token/token.cjs';
|
|
5
5
|
import { CidAssigner } from '../cid/assigner.cjs';
|
|
6
|
+
import '@croct/content-model/definition';
|
|
6
7
|
import '../evaluator.cjs';
|
|
7
8
|
import '../sourceLocation.cjs';
|
|
8
9
|
import '../logging/logger.cjs';
|
|
@@ -10,7 +11,7 @@ import '../apiKey.cjs';
|
|
|
10
11
|
import '../tab.cjs';
|
|
11
12
|
import '../eventManager.cjs';
|
|
12
13
|
|
|
13
|
-
type FetchOptions = {
|
|
14
|
+
type FetchOptions = FetchResponseOptions & {
|
|
14
15
|
version?: `${number}` | number;
|
|
15
16
|
preferredLocale?: string;
|
|
16
17
|
timeout?: number;
|
|
@@ -30,7 +31,7 @@ declare class ContentFetcherFacade {
|
|
|
30
31
|
private readonly userTokenProvider;
|
|
31
32
|
private readonly cidAssigner;
|
|
32
33
|
constructor(configuration: Configuration);
|
|
33
|
-
fetch<P extends JsonObject>(slotId: string, options?: FetchOptions): Promise<FetchResponse<P>>;
|
|
34
|
+
fetch<P extends JsonObject, O extends FetchResponseOptions>(slotId: string, options?: O & FetchOptions): Promise<FetchResponse<P, O>>;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export { type Configuration, ContentFetcherFacade, type FetchOptions };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { JsonObject } from '@croct/json';
|
|
2
|
-
import { ContentFetcher, FetchResponse } from '../contentFetcher.js';
|
|
2
|
+
import { ContentFetcher, FetchResponseOptions, FetchResponse } from '../contentFetcher.js';
|
|
3
3
|
import { ContextFactory } from './evaluatorFacade.js';
|
|
4
4
|
import { TokenProvider } from '../token/token.js';
|
|
5
5
|
import { CidAssigner } from '../cid/assigner.js';
|
|
6
|
+
import '@croct/content-model/definition';
|
|
6
7
|
import '../evaluator.js';
|
|
7
8
|
import '../sourceLocation.js';
|
|
8
9
|
import '../logging/logger.js';
|
|
@@ -10,7 +11,7 @@ import '../apiKey.js';
|
|
|
10
11
|
import '../tab.js';
|
|
11
12
|
import '../eventManager.js';
|
|
12
13
|
|
|
13
|
-
type FetchOptions = {
|
|
14
|
+
type FetchOptions = FetchResponseOptions & {
|
|
14
15
|
version?: `${number}` | number;
|
|
15
16
|
preferredLocale?: string;
|
|
16
17
|
timeout?: number;
|
|
@@ -30,7 +31,7 @@ declare class ContentFetcherFacade {
|
|
|
30
31
|
private readonly userTokenProvider;
|
|
31
32
|
private readonly cidAssigner;
|
|
32
33
|
constructor(configuration: Configuration);
|
|
33
|
-
fetch<P extends JsonObject>(slotId: string, options?: FetchOptions): Promise<FetchResponse<P>>;
|
|
34
|
+
fetch<P extends JsonObject, O extends FetchResponseOptions>(slotId: string, options?: O & FetchOptions): Promise<FetchResponse<P, O>>;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export { type Configuration, ContentFetcherFacade, type FetchOptions };
|
|
@@ -15,20 +15,23 @@ class ContentFetcherFacade {
|
|
|
15
15
|
this.cidAssigner = configuration.cidAssigner;
|
|
16
16
|
this.contextFactory = configuration.contextFactory;
|
|
17
17
|
}
|
|
18
|
-
async fetch(slotId, options
|
|
18
|
+
async fetch(slotId, options) {
|
|
19
19
|
if (typeof slotId !== "string" || slotId.length === 0) {
|
|
20
20
|
throw new Error("The slot ID must be a non-empty string.");
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
if (options !== void 0) {
|
|
23
|
+
validate(options);
|
|
24
|
+
}
|
|
23
25
|
return this.fetcher.fetch(slotId, {
|
|
24
26
|
static: false,
|
|
25
27
|
clientId: await this.cidAssigner.assignCid(),
|
|
26
28
|
userToken: this.userTokenProvider.getToken() ?? void 0,
|
|
27
29
|
previewToken: this.previewTokenProvider.getToken() ?? void 0,
|
|
28
|
-
version: options
|
|
29
|
-
context: this.contextFactory.createContext(options
|
|
30
|
-
timeout: options
|
|
31
|
-
preferredLocale: options
|
|
30
|
+
version: options?.version,
|
|
31
|
+
context: this.contextFactory.createContext(options?.attributes),
|
|
32
|
+
timeout: options?.timeout,
|
|
33
|
+
preferredLocale: options?.preferredLocale,
|
|
34
|
+
includeSchema: options?.includeSchema
|
|
32
35
|
});
|
|
33
36
|
}
|
|
34
37
|
}
|
package/facade/index.d.cts
CHANGED
|
@@ -19,6 +19,7 @@ import '../cache/cache.cjs';
|
|
|
19
19
|
import '../sdkEvents.cjs';
|
|
20
20
|
import './contentFetcherFacade.cjs';
|
|
21
21
|
import '../contentFetcher.cjs';
|
|
22
|
+
import '@croct/content-model/definition';
|
|
22
23
|
import '../cache/cookieCache.cjs';
|
|
23
24
|
import '../trackingEvents.cjs';
|
|
24
25
|
import '../patch.cjs';
|
package/facade/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import '../cache/cache.js';
|
|
|
19
19
|
import '../sdkEvents.js';
|
|
20
20
|
import './contentFetcherFacade.js';
|
|
21
21
|
import '../contentFetcher.js';
|
|
22
|
+
import '@croct/content-model/definition';
|
|
22
23
|
import '../cache/cookieCache.js';
|
|
23
24
|
import '../trackingEvents.js';
|
|
24
25
|
import '../patch.js';
|
package/facade/sdkFacade.d.cts
CHANGED
package/facade/sdkFacade.d.ts
CHANGED
package/index.d.cts
CHANGED
package/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@croct/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "Croct SDK for JavaScript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -80,19 +80,22 @@
|
|
|
80
80
|
"postbuild": "./post-build.mjs"
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
|
+
"@croct/content-model": "^0.21.1",
|
|
83
84
|
"@croct/json": "^2.0.1",
|
|
84
85
|
"tslib": "^2.5.0"
|
|
85
86
|
},
|
|
86
87
|
"devDependencies": {
|
|
87
|
-
"
|
|
88
|
-
"@
|
|
88
|
+
"@croct/eslint-plugin": "^0.8.3",
|
|
89
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
90
|
+
"@fetch-mock/jest": "^0.2.20",
|
|
91
|
+
"@typescript-eslint/parser": "^8.53.0",
|
|
89
92
|
"@types/jest": "^30.0.0",
|
|
90
|
-
"
|
|
91
|
-
"
|
|
93
|
+
"esbuild-fix-imports-plugin": "^1.0.19",
|
|
94
|
+
"eslint": "^9.39.0",
|
|
95
|
+
"fetch-mock": "^12.6.0",
|
|
92
96
|
"jest": "^30.0.0",
|
|
93
97
|
"jest-environment-jsdom": "^30.0.0",
|
|
94
|
-
"jest-extended": "^
|
|
95
|
-
"node-fetch": "^2.6.7",
|
|
98
|
+
"jest-extended": "^7.0.0",
|
|
96
99
|
"ts-jest": "^29.0.3",
|
|
97
100
|
"tsup": "^8.4.0",
|
|
98
101
|
"typescript": "^5.0.0"
|
|
@@ -39,6 +39,7 @@ const fetchOptionsSchema = new import_validation.ObjectType({
|
|
|
39
39
|
preferredLocale: new import_validation.StringType({
|
|
40
40
|
pattern: /^[a-z]{2,3}([-_][a-z]{2,3})?$/i
|
|
41
41
|
}),
|
|
42
|
+
includeSchema: new import_validation.BooleanType(),
|
|
42
43
|
attributes: new import_validation.JsonObjectType()
|
|
43
44
|
}
|
|
44
45
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ObjectType, NumberType, JsonObjectType, StringType, UnionType } from "../validation/index.js";
|
|
1
|
+
import { ObjectType, NumberType, JsonObjectType, StringType, UnionType, BooleanType } from "../validation/index.js";
|
|
2
2
|
const fetchOptionsSchema = new ObjectType({
|
|
3
3
|
properties: {
|
|
4
4
|
timeout: new NumberType({
|
|
@@ -17,6 +17,7 @@ const fetchOptionsSchema = new ObjectType({
|
|
|
17
17
|
preferredLocale: new StringType({
|
|
18
18
|
pattern: /^[a-z]{2,3}([-_][a-z]{2,3})?$/i
|
|
19
19
|
}),
|
|
20
|
+
includeSchema: new BooleanType(),
|
|
20
21
|
attributes: new JsonObjectType()
|
|
21
22
|
}
|
|
22
23
|
});
|
package/sdk.d.cts
CHANGED
package/sdk.d.ts
CHANGED
package/token/token.cjs
CHANGED
|
@@ -64,7 +64,7 @@ const _Token = class _Token {
|
|
|
64
64
|
try {
|
|
65
65
|
headers = JSON.parse((0, import_base64Url.base64UrlDecode)(parts[0], true));
|
|
66
66
|
payload = JSON.parse((0, import_base64Url.base64UrlDecode)(parts[1], true));
|
|
67
|
-
} catch
|
|
67
|
+
} catch {
|
|
68
68
|
throw new Error("The token is corrupted.");
|
|
69
69
|
}
|
|
70
70
|
return _Token.of(headers, payload, parts[2]);
|
package/token/token.js
CHANGED
|
@@ -41,7 +41,7 @@ const _Token = class _Token {
|
|
|
41
41
|
try {
|
|
42
42
|
headers = JSON.parse(base64UrlDecode(parts[0], true));
|
|
43
43
|
payload = JSON.parse(base64UrlDecode(parts[1], true));
|
|
44
|
-
} catch
|
|
44
|
+
} catch {
|
|
45
45
|
throw new Error("The token is corrupted.");
|
|
46
46
|
}
|
|
47
47
|
return _Token.of(headers, payload, parts[2]);
|
package/tracker.d.cts
CHANGED
|
@@ -2,8 +2,8 @@ import { Logger } from './logging/logger.cjs';
|
|
|
2
2
|
import { Tab } from './tab.cjs';
|
|
3
3
|
import { OutputChannel } from './channel/channel.cjs';
|
|
4
4
|
import { RetryPolicy } from './retry/policy.cjs';
|
|
5
|
-
import {
|
|
6
|
-
import { TrackingEvent, TrackingEventContext,
|
|
5
|
+
import { TokenProvider, Token } from './token/token.cjs';
|
|
6
|
+
import { Beacon, TrackingEvent, TrackingEventContext, PartialTrackingEvent } from './trackingEvents.cjs';
|
|
7
7
|
import './eventManager.cjs';
|
|
8
8
|
import '@croct/json';
|
|
9
9
|
import './apiKey.cjs';
|
package/tracker.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { Logger } from './logging/logger.js';
|
|
|
2
2
|
import { Tab } from './tab.js';
|
|
3
3
|
import { OutputChannel } from './channel/channel.js';
|
|
4
4
|
import { RetryPolicy } from './retry/policy.js';
|
|
5
|
-
import {
|
|
6
|
-
import { TrackingEvent, TrackingEventContext,
|
|
5
|
+
import { TokenProvider, Token } from './token/token.js';
|
|
6
|
+
import { Beacon, TrackingEvent, TrackingEventContext, PartialTrackingEvent } from './trackingEvents.js';
|
|
7
7
|
import './eventManager.js';
|
|
8
8
|
import '@croct/json';
|
|
9
9
|
import './apiKey.js';
|
package/tracker.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { NullLogger } from "./logging/index.js";
|
|
2
2
|
import { formatCause } from "./error.js";
|
|
3
|
-
import {
|
|
4
|
-
isCartPartialEvent,
|
|
5
|
-
isIdentifiedUserEvent
|
|
6
|
-
} from "./trackingEvents.js";
|
|
3
|
+
import { isCartPartialEvent, isIdentifiedUserEvent } from "./trackingEvents.js";
|
|
7
4
|
const trackedEvents = {};
|
|
8
5
|
class Tracker {
|
|
9
6
|
constructor(config) {
|