perspectapi-ts-sdk 6.4.1 → 6.5.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/dist/index.d.mts CHANGED
@@ -1405,7 +1405,7 @@ interface V2OrderLineItemPriceData {
1405
1405
  }
1406
1406
  interface V2OrderLineItem {
1407
1407
  sku_id?: number;
1408
- product_id?: number;
1408
+ product_id?: string | number;
1409
1409
  price_data?: V2OrderLineItemPriceData;
1410
1410
  price?: string;
1411
1411
  quantity: number;
package/dist/index.d.ts CHANGED
@@ -1405,7 +1405,7 @@ interface V2OrderLineItemPriceData {
1405
1405
  }
1406
1406
  interface V2OrderLineItem {
1407
1407
  sku_id?: number;
1408
- product_id?: number;
1408
+ product_id?: string | number;
1409
1409
  price_data?: V2OrderLineItemPriceData;
1410
1410
  price?: string;
1411
1411
  quantity: number;
package/dist/index.js CHANGED
@@ -4259,15 +4259,16 @@ function createPerspectAb(options) {
4259
4259
  `${VID_COOKIE}=${visitorId}; Path=/; Max-Age=${VID_COOKIE_MAX_AGE}; SameSite=Lax; Secure; HttpOnly`
4260
4260
  );
4261
4261
  }
4262
+ const isBot = classifyBotFromCfRequest(request);
4262
4263
  const config = await getConfig(options.cache, apiKey, siteName, baseUrl);
4263
- return { ab: buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId), responseHeaders };
4264
+ return { ab: buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot), responseHeaders };
4264
4265
  },
4265
4266
  async refreshConfig() {
4266
4267
  await fetchAndStoreConfig(options.cache, apiKey, siteName, baseUrl);
4267
4268
  }
4268
4269
  };
4269
4270
  }
4270
- function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId) {
4271
+ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot) {
4271
4272
  return {
4272
4273
  async getVariant(flagKey) {
4273
4274
  const flag = config.flags[flagKey];
@@ -4287,6 +4288,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId) {
4287
4288
  version: flag.currentVersion,
4288
4289
  variant: assigned,
4289
4290
  visitorId,
4291
+ isBot,
4290
4292
  dedup: await dedupFor(visitorId, flagKey, flag.currentVersion, assigned, "exposure"),
4291
4293
  ts: Math.floor(Date.now() / 1e3)
4292
4294
  });
@@ -4307,6 +4309,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId) {
4307
4309
  version: flag.currentVersion,
4308
4310
  variant: assigned,
4309
4311
  visitorId,
4312
+ isBot,
4310
4313
  event,
4311
4314
  dedup: await dedupFor(visitorId, flagKey, flag.currentVersion, assigned, event),
4312
4315
  ts: Math.floor(Date.now() / 1e3),
@@ -4345,6 +4348,13 @@ function emit(apiKey, baseUrl, ctx, body) {
4345
4348
  }).then(() => void 0).catch(() => void 0);
4346
4349
  if (ctx) ctx.waitUntil(task);
4347
4350
  }
4351
+ function classifyBotFromCfRequest(request) {
4352
+ const cf = request.cf;
4353
+ if (!cf?.botManagement) return false;
4354
+ if (cf.botManagement.verifiedBot) return true;
4355
+ if (typeof cf.botManagement.score === "number") return cf.botManagement.score < 30;
4356
+ return false;
4357
+ }
4348
4358
  function readOrMintVid(request) {
4349
4359
  const cookie = request.headers.get("cookie") ?? "";
4350
4360
  const match = cookie.match(/(?:^|; )perspect_vid=([^;]+)/);
package/dist/index.mjs CHANGED
@@ -4183,15 +4183,16 @@ function createPerspectAb(options) {
4183
4183
  `${VID_COOKIE}=${visitorId}; Path=/; Max-Age=${VID_COOKIE_MAX_AGE}; SameSite=Lax; Secure; HttpOnly`
4184
4184
  );
4185
4185
  }
4186
+ const isBot = classifyBotFromCfRequest(request);
4186
4187
  const config = await getConfig(options.cache, apiKey, siteName, baseUrl);
4187
- return { ab: buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId), responseHeaders };
4188
+ return { ab: buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot), responseHeaders };
4188
4189
  },
4189
4190
  async refreshConfig() {
4190
4191
  await fetchAndStoreConfig(options.cache, apiKey, siteName, baseUrl);
4191
4192
  }
4192
4193
  };
4193
4194
  }
4194
- function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId) {
4195
+ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot) {
4195
4196
  return {
4196
4197
  async getVariant(flagKey) {
4197
4198
  const flag = config.flags[flagKey];
@@ -4211,6 +4212,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId) {
4211
4212
  version: flag.currentVersion,
4212
4213
  variant: assigned,
4213
4214
  visitorId,
4215
+ isBot,
4214
4216
  dedup: await dedupFor(visitorId, flagKey, flag.currentVersion, assigned, "exposure"),
4215
4217
  ts: Math.floor(Date.now() / 1e3)
4216
4218
  });
@@ -4231,6 +4233,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId) {
4231
4233
  version: flag.currentVersion,
4232
4234
  variant: assigned,
4233
4235
  visitorId,
4236
+ isBot,
4234
4237
  event,
4235
4238
  dedup: await dedupFor(visitorId, flagKey, flag.currentVersion, assigned, event),
4236
4239
  ts: Math.floor(Date.now() / 1e3),
@@ -4269,6 +4272,13 @@ function emit(apiKey, baseUrl, ctx, body) {
4269
4272
  }).then(() => void 0).catch(() => void 0);
4270
4273
  if (ctx) ctx.waitUntil(task);
4271
4274
  }
4275
+ function classifyBotFromCfRequest(request) {
4276
+ const cf = request.cf;
4277
+ if (!cf?.botManagement) return false;
4278
+ if (cf.botManagement.verifiedBot) return true;
4279
+ if (typeof cf.botManagement.score === "number") return cf.botManagement.score < 30;
4280
+ return false;
4281
+ }
4272
4282
  function readOrMintVid(request) {
4273
4283
  const cookie = request.headers.get("cookie") ?? "";
4274
4284
  const match = cookie.match(/(?:^|; )perspect_vid=([^;]+)/);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perspectapi-ts-sdk",
3
- "version": "6.4.1",
3
+ "version": "6.5.1",
4
4
  "description": "TypeScript SDK for PerspectAPI - Cloudflare Workers compatible",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -88,8 +88,9 @@ export function createPerspectAb(options: CreatePerspectAbOptions): PerspectAb {
88
88
  `${VID_COOKIE}=${visitorId}; Path=/; Max-Age=${VID_COOKIE_MAX_AGE}; SameSite=Lax; Secure; HttpOnly`,
89
89
  );
90
90
  }
91
+ const isBot = classifyBotFromCfRequest(request);
91
92
  const config = await getConfig(options.cache, apiKey, siteName, baseUrl);
92
- return { ab: buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId), responseHeaders };
93
+ return { ab: buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot), responseHeaders };
93
94
  },
94
95
 
95
96
  async refreshConfig(): Promise<void> {
@@ -109,6 +110,7 @@ function buildAbClient(
109
110
  ctx: { waitUntil(p: Promise<unknown>): void } | undefined,
110
111
  config: AbConfigBlob,
111
112
  visitorId: string,
113
+ isBot: boolean,
112
114
  ): AbClient {
113
115
  return {
114
116
  async getVariant(flagKey: string): Promise<AbVariantResult> {
@@ -129,6 +131,7 @@ function buildAbClient(
129
131
  version: flag.currentVersion,
130
132
  variant: assigned,
131
133
  visitorId,
134
+ isBot,
132
135
  dedup: await dedupFor(visitorId, flagKey, flag.currentVersion, assigned, 'exposure'),
133
136
  ts: Math.floor(Date.now() / 1000),
134
137
  });
@@ -150,6 +153,7 @@ function buildAbClient(
150
153
  version: flag.currentVersion,
151
154
  variant: assigned,
152
155
  visitorId,
156
+ isBot,
153
157
  event,
154
158
  dedup: await dedupFor(visitorId, flagKey, flag.currentVersion, assigned, event),
155
159
  ts: Math.floor(Date.now() / 1000),
@@ -209,6 +213,7 @@ interface EventBody {
209
213
  version: number;
210
214
  variant: string;
211
215
  visitorId: string;
216
+ isBot: boolean;
212
217
  dedup: string;
213
218
  ts: number;
214
219
  event?: string;
@@ -231,6 +236,21 @@ function emit(
231
236
  if (ctx) ctx.waitUntil(task);
232
237
  }
233
238
 
239
+ // ---------------------------------------------------------------------------
240
+ // Bot classification from CF request metadata
241
+ // ---------------------------------------------------------------------------
242
+
243
+ // CF Workers attach botManagement to the request object at runtime. The SDK
244
+ // uses the standard Request type, so we access it via an unsafe cast rather
245
+ // than importing CF-specific types as a peer dependency.
246
+ function classifyBotFromCfRequest(request: Request): boolean {
247
+ const cf = (request as unknown as { cf?: { botManagement?: { score?: number; verifiedBot?: boolean } } }).cf;
248
+ if (!cf?.botManagement) return false;
249
+ if (cf.botManagement.verifiedBot) return true;
250
+ if (typeof cf.botManagement.score === 'number') return cf.botManagement.score < 30;
251
+ return false;
252
+ }
253
+
234
254
  // ---------------------------------------------------------------------------
235
255
  // Visitor ID
236
256
  // ---------------------------------------------------------------------------
package/src/v2/types.ts CHANGED
@@ -266,7 +266,7 @@ export interface V2OrderLineItemPriceData {
266
266
 
267
267
  export interface V2OrderLineItem {
268
268
  sku_id?: number;
269
- product_id?: number;
269
+ product_id?: string | number;
270
270
  price_data?: V2OrderLineItemPriceData;
271
271
  price?: string;
272
272
  quantity: number;