@zeroad.network/token 0.13.13 → 0.14.0

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.
@@ -12,9 +12,15 @@ function setLogLevel(level) {
12
12
  currentLevel = level;
13
13
  }
14
14
  }
15
+ let transport = (level, ...args) => {
16
+ console.log(`[${level.toUpperCase()}]`, ...args);
17
+ };
18
+ function setLogTransport(fn) {
19
+ transport = fn;
20
+ }
15
21
  function log(level, ...args) {
16
22
  if (levels[level] <= levels[currentLevel]) {
17
- console.log(`[${level.toUpperCase()}]`, ...args);
23
+ transport(level, ...args);
18
24
  }
19
25
  }
20
26
 
@@ -38,17 +44,9 @@ var PROTOCOL_VERSION = /* @__PURE__ */ ((PROTOCOL_VERSION2) => {
38
44
  })(PROTOCOL_VERSION || {});
39
45
  const CURRENT_PROTOCOL_VERSION = 1 /* V_1 */;
40
46
 
41
- let cachedFeatures;
42
- function FEATURE_MAP() {
43
- if (cachedFeatures) return cachedFeatures;
44
- cachedFeatures = /* @__PURE__ */ new Map();
45
- for (const key of Object.keys(FEATURE)) {
46
- if (!isNaN(Number(key))) continue;
47
- const typedKey = key;
48
- cachedFeatures.set(typedKey, FEATURE[typedKey]);
49
- }
50
- return cachedFeatures;
51
- }
47
+ const FEATURE_MAP = new Map(
48
+ Object.entries(FEATURE).filter(([k]) => isNaN(Number(k)))
49
+ );
52
50
  function toBase64(data) {
53
51
  if (typeof data.toBase64 === "function") return data.toBase64();
54
52
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
@@ -61,23 +59,25 @@ function toBase64(data) {
61
59
  }
62
60
  throw new Error("Base64 encoding not supported in this environment");
63
61
  }
64
- function fromBase64(input) {
65
- if (typeof Uint8Array.fromBase64 === "function") return Uint8Array.fromBase64(input);
66
- if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(input, "base64"));
67
- if (typeof atob === "function") {
62
+ exports.fromBase64 = void 0;
63
+ if (typeof Uint8Array.fromBase64 === "function") exports.fromBase64 = (input) => Uint8Array.fromBase64(input);
64
+ else if (typeof Buffer !== "undefined") exports.fromBase64 = (input) => new Uint8Array(Buffer.from(input, "base64"));
65
+ else if (typeof atob === "function") {
66
+ exports.fromBase64 = (input) => {
68
67
  const binary = atob(input);
69
68
  const bytes = new Uint8Array(binary.length);
70
69
  for (let i = 0; i < binary.length; i++) {
71
70
  bytes[i] = binary.charCodeAt(i);
72
71
  }
73
72
  return bytes;
74
- }
73
+ };
74
+ } else {
75
75
  throw new Error("Base64 decoding not supported in this environment");
76
76
  }
77
77
  function assert(value, message) {
78
78
  if (!value) throw new Error(message);
79
79
  }
80
- const hasFlag = (bit, flags) => Boolean(bit & flags);
80
+ const hasFlag = (bit, flags) => (bit & flags) !== 0;
81
81
  const setFlags = (features = []) => features.reduce((acc, feature) => acc | feature, 0);
82
82
 
83
83
  const SEPARATOR = "^";
@@ -107,7 +107,7 @@ function decodeServerHeader(headerValue) {
107
107
  );
108
108
  assert(Number(flags).toFixed(0).toString() === flags, "Invalid flags number");
109
109
  const features = [];
110
- for (const [feature, bit] of FEATURE_MAP()) {
110
+ for (const [feature, bit] of FEATURE_MAP) {
111
111
  if (hasFlag(Number(flags), bit)) features.push(feature);
112
112
  }
113
113
  return {
@@ -128,9 +128,8 @@ exports.SERVER_HEADER = SERVER_HEADER;
128
128
  exports.ZEROAD_NETWORK_PUBLIC_KEY = ZEROAD_NETWORK_PUBLIC_KEY;
129
129
  exports.decodeServerHeader = decodeServerHeader;
130
130
  exports.encodeServerHeader = encodeServerHeader;
131
- exports.fromBase64 = fromBase64;
132
- exports.hasFlag = hasFlag;
133
131
  exports.log = log;
134
132
  exports.setFlags = setFlags;
135
133
  exports.setLogLevel = setLogLevel;
134
+ exports.setLogTransport = setLogTransport;
136
135
  exports.toBase64 = toBase64;
@@ -10,9 +10,15 @@ function setLogLevel(level) {
10
10
  currentLevel = level;
11
11
  }
12
12
  }
13
+ let transport = (level, ...args) => {
14
+ console.log(`[${level.toUpperCase()}]`, ...args);
15
+ };
16
+ function setLogTransport(fn) {
17
+ transport = fn;
18
+ }
13
19
  function log(level, ...args) {
14
20
  if (levels[level] <= levels[currentLevel]) {
15
- console.log(`[${level.toUpperCase()}]`, ...args);
21
+ transport(level, ...args);
16
22
  }
17
23
  }
18
24
 
@@ -36,17 +42,9 @@ var PROTOCOL_VERSION = /* @__PURE__ */ ((PROTOCOL_VERSION2) => {
36
42
  })(PROTOCOL_VERSION || {});
37
43
  const CURRENT_PROTOCOL_VERSION = 1 /* V_1 */;
38
44
 
39
- let cachedFeatures;
40
- function FEATURE_MAP() {
41
- if (cachedFeatures) return cachedFeatures;
42
- cachedFeatures = /* @__PURE__ */ new Map();
43
- for (const key of Object.keys(FEATURE)) {
44
- if (!isNaN(Number(key))) continue;
45
- const typedKey = key;
46
- cachedFeatures.set(typedKey, FEATURE[typedKey]);
47
- }
48
- return cachedFeatures;
49
- }
45
+ const FEATURE_MAP = new Map(
46
+ Object.entries(FEATURE).filter(([k]) => isNaN(Number(k)))
47
+ );
50
48
  function toBase64(data) {
51
49
  if (typeof data.toBase64 === "function") return data.toBase64();
52
50
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
@@ -59,23 +57,25 @@ function toBase64(data) {
59
57
  }
60
58
  throw new Error("Base64 encoding not supported in this environment");
61
59
  }
62
- function fromBase64(input) {
63
- if (typeof Uint8Array.fromBase64 === "function") return Uint8Array.fromBase64(input);
64
- if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(input, "base64"));
65
- if (typeof atob === "function") {
60
+ let fromBase64;
61
+ if (typeof Uint8Array.fromBase64 === "function") fromBase64 = (input) => Uint8Array.fromBase64(input);
62
+ else if (typeof Buffer !== "undefined") fromBase64 = (input) => new Uint8Array(Buffer.from(input, "base64"));
63
+ else if (typeof atob === "function") {
64
+ fromBase64 = (input) => {
66
65
  const binary = atob(input);
67
66
  const bytes = new Uint8Array(binary.length);
68
67
  for (let i = 0; i < binary.length; i++) {
69
68
  bytes[i] = binary.charCodeAt(i);
70
69
  }
71
70
  return bytes;
72
- }
71
+ };
72
+ } else {
73
73
  throw new Error("Base64 decoding not supported in this environment");
74
74
  }
75
75
  function assert(value, message) {
76
76
  if (!value) throw new Error(message);
77
77
  }
78
- const hasFlag = (bit, flags) => Boolean(bit & flags);
78
+ const hasFlag = (bit, flags) => (bit & flags) !== 0;
79
79
  const setFlags = (features = []) => features.reduce((acc, feature) => acc | feature, 0);
80
80
 
81
81
  const SEPARATOR = "^";
@@ -105,7 +105,7 @@ function decodeServerHeader(headerValue) {
105
105
  );
106
106
  assert(Number(flags).toFixed(0).toString() === flags, "Invalid flags number");
107
107
  const features = [];
108
- for (const [feature, bit] of FEATURE_MAP()) {
108
+ for (const [feature, bit] of FEATURE_MAP) {
109
109
  if (hasFlag(Number(flags), bit)) features.push(feature);
110
110
  }
111
111
  return {
@@ -118,4 +118,4 @@ function decodeServerHeader(headerValue) {
118
118
  }
119
119
  }
120
120
 
121
- export { CLIENT_HEADER as C, FEATURE as F, PROTOCOL_VERSION as P, SERVER_HEADER as S, ZEROAD_NETWORK_PUBLIC_KEY as Z, setLogLevel as a, CURRENT_PROTOCOL_VERSION as b, decodeServerHeader as d, encodeServerHeader as e, fromBase64 as f, hasFlag as h, log as l, setFlags as s, toBase64 as t };
121
+ export { CLIENT_HEADER as C, FEATURE as F, PROTOCOL_VERSION as P, SERVER_HEADER as S, ZEROAD_NETWORK_PUBLIC_KEY as Z, setLogLevel as a, setLogTransport as b, CURRENT_PROTOCOL_VERSION as c, decodeServerHeader as d, encodeServerHeader as e, fromBase64 as f, log as l, setFlags as s, toBase64 as t };
package/dist/browser.mjs CHANGED
@@ -1 +1 @@
1
- export { C as CLIENT_HEADER, b as CURRENT_PROTOCOL_VERSION, F as FEATURE, P as PROTOCOL_VERSION, S as SERVER_HEADER, Z as ZEROAD_NETWORK_PUBLIC_KEY, d as decodeServerHeader } from './browser-DiH4sEBn.mjs';
1
+ export { C as CLIENT_HEADER, c as CURRENT_PROTOCOL_VERSION, F as FEATURE, P as PROTOCOL_VERSION, S as SERVER_HEADER, Z as ZEROAD_NETWORK_PUBLIC_KEY, d as decodeServerHeader } from './browser-VjxLaeuu.mjs';
package/dist/index.cjs CHANGED
@@ -1,17 +1,74 @@
1
1
  'use strict';
2
2
 
3
- var browser = require('./browser-Do--x9Sv.cjs');
3
+ var browser = require('./browser-D3BXUIiT.cjs');
4
4
  var node_buffer = require('node:buffer');
5
5
  var node_crypto = require('node:crypto');
6
6
 
7
+ const DEFAULT_CACHE_CONFIG = {
8
+ enabled: true,
9
+ maxSize: 100,
10
+ ttl: 5e3
11
+ // 5 seconds
12
+ };
13
+ exports.cacheConfig = { ...DEFAULT_CACHE_CONFIG };
14
+ function configureCaching(config) {
15
+ if (config.ttl !== void 0 && config.ttl < 0) {
16
+ throw new Error("Cache TTL must be >= 0");
17
+ }
18
+ if (config.maxSize !== void 0 && config.maxSize < 1) {
19
+ throw new Error("Cache maxSize must be >= 1");
20
+ }
21
+ exports.cacheConfig = { ...exports.cacheConfig, ...config };
22
+ if (!exports.cacheConfig.enabled) {
23
+ headerCache.clear();
24
+ }
25
+ trimCache();
26
+ browser.log("debug", "Cache configuration updated", exports.cacheConfig);
27
+ }
28
+ function getCacheConfig() {
29
+ return { ...exports.cacheConfig };
30
+ }
31
+ const headerCache = /* @__PURE__ */ new Map();
32
+ function trimCache() {
33
+ if (headerCache.size <= exports.cacheConfig.maxSize) return;
34
+ const entriesToRemove = headerCache.size - exports.cacheConfig.maxSize;
35
+ const entries = Array.from(headerCache.entries());
36
+ entries.sort((a, b) => {
37
+ if (a[1].accessCount !== b[1].accessCount) {
38
+ return a[1].accessCount - b[1].accessCount;
39
+ }
40
+ return a[1].timestamp - b[1].timestamp;
41
+ });
42
+ for (let i = 0; i < entriesToRemove; i++) {
43
+ headerCache.delete(entries[i][0]);
44
+ }
45
+ }
46
+ function cleanExpiredEntries(now) {
47
+ for (const [key, entry] of headerCache.entries()) {
48
+ if (entry.effectiveExpiry <= now) {
49
+ headerCache.delete(key);
50
+ }
51
+ }
52
+ }
53
+
7
54
  const keyCache = /* @__PURE__ */ new Map();
8
55
  function sign(data, privateKey) {
9
56
  const key = importPrivateKey(privateKey);
10
- return node_crypto.sign(null, node_buffer.Buffer.from(data), key);
57
+ return new Promise((resolve, reject) => {
58
+ node_crypto.sign(null, node_buffer.Buffer.from(data), key, (err, result) => {
59
+ if (err) reject(err);
60
+ else resolve(result);
61
+ });
62
+ });
11
63
  }
12
64
  function verify(data, signature, publicKey) {
13
65
  const key = importPublicKey(publicKey);
14
- return node_crypto.verify(null, node_buffer.Buffer.from(data), key, node_buffer.Buffer.from(signature));
66
+ return new Promise((resolve, reject) => {
67
+ node_crypto.verify(null, node_buffer.Buffer.from(data), key, node_buffer.Buffer.from(signature), (err, result) => {
68
+ if (err) reject(err);
69
+ else resolve(result);
70
+ });
71
+ });
15
72
  }
16
73
  const nonce = (size) => new Uint8Array(node_crypto.randomBytes(size));
17
74
  function importPrivateKey(privateKeyBase64) {
@@ -38,55 +95,132 @@ function importPublicKey(publicKeyBase64) {
38
95
  const VERSION_BYTES = 1;
39
96
  const NONCE_BYTES = 4;
40
97
  const SEPARATOR = ".";
41
- const FEATURE_TO_ACTIONS = {
42
- [browser.FEATURE.CLEAN_WEB]: [
98
+ const UINT32_BYTES = 4;
99
+ const FEATURE_TO_ACTIONS = Object.freeze({
100
+ [browser.FEATURE.CLEAN_WEB]: Object.freeze([
43
101
  "HIDE_ADVERTISEMENTS",
44
102
  "HIDE_COOKIE_CONSENT_SCREEN",
45
103
  "HIDE_MARKETING_DIALOGS",
46
104
  "DISABLE_NON_FUNCTIONAL_TRACKING"
47
- ],
48
- [browser.FEATURE.ONE_PASS]: ["DISABLE_CONTENT_PAYWALL", "ENABLE_SUBSCRIPTION_ACCESS"]
49
- };
50
- function parseClientToken(headerValue, options) {
105
+ ]),
106
+ [browser.FEATURE.ONE_PASS]: Object.freeze([
107
+ "DISABLE_CONTENT_PAYWALL",
108
+ "ENABLE_SUBSCRIPTION_ACCESS"
109
+ ])
110
+ });
111
+ const FEATURE_NUMBERS = Object.freeze([browser.FEATURE.CLEAN_WEB, browser.FEATURE.ONE_PASS]);
112
+ const EMPTY_CONTEXT = Object.freeze({
113
+ HIDE_ADVERTISEMENTS: false,
114
+ HIDE_COOKIE_CONSENT_SCREEN: false,
115
+ HIDE_MARKETING_DIALOGS: false,
116
+ DISABLE_NON_FUNCTIONAL_TRACKING: false,
117
+ DISABLE_CONTENT_PAYWALL: false,
118
+ ENABLE_SUBSCRIPTION_ACCESS: false
119
+ });
120
+ function createEmptyContext() {
121
+ return EMPTY_CONTEXT;
122
+ }
123
+ async function parseClientToken(headerValue, options) {
124
+ if (!headerValue || Array.isArray(headerValue) && !headerValue.length) {
125
+ return createEmptyContext();
126
+ }
51
127
  const headerValueAsString = Array.isArray(headerValue) ? headerValue[0] : headerValue;
52
- const data = decodeClientHeader(headerValueAsString, options.publicKey || browser.ZEROAD_NETWORK_PUBLIC_KEY);
128
+ const now = Date.now();
129
+ if (exports.cacheConfig.enabled && !options.bypassCache) {
130
+ const cached = headerCache.get(headerValueAsString);
131
+ if (cached && cached.effectiveExpiry > now) {
132
+ cached.accessCount++;
133
+ return buildContext(cached.data, options, now);
134
+ } else if (cached) {
135
+ headerCache.delete(headerValueAsString);
136
+ }
137
+ }
138
+ const data = await decodeClientHeader(headerValueAsString, options.publicKey || browser.ZEROAD_NETWORK_PUBLIC_KEY);
139
+ if (exports.cacheConfig.enabled && !options.bypassCache) {
140
+ const cacheTTLExpiry = now + exports.cacheConfig.ttl;
141
+ const tokenExpiry = data?.expiresAt.getTime() ?? 0;
142
+ const effectiveExpiry = tokenExpiry > 0 ? Math.min(cacheTTLExpiry, tokenExpiry) : cacheTTLExpiry;
143
+ headerCache.set(headerValueAsString, {
144
+ data,
145
+ timestamp: now,
146
+ accessCount: 1,
147
+ effectiveExpiry
148
+ });
149
+ if (headerCache.size > 0 && headerCache.size % 100 === 0) {
150
+ cleanExpiredEntries(now);
151
+ }
152
+ trimCache();
153
+ }
154
+ return buildContext(data, options, now);
155
+ }
156
+ function buildContext(data, options, now) {
53
157
  let flags = 0;
54
- if (data && data.expiresAt.getTime() >= Date.now()) flags = data.flags;
55
- if (flags && data?.clientId && data.clientId !== options.clientId) flags = 0;
56
- const context = /* @__PURE__ */ new Map();
57
- for (const [feature, actionNames] of Object.entries(FEATURE_TO_ACTIONS)) {
58
- const decision = options.features.includes(Number(feature)) && browser.hasFlag(Number(feature), flags);
59
- for (const actionName of actionNames) {
60
- context.set(actionName, decision);
158
+ if (data && data.expiresAt.getTime() >= now) {
159
+ if (!data.clientId || data.clientId === options.clientId) {
160
+ flags = data.flags;
61
161
  }
62
162
  }
63
- return Object.fromEntries(context);
163
+ if (!flags) {
164
+ return createEmptyContext();
165
+ }
166
+ const featuresSet = options.features.length <= 2 ? options.features : new Set(options.features);
167
+ const context = {};
168
+ for (let i = 0; i < FEATURE_NUMBERS.length; i++) {
169
+ const feature = FEATURE_NUMBERS[i];
170
+ const actionNames = FEATURE_TO_ACTIONS[feature];
171
+ const isEnabled = (Array.isArray(featuresSet) ? featuresSet.includes(feature) : featuresSet.has(feature)) && (flags & feature) !== 0;
172
+ const len = actionNames.length;
173
+ if (len > 0) context[actionNames[0]] = isEnabled;
174
+ if (len > 1) context[actionNames[1]] = isEnabled;
175
+ if (len > 2) context[actionNames[2]] = isEnabled;
176
+ if (len > 3) context[actionNames[3]] = isEnabled;
177
+ }
178
+ return context;
64
179
  }
65
- function decodeClientHeader(headerValue, publicKey) {
66
- if (!headerValue?.length) return;
180
+ async function decodeClientHeader(headerValue, publicKey) {
181
+ if (!headerValue?.length) return void 0;
67
182
  try {
68
- const [data, signature] = headerValue.split(SEPARATOR);
183
+ const separatorIndex = headerValue.indexOf(SEPARATOR);
184
+ if (separatorIndex === -1) {
185
+ throw new Error("Invalid header format: missing separator");
186
+ }
187
+ const data = headerValue.substring(0, separatorIndex);
188
+ const signature = headerValue.substring(separatorIndex + 1);
69
189
  const dataBytes = browser.fromBase64(data);
70
190
  const signatureBytes = browser.fromBase64(signature);
71
- if (!verify(dataBytes.buffer, signatureBytes.buffer, publicKey)) {
191
+ if (!await verify(dataBytes.buffer, signatureBytes.buffer, publicKey)) {
72
192
  throw new Error("Forged header value is provided");
73
193
  }
74
194
  const version = dataBytes[0];
75
- let clientId;
76
195
  if (version === browser.PROTOCOL_VERSION.V_1) {
77
- const expiresAt = as32BitNumber(dataBytes, VERSION_BYTES + NONCE_BYTES);
78
- const flags = as32BitNumber(dataBytes, VERSION_BYTES + NONCE_BYTES + Uint32Array.BYTES_PER_ELEMENT);
79
- const expectedByteLength = VERSION_BYTES + NONCE_BYTES + Uint32Array.BYTES_PER_ELEMENT * 2;
80
- if (dataBytes.byteLength > expectedByteLength) {
81
- clientId = new TextDecoder().decode(dataBytes.subarray(expectedByteLength));
196
+ const expectedMinLength = VERSION_BYTES + NONCE_BYTES + UINT32_BYTES * 2;
197
+ if (dataBytes.byteLength < expectedMinLength) {
198
+ throw new Error("Invalid data length");
82
199
  }
83
- return { version, expiresAt: new Date(expiresAt * 1e3), flags, ...clientId && { clientId } };
200
+ const view = new DataView(dataBytes.buffer, dataBytes.byteOffset, dataBytes.byteLength);
201
+ const expiresAtOffset = VERSION_BYTES + NONCE_BYTES;
202
+ const flagsOffset = expiresAtOffset + UINT32_BYTES;
203
+ const expiresAt = view.getUint32(expiresAtOffset, true);
204
+ const flags = view.getUint32(flagsOffset, true);
205
+ let clientId;
206
+ if (dataBytes.byteLength > expectedMinLength) {
207
+ const clientIdBytes = dataBytes.subarray(expectedMinLength);
208
+ clientId = new TextDecoder().decode(clientIdBytes);
209
+ }
210
+ return {
211
+ version,
212
+ expiresAt: new Date(expiresAt * 1e3),
213
+ flags,
214
+ ...clientId && { clientId }
215
+ };
84
216
  }
217
+ throw new Error(`Unsupported protocol version: ${version}`);
85
218
  } catch (err) {
86
219
  browser.log("warn", "Could not decode client header value", { reason: err?.message });
220
+ return void 0;
87
221
  }
88
222
  }
89
- function encodeClientHeader(data, privateKey) {
223
+ async function encodeClientHeader(data, privateKey) {
90
224
  const payload = mergeByteArrays([
91
225
  new Uint8Array([data.version]),
92
226
  new Uint8Array(nonce(NONCE_BYTES)),
@@ -94,7 +228,7 @@ function encodeClientHeader(data, privateKey) {
94
228
  new Uint32Array([browser.setFlags(data.features)]),
95
229
  ...data.clientId?.length ? [new Uint8Array(new TextEncoder().encode(data.clientId))] : []
96
230
  ]);
97
- return [browser.toBase64(payload), browser.toBase64(new Uint8Array(sign(payload.buffer, privateKey)))].join(SEPARATOR);
231
+ return [browser.toBase64(payload), browser.toBase64(new Uint8Array(await sign(payload.buffer, privateKey)))].join(SEPARATOR);
98
232
  }
99
233
  function mergeByteArrays(arrays) {
100
234
  const totalLength = arrays.reduce((sum, a) => sum + a.byteLength, 0);
@@ -110,14 +244,12 @@ function mergeByteArrays(arrays) {
110
244
  }
111
245
  return data;
112
246
  }
113
- function as32BitNumber(byteArray, begin) {
114
- const bytes = byteArray.subarray(begin, begin + Uint32Array.BYTES_PER_ELEMENT);
115
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
116
- return view.getUint32(0, true);
117
- }
118
247
 
119
248
  function Site(options) {
120
249
  const serverHeaderValue = browser.encodeServerHeader(options.clientId, options.features);
250
+ if (options.cacheConfig) {
251
+ configureCaching(options.cacheConfig);
252
+ }
121
253
  return {
122
254
  parseClientToken: (headerValue) => parseClientToken(headerValue, { clientId: options.clientId, features: options.features }),
123
255
  CLIENT_HEADER_NAME: browser.CLIENT_HEADER.HELLO.toLowerCase(),
@@ -135,7 +267,13 @@ exports.ZEROAD_NETWORK_PUBLIC_KEY = browser.ZEROAD_NETWORK_PUBLIC_KEY;
135
267
  exports.decodeServerHeader = browser.decodeServerHeader;
136
268
  exports.encodeServerHeader = browser.encodeServerHeader;
137
269
  exports.setLogLevel = browser.setLogLevel;
270
+ exports.setLogTransport = browser.setLogTransport;
138
271
  exports.Site = Site;
272
+ exports.cleanExpiredEntries = cleanExpiredEntries;
273
+ exports.configureCaching = configureCaching;
139
274
  exports.decodeClientHeader = decodeClientHeader;
140
275
  exports.encodeClientHeader = encodeClientHeader;
276
+ exports.getCacheConfig = getCacheConfig;
277
+ exports.headerCache = headerCache;
141
278
  exports.parseClientToken = parseClientToken;
279
+ exports.trimCache = trimCache;
package/dist/index.d.cts CHANGED
@@ -3,6 +3,8 @@ export { C as CLIENT_HEADER, a as CURRENT_PROTOCOL_VERSION, W as WelcomeHeader,
3
3
 
4
4
  type LogLevel = "error" | "warn" | "info" | "debug";
5
5
  declare function setLogLevel(level: LogLevel): void;
6
+ type LogTransport = (level: LogLevel, ...args: unknown[]) => void;
7
+ declare function setLogTransport(fn: LogTransport): void;
6
8
 
7
9
  type FEATURE_ACTION = "HIDE_ADVERTISEMENTS" | "HIDE_COOKIE_CONSENT_SCREEN" | "HIDE_MARKETING_DIALOGS" | "DISABLE_NON_FUNCTIONAL_TRACKING" | "DISABLE_CONTENT_PAYWALL" | "ENABLE_SUBSCRIPTION_ACCESS";
8
10
  type ClientHeaderValue = string | string[] | undefined;
@@ -11,33 +13,53 @@ type ParseClientTokenOptions = {
11
13
  clientId: string;
12
14
  features: FEATURE[];
13
15
  publicKey?: string;
16
+ bypassCache?: boolean;
14
17
  };
15
- declare function parseClientToken(headerValue: ClientHeaderValue, options: ParseClientTokenOptions): TokenContext;
18
+ declare function parseClientToken(headerValue: ClientHeaderValue, options: ParseClientTokenOptions): Promise<TokenContext>;
16
19
  type DecodedClientHeader = {
17
20
  version: PROTOCOL_VERSION;
18
21
  expiresAt: Date;
19
22
  flags: number;
20
23
  clientId?: string;
21
24
  };
22
- declare function decodeClientHeader(headerValue: string | null | undefined, publicKey: string): DecodedClientHeader | undefined;
25
+ declare function decodeClientHeader(headerValue: string | null | undefined, publicKey: string): Promise<DecodedClientHeader | undefined>;
23
26
  type EncodeData = {
24
27
  version: PROTOCOL_VERSION;
25
28
  expiresAt: Date;
26
29
  features: FEATURE[];
27
30
  clientId?: string;
28
31
  };
29
- declare function encodeClientHeader(data: EncodeData, privateKey: string): string;
32
+ declare function encodeClientHeader(data: EncodeData, privateKey: string): Promise<string>;
33
+
34
+ interface CacheConfig {
35
+ enabled: boolean;
36
+ maxSize: number;
37
+ ttl: number;
38
+ }
39
+ declare let cacheConfig: CacheConfig;
40
+ declare function configureCaching(config: Partial<CacheConfig>): void;
41
+ declare function getCacheConfig(): Readonly<CacheConfig>;
42
+ interface CacheEntry {
43
+ data: DecodedClientHeader | undefined;
44
+ effectiveExpiry: number;
45
+ accessCount: number;
46
+ timestamp: number;
47
+ }
48
+ declare const headerCache: Map<string, CacheEntry>;
49
+ declare function trimCache(): void;
50
+ declare function cleanExpiredEntries(now: number): void;
30
51
 
31
52
  type SiteOptions = {
32
53
  clientId: string;
33
54
  features: FEATURE[];
55
+ cacheConfig?: CacheConfig;
34
56
  };
35
57
  declare function Site(options: SiteOptions): {
36
- parseClientToken: (headerValue: ClientHeaderValue) => TokenContext;
58
+ parseClientToken: (headerValue: ClientHeaderValue) => Promise<TokenContext>;
37
59
  CLIENT_HEADER_NAME: string;
38
60
  SERVER_HEADER_NAME: SERVER_HEADER;
39
61
  SERVER_HEADER_VALUE: string;
40
62
  };
41
63
 
42
- export { FEATURE, PROTOCOL_VERSION, SERVER_HEADER, Site, decodeClientHeader, encodeClientHeader, parseClientToken, setLogLevel };
43
- export type { ClientHeaderValue, DecodedClientHeader, FEATURE_ACTION, ParseClientTokenOptions, TokenContext };
64
+ export { FEATURE, PROTOCOL_VERSION, SERVER_HEADER, Site, cacheConfig, cleanExpiredEntries, configureCaching, decodeClientHeader, encodeClientHeader, getCacheConfig, headerCache, parseClientToken, setLogLevel, setLogTransport, trimCache };
65
+ export type { CacheConfig, ClientHeaderValue, DecodedClientHeader, FEATURE_ACTION, ParseClientTokenOptions, TokenContext };
package/dist/index.d.mts CHANGED
@@ -3,6 +3,8 @@ export { C as CLIENT_HEADER, a as CURRENT_PROTOCOL_VERSION, W as WelcomeHeader,
3
3
 
4
4
  type LogLevel = "error" | "warn" | "info" | "debug";
5
5
  declare function setLogLevel(level: LogLevel): void;
6
+ type LogTransport = (level: LogLevel, ...args: unknown[]) => void;
7
+ declare function setLogTransport(fn: LogTransport): void;
6
8
 
7
9
  type FEATURE_ACTION = "HIDE_ADVERTISEMENTS" | "HIDE_COOKIE_CONSENT_SCREEN" | "HIDE_MARKETING_DIALOGS" | "DISABLE_NON_FUNCTIONAL_TRACKING" | "DISABLE_CONTENT_PAYWALL" | "ENABLE_SUBSCRIPTION_ACCESS";
8
10
  type ClientHeaderValue = string | string[] | undefined;
@@ -11,33 +13,53 @@ type ParseClientTokenOptions = {
11
13
  clientId: string;
12
14
  features: FEATURE[];
13
15
  publicKey?: string;
16
+ bypassCache?: boolean;
14
17
  };
15
- declare function parseClientToken(headerValue: ClientHeaderValue, options: ParseClientTokenOptions): TokenContext;
18
+ declare function parseClientToken(headerValue: ClientHeaderValue, options: ParseClientTokenOptions): Promise<TokenContext>;
16
19
  type DecodedClientHeader = {
17
20
  version: PROTOCOL_VERSION;
18
21
  expiresAt: Date;
19
22
  flags: number;
20
23
  clientId?: string;
21
24
  };
22
- declare function decodeClientHeader(headerValue: string | null | undefined, publicKey: string): DecodedClientHeader | undefined;
25
+ declare function decodeClientHeader(headerValue: string | null | undefined, publicKey: string): Promise<DecodedClientHeader | undefined>;
23
26
  type EncodeData = {
24
27
  version: PROTOCOL_VERSION;
25
28
  expiresAt: Date;
26
29
  features: FEATURE[];
27
30
  clientId?: string;
28
31
  };
29
- declare function encodeClientHeader(data: EncodeData, privateKey: string): string;
32
+ declare function encodeClientHeader(data: EncodeData, privateKey: string): Promise<string>;
33
+
34
+ interface CacheConfig {
35
+ enabled: boolean;
36
+ maxSize: number;
37
+ ttl: number;
38
+ }
39
+ declare let cacheConfig: CacheConfig;
40
+ declare function configureCaching(config: Partial<CacheConfig>): void;
41
+ declare function getCacheConfig(): Readonly<CacheConfig>;
42
+ interface CacheEntry {
43
+ data: DecodedClientHeader | undefined;
44
+ effectiveExpiry: number;
45
+ accessCount: number;
46
+ timestamp: number;
47
+ }
48
+ declare const headerCache: Map<string, CacheEntry>;
49
+ declare function trimCache(): void;
50
+ declare function cleanExpiredEntries(now: number): void;
30
51
 
31
52
  type SiteOptions = {
32
53
  clientId: string;
33
54
  features: FEATURE[];
55
+ cacheConfig?: CacheConfig;
34
56
  };
35
57
  declare function Site(options: SiteOptions): {
36
- parseClientToken: (headerValue: ClientHeaderValue) => TokenContext;
58
+ parseClientToken: (headerValue: ClientHeaderValue) => Promise<TokenContext>;
37
59
  CLIENT_HEADER_NAME: string;
38
60
  SERVER_HEADER_NAME: SERVER_HEADER;
39
61
  SERVER_HEADER_VALUE: string;
40
62
  };
41
63
 
42
- export { FEATURE, PROTOCOL_VERSION, SERVER_HEADER, Site, decodeClientHeader, encodeClientHeader, parseClientToken, setLogLevel };
43
- export type { ClientHeaderValue, DecodedClientHeader, FEATURE_ACTION, ParseClientTokenOptions, TokenContext };
64
+ export { FEATURE, PROTOCOL_VERSION, SERVER_HEADER, Site, cacheConfig, cleanExpiredEntries, configureCaching, decodeClientHeader, encodeClientHeader, getCacheConfig, headerCache, parseClientToken, setLogLevel, setLogTransport, trimCache };
65
+ export type { CacheConfig, ClientHeaderValue, DecodedClientHeader, FEATURE_ACTION, ParseClientTokenOptions, TokenContext };