@coframe/sdk 1.1.9 → 1.1.10

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/README.md CHANGED
@@ -40,6 +40,21 @@ await init({
40
40
 
41
41
  `init()` accepts `config` and optional `projectData`, so npm consumers do not need to manually populate `window.CFQ` first.
42
42
 
43
+ ### URL controls
44
+
45
+ The npm entry uses the same browser URL controls as the script-tag and Edge
46
+ installations:
47
+
48
+ - `cf_disable` skips initialization and reveals any antiflicker state.
49
+ - `coframe_variant_id` previews one or more comma-separated variant IDs.
50
+ - `keep_preview_for_session=true` keeps that preview active for the tab.
51
+ - `coframe_should_send_events=true` allows events during preview for testing.
52
+
53
+ For SSR, pass the complete request URL, including its query string, as
54
+ `currentUrl`. This is required for query-sensitive targeting and allows
55
+ `getProjectData()` to short-circuit before any request when `cf_disable` is
56
+ present.
57
+
43
58
  ### React
44
59
 
45
60
  ```tsx
@@ -60,6 +75,8 @@ export default function App({ children }) {
60
75
  ```
61
76
 
62
77
  Mount the provider once at the root of your app. It initializes the SDK on mount and keeps treatment state available to child components.
78
+ Keep it mounted across client-side route changes; runtime commands and the SDK's
79
+ navigation observer handle subsequent page changes without remounting it.
63
80
 
64
81
  ### Server prefetch
65
82
 
@@ -148,6 +165,10 @@ import { CoframeProvider } from '@coframe/sdk/react'
148
165
  </CoframeProvider>
149
166
  ```
150
167
 
168
+ If your privacy policy permits treatment analytics before cookie consent, use
169
+ `onTreatmentAppliedBulkV2WithoutConsent` instead. It has the same callback
170
+ arguments and does not fire again when consent is later granted.
171
+
151
172
  Outside React, you can also register callbacks from the main entry:
152
173
 
153
174
  ```ts
@@ -159,6 +180,7 @@ import { onLog, onTreatmentApplied } from '@coframe/sdk'
159
180
  - `getProjectData()` is intended for SSR and edge runtimes that can provide a full request URL and request headers.
160
181
  - In Pages Router or Remix, per-request server loaders are the most straightforward place to call it.
161
182
  - In App Router, keep the provider mounted in a persistent shell, but be careful about request URL handling in `layout.tsx` if you need query-sensitive SSR targeting.
183
+ - The npm runtime reveals antiflicker styles but cannot insert them early enough to protect the initial paint. Render `antiflickerCSS` from `getProjectData()` in the server document head, or place equivalent static CSS and a timeout fallback there before application content.
162
184
 
163
185
  ## Package layout
164
186
 
@@ -1823,6 +1823,7 @@ const waitForBody = (timeout = 10000) => {
1823
1823
  function revealPage() {
1824
1824
  document.dispatchEvent(new CustomEvent('coframe:show', {}));
1825
1825
  document.documentElement.style.setProperty('--cf-show', '1');
1826
+ document.documentElement.style.setProperty('--cf-visibility', 'visible');
1826
1827
  }
1827
1828
  async function replaceVariants(variants, orgId, logger, nonce) {
1828
1829
  const failedReplacements = [];
@@ -3646,6 +3647,12 @@ const Coframe = {
3646
3647
  };
3647
3648
  Coframe.logger = createLogger(() => Coframe);
3648
3649
  async function init(options) {
3650
+ if (typeof window !== 'undefined' &&
3651
+ /cf_disable/.test(window.location.search)) {
3652
+ console.warn('[Coframe] Disabled via URL parameter');
3653
+ revealPage();
3654
+ return;
3655
+ }
3649
3656
  if (options)
3650
3657
  injectOptions(options);
3651
3658
  const gracefulExit = (msg) => {
@@ -1821,6 +1821,7 @@ const waitForBody = (timeout = 10000) => {
1821
1821
  function revealPage() {
1822
1822
  document.dispatchEvent(new CustomEvent('coframe:show', {}));
1823
1823
  document.documentElement.style.setProperty('--cf-show', '1');
1824
+ document.documentElement.style.setProperty('--cf-visibility', 'visible');
1824
1825
  }
1825
1826
  async function replaceVariants(variants, orgId, logger, nonce) {
1826
1827
  const failedReplacements = [];
@@ -3644,6 +3645,12 @@ const Coframe = {
3644
3645
  };
3645
3646
  Coframe.logger = createLogger(() => Coframe);
3646
3647
  async function init(options) {
3648
+ if (typeof window !== 'undefined' &&
3649
+ /cf_disable/.test(window.location.search)) {
3650
+ console.warn('[Coframe] Disabled via URL parameter');
3651
+ revealPage();
3652
+ return;
3653
+ }
3647
3654
  if (options)
3648
3655
  injectOptions(options);
3649
3656
  const gracefulExit = (msg) => {
@@ -5,10 +5,17 @@ var sdk = require('@coframe/sdk');
5
5
  var React = require('react');
6
6
 
7
7
  const CoframeContext = React.createContext({ treatments: null });
8
- function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTreatmentAppliedProp, onTreatmentAppliedBulk: onTreatmentAppliedBulkProp, onTreatmentAppliedBulkV2, onLog: onLogProp, children, }) {
8
+ function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTreatmentAppliedProp, onTreatmentAppliedBulk: onTreatmentAppliedBulkProp, onTreatmentAppliedBulkV2, onTreatmentAppliedBulkV2WithoutConsent, onLog: onLogProp, children, }) {
9
9
  const [treatments, setTreatments] = React.useState(null);
10
10
  React.useEffect(() => {
11
11
  var _a, _b;
12
+ if (/cf_disable/.test(window.location.search)) {
13
+ sdk.init().catch((e) => {
14
+ console.error('[Coframe] Error disabling SDK', e);
15
+ });
16
+ setTreatments([]);
17
+ return;
18
+ }
12
19
  sdk.onTreatmentApplied({
13
20
  callback: onTreatmentAppliedProp,
14
21
  bulkCallback: (data) => {
@@ -16,6 +23,7 @@ function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTre
16
23
  onTreatmentAppliedBulkProp === null || onTreatmentAppliedBulkProp === void 0 ? void 0 : onTreatmentAppliedBulkProp(data);
17
24
  },
18
25
  bulkCallbackV2: onTreatmentAppliedBulkV2,
26
+ bulkCallbackV2WithoutConsent: onTreatmentAppliedBulkV2WithoutConsent,
19
27
  });
20
28
  if (onLogProp) {
21
29
  sdk.onLog(onLogProp);
@@ -1,13 +1,20 @@
1
1
  'use client';
2
- import { onTreatmentApplied, onLog, init } from '@coframe/sdk';
2
+ import { init, onTreatmentApplied, onLog } from '@coframe/sdk';
3
3
  export { init, onLog, onTreatmentApplied, setConsent, setFeatureFlag, setPageHydrated, setUserToken, trackConversion } from '@coframe/sdk';
4
4
  import React, { createContext, useState, useEffect, useContext } from 'react';
5
5
 
6
6
  const CoframeContext = createContext({ treatments: null });
7
- function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTreatmentAppliedProp, onTreatmentAppliedBulk: onTreatmentAppliedBulkProp, onTreatmentAppliedBulkV2, onLog: onLogProp, children, }) {
7
+ function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTreatmentAppliedProp, onTreatmentAppliedBulk: onTreatmentAppliedBulkProp, onTreatmentAppliedBulkV2, onTreatmentAppliedBulkV2WithoutConsent, onLog: onLogProp, children, }) {
8
8
  const [treatments, setTreatments] = useState(null);
9
9
  useEffect(() => {
10
10
  var _a, _b;
11
+ if (/cf_disable/.test(window.location.search)) {
12
+ init().catch((e) => {
13
+ console.error('[Coframe] Error disabling SDK', e);
14
+ });
15
+ setTreatments([]);
16
+ return;
17
+ }
11
18
  onTreatmentApplied({
12
19
  callback: onTreatmentAppliedProp,
13
20
  bulkCallback: (data) => {
@@ -15,6 +22,7 @@ function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTre
15
22
  onTreatmentAppliedBulkProp === null || onTreatmentAppliedBulkProp === void 0 ? void 0 : onTreatmentAppliedBulkProp(data);
16
23
  },
17
24
  bulkCallbackV2: onTreatmentAppliedBulkV2,
25
+ bulkCallbackV2WithoutConsent: onTreatmentAppliedBulkV2WithoutConsent,
18
26
  });
19
27
  if (onLogProp) {
20
28
  onLog(onLogProp);
@@ -45,14 +45,14 @@ async function fetchProjectFromEdge(projectId, currentUrl, signal, userContext,
45
45
  }
46
46
  }
47
47
 
48
- async function fetchAntiflickerFromEdge(projectId, currentUrl, userContext, enableElementAntiFlicker, headers) {
48
+ async function fetchAntiflickerFromEdge(projectId, currentUrl, userContext, antiflickerMode, headers) {
49
49
  try {
50
50
  const payload = { projectId, currentUrl };
51
51
  if (userContext) {
52
52
  payload.userContext = userContext;
53
53
  }
54
- if (enableElementAntiFlicker) {
55
- payload.enableElementAntiFlicker = enableElementAntiFlicker;
54
+ if (antiflickerMode) {
55
+ payload.antiflickerMode = antiflickerMode;
56
56
  }
57
57
  const config = encodeURIComponent(JSON.stringify(payload));
58
58
  const edgeUrl = new URL(`${"https://edge.cofra.me"}/cf.css`);
@@ -69,6 +69,13 @@ async function fetchAntiflickerFromEdge(projectId, currentUrl, userContext, enab
69
69
  }
70
70
  }
71
71
  async function getProjectData(options) {
72
+ try {
73
+ if (/cf_disable/.test(new URL(options.currentUrl).search)) {
74
+ return null;
75
+ }
76
+ }
77
+ catch (_a) {
78
+ }
72
79
  const includeProject = options.includeProject !== false;
73
80
  const includeCSS = options.includeCSS !== false;
74
81
  const [projectResult, antiflickerCSS] = await Promise.all([
@@ -76,7 +83,7 @@ async function getProjectData(options) {
76
83
  ? fetchProjectFromEdge(options.projectId, options.currentUrl, undefined, options.userContext, undefined, options.headers)
77
84
  : Promise.resolve(null),
78
85
  includeCSS
79
- ? fetchAntiflickerFromEdge(options.projectId, options.currentUrl, options.userContext, options.enableElementAntiFlicker, options.headers)
86
+ ? fetchAntiflickerFromEdge(options.projectId, options.currentUrl, options.userContext, options.antiflickerMode, options.headers)
80
87
  : Promise.resolve(null),
81
88
  ]);
82
89
  const config = {};
@@ -43,14 +43,14 @@ async function fetchProjectFromEdge(projectId, currentUrl, signal, userContext,
43
43
  }
44
44
  }
45
45
 
46
- async function fetchAntiflickerFromEdge(projectId, currentUrl, userContext, enableElementAntiFlicker, headers) {
46
+ async function fetchAntiflickerFromEdge(projectId, currentUrl, userContext, antiflickerMode, headers) {
47
47
  try {
48
48
  const payload = { projectId, currentUrl };
49
49
  if (userContext) {
50
50
  payload.userContext = userContext;
51
51
  }
52
- if (enableElementAntiFlicker) {
53
- payload.enableElementAntiFlicker = enableElementAntiFlicker;
52
+ if (antiflickerMode) {
53
+ payload.antiflickerMode = antiflickerMode;
54
54
  }
55
55
  const config = encodeURIComponent(JSON.stringify(payload));
56
56
  const edgeUrl = new URL(`${"https://edge.cofra.me"}/cf.css`);
@@ -67,6 +67,13 @@ async function fetchAntiflickerFromEdge(projectId, currentUrl, userContext, enab
67
67
  }
68
68
  }
69
69
  async function getProjectData(options) {
70
+ try {
71
+ if (/cf_disable/.test(new URL(options.currentUrl).search)) {
72
+ return null;
73
+ }
74
+ }
75
+ catch (_a) {
76
+ }
70
77
  const includeProject = options.includeProject !== false;
71
78
  const includeCSS = options.includeCSS !== false;
72
79
  const [projectResult, antiflickerCSS] = await Promise.all([
@@ -74,7 +81,7 @@ async function getProjectData(options) {
74
81
  ? fetchProjectFromEdge(options.projectId, options.currentUrl, undefined, options.userContext, undefined, options.headers)
75
82
  : Promise.resolve(null),
76
83
  includeCSS
77
- ? fetchAntiflickerFromEdge(options.projectId, options.currentUrl, options.userContext, options.enableElementAntiFlicker, options.headers)
84
+ ? fetchAntiflickerFromEdge(options.projectId, options.currentUrl, options.userContext, options.antiflickerMode, options.headers)
78
85
  : Promise.resolve(null),
79
86
  ]);
80
87
  const config = {};
@@ -230,12 +230,13 @@ type ActivationCondition = {
230
230
  allocation?: ActivationConditionAllocation;
231
231
  js_function?: string;
232
232
  };
233
+ type AntiflickerMode = 'body' | 'include' | 'exclude';
233
234
  type CoframeConfig = {
234
235
  projectId: string;
235
236
  previewVariantId?: string;
236
237
  trackingOnly?: boolean;
237
238
  enableAntiFlickering?: boolean;
238
- enableElementAntiFlicker?: boolean;
239
+ antiflickerMode?: AntiflickerMode;
239
240
  waitForHydration?: boolean;
240
241
  waitForCookiesEnabled?: boolean;
241
242
  waitForFeatureFlag?: boolean;
@@ -295,6 +296,7 @@ interface TreatmentAppliedHandlers {
295
296
  callback?: (data: TreatmentData) => void;
296
297
  bulkCallback?: (data: TreatmentData[]) => void;
297
298
  bulkCallbackV2?: (data: TreatmentDataV2[], rawIds: ExperimentInfo[]) => void;
299
+ bulkCallbackV2WithoutConsent?: (data: TreatmentDataV2[], rawIds: ExperimentInfo[]) => void;
298
300
  }
299
301
  declare function setConsent(enabled: boolean): void;
300
302
  declare function setUserToken(token: string): void;
@@ -233,12 +233,13 @@ type ActivationCondition = {
233
233
  allocation?: ActivationConditionAllocation;
234
234
  js_function?: string;
235
235
  };
236
+ type AntiflickerMode = 'body' | 'include' | 'exclude';
236
237
  type CoframeConfig = {
237
238
  projectId: string;
238
239
  previewVariantId?: string;
239
240
  trackingOnly?: boolean;
240
241
  enableAntiFlickering?: boolean;
241
- enableElementAntiFlicker?: boolean;
242
+ antiflickerMode?: AntiflickerMode;
242
243
  waitForHydration?: boolean;
243
244
  waitForCookiesEnabled?: boolean;
244
245
  waitForFeatureFlag?: boolean;
@@ -290,13 +291,14 @@ interface CoframeProviderProps {
290
291
  onTreatmentApplied?: (data: TreatmentData) => void;
291
292
  onTreatmentAppliedBulk?: (data: TreatmentData[]) => void;
292
293
  onTreatmentAppliedBulkV2?: (data: TreatmentDataV2[], rawIds: ExperimentInfo[]) => void;
294
+ onTreatmentAppliedBulkV2WithoutConsent?: (data: TreatmentDataV2[], rawIds: ExperimentInfo[]) => void;
293
295
  onLog?: (payload: LogPayload) => void;
294
296
  children: ReactNode;
295
297
  }
296
298
  interface CoframeContextValue {
297
299
  treatments: TreatmentData[] | null;
298
300
  }
299
- declare function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTreatmentAppliedProp, onTreatmentAppliedBulk: onTreatmentAppliedBulkProp, onTreatmentAppliedBulkV2, onLog: onLogProp, children, }: CoframeProviderProps): React.FunctionComponentElement<React.ProviderProps<CoframeContextValue>>;
301
+ declare function CoframeProvider({ projectConfig, projectData, onTreatmentApplied: onTreatmentAppliedProp, onTreatmentAppliedBulk: onTreatmentAppliedBulkProp, onTreatmentAppliedBulkV2, onTreatmentAppliedBulkV2WithoutConsent, onLog: onLogProp, children, }: CoframeProviderProps): React.FunctionComponentElement<React.ProviderProps<CoframeContextValue>>;
300
302
  declare function useCoframeTreatments(): TreatmentData[] | null;
301
303
  declare function useCoframeTreatment(experimentId: string): TreatmentData | undefined;
302
304
  declare function useCoframeVariant(experimentId: string): string | undefined;
@@ -196,6 +196,7 @@ type ActivationCondition = {
196
196
  allocation?: ActivationConditionAllocation;
197
197
  js_function?: string;
198
198
  };
199
+ type AntiflickerMode = 'body' | 'include' | 'exclude';
199
200
  type BotReason = 'none' | 'cf_bot_score' | 'cf_verified_bot' | 'force_bot_param';
200
201
  type PersonalizationHeaders = {
201
202
  'x-device-type': string;
@@ -215,7 +216,7 @@ interface GetProjectDataOptions {
215
216
  currentUrl: string;
216
217
  userContext?: Record<string, unknown>;
217
218
  headers: Headers | Record<string, string>;
218
- enableElementAntiFlicker?: boolean;
219
+ antiflickerMode?: AntiflickerMode;
219
220
  includeProject?: boolean;
220
221
  includeCSS?: boolean;
221
222
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coframe/sdk",
3
- "version": "1.1.9",
3
+ "version": "1.1.10",
4
4
  "description": "Coframe optimizes your website using generative AI to deliver maximum impact to your audience and allow your site to improve itself as you sleep. Learn more at coframe.com.",
5
5
  "main": "dist/pkg/cf.cjs.js",
6
6
  "module": "dist/pkg/cf.esm.mjs",