@zeroad.network/token 0.13.12 → 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.
package/dist/index.d.cts CHANGED
@@ -1,43 +1,65 @@
1
- import { F as FEATURES, P as PROTOCOL_VERSION, S as SERVER_HEADERS } from './browser-BiNZ2c6t.cjs';
2
- export { C as CLIENT_HEADERS, a as CURRENT_PROTOCOL_VERSION, W as WelcomeHeader, Z as ZEROAD_NETWORK_PUBLIC_KEY, d as decodeServerHeader, e as encodeServerHeader } from './browser-BiNZ2c6t.cjs';
1
+ import { F as FEATURE, P as PROTOCOL_VERSION, S as SERVER_HEADER } from './browser-Bl2JEJGW.cjs';
2
+ export { C as CLIENT_HEADER, a as CURRENT_PROTOCOL_VERSION, W as WelcomeHeader, Z as ZEROAD_NETWORK_PUBLIC_KEY, d as decodeServerHeader, e as encodeServerHeader } from './browser-Bl2JEJGW.cjs';
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
- type FEATURE_ACTIONS = "HIDE_ADVERTISEMENTS" | "HIDE_COOKIE_CONSENT_SCREEN" | "HIDE_MARKETING_DIALOGS" | "DISABLE_NON_FUNCTIONAL_TRACKING" | "DISABLE_CONTENT_PAYWALL" | "ENABLE_SUBSCRIPTION_ACCESS";
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;
9
- type TokenContext = Record<FEATURE_ACTIONS, boolean>;
11
+ type TokenContext = Record<FEATURE_ACTION, boolean>;
10
12
  type ParseClientTokenOptions = {
11
13
  clientId: string;
12
- features: FEATURES[];
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
- features: FEATURES[];
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
- features: FEATURES[];
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
- SERVER_HEADER_NAME: SERVER_HEADERS;
60
+ SERVER_HEADER_NAME: SERVER_HEADER;
39
61
  SERVER_HEADER_VALUE: string;
40
62
  };
41
63
 
42
- export { FEATURES, PROTOCOL_VERSION, SERVER_HEADERS, Site, decodeClientHeader, encodeClientHeader, parseClientToken, setLogLevel };
43
- export type { ClientHeaderValue, DecodedClientHeader, FEATURE_ACTIONS, 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
@@ -1,43 +1,65 @@
1
- import { F as FEATURES, P as PROTOCOL_VERSION, S as SERVER_HEADERS } from './browser-BiNZ2c6t.mjs';
2
- export { C as CLIENT_HEADERS, a as CURRENT_PROTOCOL_VERSION, W as WelcomeHeader, Z as ZEROAD_NETWORK_PUBLIC_KEY, d as decodeServerHeader, e as encodeServerHeader } from './browser-BiNZ2c6t.mjs';
1
+ import { F as FEATURE, P as PROTOCOL_VERSION, S as SERVER_HEADER } from './browser-Bl2JEJGW.mjs';
2
+ export { C as CLIENT_HEADER, a as CURRENT_PROTOCOL_VERSION, W as WelcomeHeader, Z as ZEROAD_NETWORK_PUBLIC_KEY, d as decodeServerHeader, e as encodeServerHeader } from './browser-Bl2JEJGW.mjs';
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
- type FEATURE_ACTIONS = "HIDE_ADVERTISEMENTS" | "HIDE_COOKIE_CONSENT_SCREEN" | "HIDE_MARKETING_DIALOGS" | "DISABLE_NON_FUNCTIONAL_TRACKING" | "DISABLE_CONTENT_PAYWALL" | "ENABLE_SUBSCRIPTION_ACCESS";
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;
9
- type TokenContext = Record<FEATURE_ACTIONS, boolean>;
11
+ type TokenContext = Record<FEATURE_ACTION, boolean>;
10
12
  type ParseClientTokenOptions = {
11
13
  clientId: string;
12
- features: FEATURES[];
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
- features: FEATURES[];
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
- features: FEATURES[];
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
- SERVER_HEADER_NAME: SERVER_HEADERS;
60
+ SERVER_HEADER_NAME: SERVER_HEADER;
39
61
  SERVER_HEADER_VALUE: string;
40
62
  };
41
63
 
42
- export { FEATURES, PROTOCOL_VERSION, SERVER_HEADERS, Site, decodeClientHeader, encodeClientHeader, parseClientToken, setLogLevel };
43
- export type { ClientHeaderValue, DecodedClientHeader, FEATURE_ACTIONS, 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.mjs CHANGED
@@ -1,16 +1,73 @@
1
- import { F as FEATURES, Z as ZEROAD_NETWORK_PUBLIC_KEY, h as hasFlag, f as fromBase64, P as PROTOCOL_VERSION, l as log, s as setFlags, t as toBase64, e as encodeServerHeader, S as SERVER_HEADERS, C as CLIENT_HEADERS } from './browser--AdrX2EX.mjs';
2
- export { b as CURRENT_PROTOCOL_VERSION, d as decodeServerHeader, a as setLogLevel } from './browser--AdrX2EX.mjs';
1
+ import { l as log, F as FEATURE, Z as ZEROAD_NETWORK_PUBLIC_KEY, f as fromBase64, P as PROTOCOL_VERSION, s as setFlags, t as toBase64, e as encodeServerHeader, S as SERVER_HEADER, C as CLIENT_HEADER } from './browser-VjxLaeuu.mjs';
2
+ export { c as CURRENT_PROTOCOL_VERSION, d as decodeServerHeader, a as setLogLevel, b as setLogTransport } from './browser-VjxLaeuu.mjs';
3
3
  import { Buffer } from 'node:buffer';
4
4
  import { verify as verify$1, randomBytes, sign as sign$1, createPublicKey, createPrivateKey } from 'node:crypto';
5
5
 
6
+ const DEFAULT_CACHE_CONFIG = {
7
+ enabled: true,
8
+ maxSize: 100,
9
+ ttl: 5e3
10
+ // 5 seconds
11
+ };
12
+ let cacheConfig = { ...DEFAULT_CACHE_CONFIG };
13
+ function configureCaching(config) {
14
+ if (config.ttl !== void 0 && config.ttl < 0) {
15
+ throw new Error("Cache TTL must be >= 0");
16
+ }
17
+ if (config.maxSize !== void 0 && config.maxSize < 1) {
18
+ throw new Error("Cache maxSize must be >= 1");
19
+ }
20
+ cacheConfig = { ...cacheConfig, ...config };
21
+ if (!cacheConfig.enabled) {
22
+ headerCache.clear();
23
+ }
24
+ trimCache();
25
+ log("debug", "Cache configuration updated", cacheConfig);
26
+ }
27
+ function getCacheConfig() {
28
+ return { ...cacheConfig };
29
+ }
30
+ const headerCache = /* @__PURE__ */ new Map();
31
+ function trimCache() {
32
+ if (headerCache.size <= cacheConfig.maxSize) return;
33
+ const entriesToRemove = headerCache.size - cacheConfig.maxSize;
34
+ const entries = Array.from(headerCache.entries());
35
+ entries.sort((a, b) => {
36
+ if (a[1].accessCount !== b[1].accessCount) {
37
+ return a[1].accessCount - b[1].accessCount;
38
+ }
39
+ return a[1].timestamp - b[1].timestamp;
40
+ });
41
+ for (let i = 0; i < entriesToRemove; i++) {
42
+ headerCache.delete(entries[i][0]);
43
+ }
44
+ }
45
+ function cleanExpiredEntries(now) {
46
+ for (const [key, entry] of headerCache.entries()) {
47
+ if (entry.effectiveExpiry <= now) {
48
+ headerCache.delete(key);
49
+ }
50
+ }
51
+ }
52
+
6
53
  const keyCache = /* @__PURE__ */ new Map();
7
54
  function sign(data, privateKey) {
8
55
  const key = importPrivateKey(privateKey);
9
- return sign$1(null, Buffer.from(data), key);
56
+ return new Promise((resolve, reject) => {
57
+ sign$1(null, Buffer.from(data), key, (err, result) => {
58
+ if (err) reject(err);
59
+ else resolve(result);
60
+ });
61
+ });
10
62
  }
11
63
  function verify(data, signature, publicKey) {
12
64
  const key = importPublicKey(publicKey);
13
- return verify$1(null, Buffer.from(data), key, Buffer.from(signature));
65
+ return new Promise((resolve, reject) => {
66
+ verify$1(null, Buffer.from(data), key, Buffer.from(signature), (err, result) => {
67
+ if (err) reject(err);
68
+ else resolve(result);
69
+ });
70
+ });
14
71
  }
15
72
  const nonce = (size) => new Uint8Array(randomBytes(size));
16
73
  function importPrivateKey(privateKeyBase64) {
@@ -37,55 +94,132 @@ function importPublicKey(publicKeyBase64) {
37
94
  const VERSION_BYTES = 1;
38
95
  const NONCE_BYTES = 4;
39
96
  const SEPARATOR = ".";
40
- const FEATURES_TO_ACTIONS = {
41
- [FEATURES.CLEAN_WEB]: [
97
+ const UINT32_BYTES = 4;
98
+ const FEATURE_TO_ACTIONS = Object.freeze({
99
+ [FEATURE.CLEAN_WEB]: Object.freeze([
42
100
  "HIDE_ADVERTISEMENTS",
43
101
  "HIDE_COOKIE_CONSENT_SCREEN",
44
102
  "HIDE_MARKETING_DIALOGS",
45
103
  "DISABLE_NON_FUNCTIONAL_TRACKING"
46
- ],
47
- [FEATURES.ONE_PASS]: ["DISABLE_CONTENT_PAYWALL", "ENABLE_SUBSCRIPTION_ACCESS"]
48
- };
49
- function parseClientToken(headerValue, options) {
104
+ ]),
105
+ [FEATURE.ONE_PASS]: Object.freeze([
106
+ "DISABLE_CONTENT_PAYWALL",
107
+ "ENABLE_SUBSCRIPTION_ACCESS"
108
+ ])
109
+ });
110
+ const FEATURE_NUMBERS = Object.freeze([FEATURE.CLEAN_WEB, FEATURE.ONE_PASS]);
111
+ const EMPTY_CONTEXT = Object.freeze({
112
+ HIDE_ADVERTISEMENTS: false,
113
+ HIDE_COOKIE_CONSENT_SCREEN: false,
114
+ HIDE_MARKETING_DIALOGS: false,
115
+ DISABLE_NON_FUNCTIONAL_TRACKING: false,
116
+ DISABLE_CONTENT_PAYWALL: false,
117
+ ENABLE_SUBSCRIPTION_ACCESS: false
118
+ });
119
+ function createEmptyContext() {
120
+ return EMPTY_CONTEXT;
121
+ }
122
+ async function parseClientToken(headerValue, options) {
123
+ if (!headerValue || Array.isArray(headerValue) && !headerValue.length) {
124
+ return createEmptyContext();
125
+ }
50
126
  const headerValueAsString = Array.isArray(headerValue) ? headerValue[0] : headerValue;
51
- const data = decodeClientHeader(headerValueAsString, options.publicKey || ZEROAD_NETWORK_PUBLIC_KEY);
127
+ const now = Date.now();
128
+ if (cacheConfig.enabled && !options.bypassCache) {
129
+ const cached = headerCache.get(headerValueAsString);
130
+ if (cached && cached.effectiveExpiry > now) {
131
+ cached.accessCount++;
132
+ return buildContext(cached.data, options, now);
133
+ } else if (cached) {
134
+ headerCache.delete(headerValueAsString);
135
+ }
136
+ }
137
+ const data = await decodeClientHeader(headerValueAsString, options.publicKey || ZEROAD_NETWORK_PUBLIC_KEY);
138
+ if (cacheConfig.enabled && !options.bypassCache) {
139
+ const cacheTTLExpiry = now + cacheConfig.ttl;
140
+ const tokenExpiry = data?.expiresAt.getTime() ?? 0;
141
+ const effectiveExpiry = tokenExpiry > 0 ? Math.min(cacheTTLExpiry, tokenExpiry) : cacheTTLExpiry;
142
+ headerCache.set(headerValueAsString, {
143
+ data,
144
+ timestamp: now,
145
+ accessCount: 1,
146
+ effectiveExpiry
147
+ });
148
+ if (headerCache.size > 0 && headerCache.size % 100 === 0) {
149
+ cleanExpiredEntries(now);
150
+ }
151
+ trimCache();
152
+ }
153
+ return buildContext(data, options, now);
154
+ }
155
+ function buildContext(data, options, now) {
52
156
  let flags = 0;
53
- if (data && data.expiresAt.getTime() >= Date.now()) flags = data.flags;
54
- if (flags && data?.clientId && data.clientId !== options.clientId) flags = 0;
55
- const context = /* @__PURE__ */ new Map();
56
- for (const [feature, actionNames] of Object.entries(FEATURES_TO_ACTIONS)) {
57
- const decision = options.features.includes(Number(feature)) && hasFlag(Number(feature), flags);
58
- for (const actionName of actionNames) {
59
- context.set(actionName, decision);
157
+ if (data && data.expiresAt.getTime() >= now) {
158
+ if (!data.clientId || data.clientId === options.clientId) {
159
+ flags = data.flags;
60
160
  }
61
161
  }
62
- return Object.fromEntries(context);
162
+ if (!flags) {
163
+ return createEmptyContext();
164
+ }
165
+ const featuresSet = options.features.length <= 2 ? options.features : new Set(options.features);
166
+ const context = {};
167
+ for (let i = 0; i < FEATURE_NUMBERS.length; i++) {
168
+ const feature = FEATURE_NUMBERS[i];
169
+ const actionNames = FEATURE_TO_ACTIONS[feature];
170
+ const isEnabled = (Array.isArray(featuresSet) ? featuresSet.includes(feature) : featuresSet.has(feature)) && (flags & feature) !== 0;
171
+ const len = actionNames.length;
172
+ if (len > 0) context[actionNames[0]] = isEnabled;
173
+ if (len > 1) context[actionNames[1]] = isEnabled;
174
+ if (len > 2) context[actionNames[2]] = isEnabled;
175
+ if (len > 3) context[actionNames[3]] = isEnabled;
176
+ }
177
+ return context;
63
178
  }
64
- function decodeClientHeader(headerValue, publicKey) {
65
- if (!headerValue?.length) return;
179
+ async function decodeClientHeader(headerValue, publicKey) {
180
+ if (!headerValue?.length) return void 0;
66
181
  try {
67
- const [data, signature] = headerValue.split(SEPARATOR);
182
+ const separatorIndex = headerValue.indexOf(SEPARATOR);
183
+ if (separatorIndex === -1) {
184
+ throw new Error("Invalid header format: missing separator");
185
+ }
186
+ const data = headerValue.substring(0, separatorIndex);
187
+ const signature = headerValue.substring(separatorIndex + 1);
68
188
  const dataBytes = fromBase64(data);
69
189
  const signatureBytes = fromBase64(signature);
70
- if (!verify(dataBytes.buffer, signatureBytes.buffer, publicKey)) {
190
+ if (!await verify(dataBytes.buffer, signatureBytes.buffer, publicKey)) {
71
191
  throw new Error("Forged header value is provided");
72
192
  }
73
193
  const version = dataBytes[0];
74
- let clientId;
75
194
  if (version === PROTOCOL_VERSION.V_1) {
76
- const expiresAt = as32BitNumber(dataBytes, VERSION_BYTES + NONCE_BYTES);
77
- const flags = as32BitNumber(dataBytes, VERSION_BYTES + NONCE_BYTES + Uint32Array.BYTES_PER_ELEMENT);
78
- const expectedByteLength = VERSION_BYTES + NONCE_BYTES + Uint32Array.BYTES_PER_ELEMENT * 2;
79
- if (dataBytes.byteLength > expectedByteLength) {
80
- clientId = new TextDecoder().decode(dataBytes.subarray(expectedByteLength));
195
+ const expectedMinLength = VERSION_BYTES + NONCE_BYTES + UINT32_BYTES * 2;
196
+ if (dataBytes.byteLength < expectedMinLength) {
197
+ throw new Error("Invalid data length");
81
198
  }
82
- return { version, expiresAt: new Date(expiresAt * 1e3), flags, ...clientId && { clientId } };
199
+ const view = new DataView(dataBytes.buffer, dataBytes.byteOffset, dataBytes.byteLength);
200
+ const expiresAtOffset = VERSION_BYTES + NONCE_BYTES;
201
+ const flagsOffset = expiresAtOffset + UINT32_BYTES;
202
+ const expiresAt = view.getUint32(expiresAtOffset, true);
203
+ const flags = view.getUint32(flagsOffset, true);
204
+ let clientId;
205
+ if (dataBytes.byteLength > expectedMinLength) {
206
+ const clientIdBytes = dataBytes.subarray(expectedMinLength);
207
+ clientId = new TextDecoder().decode(clientIdBytes);
208
+ }
209
+ return {
210
+ version,
211
+ expiresAt: new Date(expiresAt * 1e3),
212
+ flags,
213
+ ...clientId && { clientId }
214
+ };
83
215
  }
216
+ throw new Error(`Unsupported protocol version: ${version}`);
84
217
  } catch (err) {
85
218
  log("warn", "Could not decode client header value", { reason: err?.message });
219
+ return void 0;
86
220
  }
87
221
  }
88
- function encodeClientHeader(data, privateKey) {
222
+ async function encodeClientHeader(data, privateKey) {
89
223
  const payload = mergeByteArrays([
90
224
  new Uint8Array([data.version]),
91
225
  new Uint8Array(nonce(NONCE_BYTES)),
@@ -93,7 +227,7 @@ function encodeClientHeader(data, privateKey) {
93
227
  new Uint32Array([setFlags(data.features)]),
94
228
  ...data.clientId?.length ? [new Uint8Array(new TextEncoder().encode(data.clientId))] : []
95
229
  ]);
96
- return [toBase64(payload), toBase64(new Uint8Array(sign(payload.buffer, privateKey)))].join(SEPARATOR);
230
+ return [toBase64(payload), toBase64(new Uint8Array(await sign(payload.buffer, privateKey)))].join(SEPARATOR);
97
231
  }
98
232
  function mergeByteArrays(arrays) {
99
233
  const totalLength = arrays.reduce((sum, a) => sum + a.byteLength, 0);
@@ -109,20 +243,18 @@ function mergeByteArrays(arrays) {
109
243
  }
110
244
  return data;
111
245
  }
112
- function as32BitNumber(byteArray, begin) {
113
- const bytes = byteArray.subarray(begin, begin + Uint32Array.BYTES_PER_ELEMENT);
114
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
115
- return view.getUint32(0, true);
116
- }
117
246
 
118
247
  function Site(options) {
119
248
  const serverHeaderValue = encodeServerHeader(options.clientId, options.features);
249
+ if (options.cacheConfig) {
250
+ configureCaching(options.cacheConfig);
251
+ }
120
252
  return {
121
253
  parseClientToken: (headerValue) => parseClientToken(headerValue, { clientId: options.clientId, features: options.features }),
122
- CLIENT_HEADER_NAME: CLIENT_HEADERS.HELLO.toLowerCase(),
123
- SERVER_HEADER_NAME: SERVER_HEADERS.WELCOME,
254
+ CLIENT_HEADER_NAME: CLIENT_HEADER.HELLO.toLowerCase(),
255
+ SERVER_HEADER_NAME: SERVER_HEADER.WELCOME,
124
256
  SERVER_HEADER_VALUE: serverHeaderValue
125
257
  };
126
258
  }
127
259
 
128
- export { CLIENT_HEADERS, FEATURES, PROTOCOL_VERSION, SERVER_HEADERS, Site, ZEROAD_NETWORK_PUBLIC_KEY, decodeClientHeader, encodeClientHeader, encodeServerHeader, parseClientToken };
260
+ export { CLIENT_HEADER, FEATURE, PROTOCOL_VERSION, SERVER_HEADER, Site, ZEROAD_NETWORK_PUBLIC_KEY, cacheConfig, cleanExpiredEntries, configureCaching, decodeClientHeader, encodeClientHeader, encodeServerHeader, getCacheConfig, headerCache, parseClientToken, trimCache };
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "@zeroad.network/token",
3
- "version": "0.13.12",
3
+ "version": "0.14.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": "github:laurynas-karvelis/zeroad-token-typescript",
6
6
  "homepage": "https://zeroad.network",
7
- "private": false,
8
7
  "author": {
9
8
  "name": "Laurynas Karvelis <Explosive Brains Ltd>",
10
9
  "email": "hello@zeroad.network",
@@ -70,13 +69,13 @@
70
69
  "scripts": {
71
70
  "keys:generate": "bun run ./src/tools/cli.ts",
72
71
  "prettier": "prettier . --write",
73
- "build": "pkgroll --target=node18",
72
+ "build": "pkgroll --target=esnext --target=node18",
74
73
  "test": "bun test ./src"
75
74
  },
76
75
  "dependencies": {},
77
76
  "devDependencies": {
78
77
  "@types/bun": "^1.3.4",
79
- "@types/node": "^24.10.2",
78
+ "@types/node": "^25.0.1",
80
79
  "pkgroll": "^2.21.4",
81
80
  "prettier": "^3.7.4",
82
81
  "typescript": "^5.9.3"