@chordcommerce/analytics 1.21.1 → 1.21.2
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 +45 -10
- package/dist/cjs/client/cdp.js +0 -6
- package/dist/cjs/client/consent/index.js +3 -10
- package/dist/cjs/client/consent/onetrust-api.d.ts +10 -0
- package/dist/cjs/client/consent/onetrust-api.js +14 -1
- package/dist/cjs/client/consent/onetrust.js +1 -1
- package/dist/client/cdp.js +0 -6
- package/dist/client/consent/index.js +3 -8
- package/dist/client/consent/onetrust-api.d.ts +10 -0
- package/dist/client/consent/onetrust-api.js +12 -0
- package/dist/client/consent/onetrust.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -168,15 +168,34 @@ This package uses [semantic-release](https://github.com/semantic-release/semanti
|
|
|
168
168
|
|
|
169
169
|
### How it works
|
|
170
170
|
|
|
171
|
+
The repo has a single CI workflow (`.github/workflows/ci.yml`) with two jobs:
|
|
172
|
+
|
|
173
|
+
1. **`test`** — Runs lint, prettier, build, and tests for all packages. Triggers on every push to `main`/`beta` and on every pull request.
|
|
174
|
+
2. **`release`** — Runs only on `main` and `beta` branches, after `test` passes. Runs `semantic-release` to determine if a new version should be published.
|
|
175
|
+
|
|
176
|
+
The release flow:
|
|
177
|
+
|
|
171
178
|
1. Merge a PR into `main` (stable) or `beta` (pre-release).
|
|
172
|
-
2. The
|
|
173
|
-
3.
|
|
174
|
-
4.
|
|
175
|
-
5.
|
|
179
|
+
2. The `test` job runs. If it passes, the `release` job starts.
|
|
180
|
+
3. `semantic-release` analyzes commit messages since the last release tag.
|
|
181
|
+
4. If releasable commits exist, the package is published to npm and GitHub Packages, CHANGELOG.md is updated, and a Git tag is created.
|
|
182
|
+
5. If no releasable commits exist, `semantic-release` exits cleanly and nothing is published.
|
|
183
|
+
|
|
184
|
+
### PR titles must follow conventional commits
|
|
185
|
+
|
|
186
|
+
When using GitHub's **squash merge** (the default), the PR title becomes the first line of the squash commit message. Semantic-release only parses the **first line** to determine the version bump, so **the PR title must use a conventional commit prefix** (e.g., `fix: resolve consent race condition`). Individual commit messages in the PR body are ignored.
|
|
187
|
+
|
|
188
|
+
If the PR title does not start with a releasable prefix, no release will be published even if the individual commits within the PR use `fix:` or `feat:`.
|
|
189
|
+
|
|
190
|
+
### When a release happens (and when it doesn't)
|
|
176
191
|
|
|
177
|
-
|
|
192
|
+
A release is published **only** when all three conditions are met:
|
|
178
193
|
|
|
179
|
-
|
|
194
|
+
1. A push lands on `main` or `beta` (via merged PR or direct push)
|
|
195
|
+
2. Tests pass
|
|
196
|
+
3. There are new commits since the last release tag with a releasable prefix (checked against the **first line** of each commit message)
|
|
197
|
+
|
|
198
|
+
**Releasable commit prefixes** (these trigger a version bump):
|
|
180
199
|
|
|
181
200
|
| Prefix | Version Bump | Example |
|
|
182
201
|
| -------------------------- | --------------------- | --------------------------------------------------------- |
|
|
@@ -184,19 +203,35 @@ This repo enforces [Conventional Commits](https://www.conventionalcommits.org/)
|
|
|
184
203
|
| `feat:` | Minor (1.0.0 → 1.1.0) | `feat: add trackOrderCompleted method` |
|
|
185
204
|
| `BREAKING CHANGE:` in body | Major (1.0.0 → 2.0.0) | Commit body contains `BREAKING CHANGE: remove legacy API` |
|
|
186
205
|
|
|
187
|
-
|
|
206
|
+
**Non-releasable prefixes** (these do NOT trigger a release):
|
|
207
|
+
|
|
208
|
+
`chore:`, `ci:`, `docs:`, `refactor:`, `test:`, `style:`, `build:`, `perf:`
|
|
209
|
+
|
|
210
|
+
If a merge to `main` or `beta` contains only non-releasable commits, the release job runs but `semantic-release` determines no release is needed and exits without publishing.
|
|
188
211
|
|
|
189
212
|
### Monorepo scoping
|
|
190
213
|
|
|
191
|
-
This repo uses [semantic-release-monorepo](https://github.com/pmowrer/semantic-release-monorepo) to scope releases to individual packages. Only commits that touch files within a package's directory (e.g., `packages/core/`) are considered when determining the next version.
|
|
214
|
+
This repo uses [semantic-release-monorepo](https://github.com/pmowrer/semantic-release-monorepo) to scope releases to individual packages. Only commits that touch files within a package's directory (e.g., `packages/core/`) are considered when determining the next version. A `feat:` commit that only modifies `.github/workflows/` or another package's directory will **not** trigger a release for `@chordcommerce/analytics`.
|
|
192
215
|
|
|
193
216
|
### Pre-releases
|
|
194
217
|
|
|
195
|
-
Merging to `beta` creates pre-release versions (e.g., `1.
|
|
218
|
+
Merging to `beta` creates pre-release versions (e.g., `1.22.0-beta.1`). Use this for testing before promoting to `main`. Only `main` and `beta` are currently configured for automatic releases in the CI workflow. Additional prerelease branches (e.g., `alpha`) can be enabled by adding them to both the workflow's branch filter in `ci.yml` and the semantic-release branch config.
|
|
219
|
+
|
|
220
|
+
### Beta release workflow
|
|
221
|
+
|
|
222
|
+
1. Create a feature branch off `beta` and do your work.
|
|
223
|
+
2. Create a PR targeting the `beta` branch and merge it.
|
|
224
|
+
3. The CI workflow runs tests, then `semantic-release` publishes a beta version (e.g., `1.22.0-beta.1`).
|
|
225
|
+
4. Install with: `npm install @chordcommerce/analytics@beta`
|
|
226
|
+
|
|
227
|
+
### Promoting beta to production
|
|
228
|
+
|
|
229
|
+
1. Create a PR from `beta` → `main` and merge it.
|
|
230
|
+
2. The CI workflow runs tests, then `semantic-release` publishes a stable version on `main`.
|
|
196
231
|
|
|
197
232
|
### Dry run
|
|
198
233
|
|
|
199
|
-
You can preview what a release would do without publishing by manually triggering the
|
|
234
|
+
You can preview what a release would do without publishing by manually triggering the CI workflow in GitHub Actions with `dryRun` set to `true`.
|
|
200
235
|
|
|
201
236
|
## Support
|
|
202
237
|
|
package/dist/cjs/client/cdp.js
CHANGED
|
@@ -80,15 +80,9 @@ var addCdpSnippet = function (options) { return __awaiter(void 0, void 0, void 0
|
|
|
80
80
|
_a.sent();
|
|
81
81
|
initialConsent = null;
|
|
82
82
|
if (!options.consent) return [3 /*break*/, 3];
|
|
83
|
-
if (options.debug && options.enableLogging) {
|
|
84
|
-
console.log('[Chord Analytics DEBUG]: Setting up consent management');
|
|
85
|
-
}
|
|
86
83
|
return [4 /*yield*/, (0, index_js_1.addCdpConsent)(options).init()];
|
|
87
84
|
case 2:
|
|
88
85
|
initialConsent = _a.sent();
|
|
89
|
-
if (options.debug && options.enableLogging) {
|
|
90
|
-
console.log('[Chord Analytics DEBUG]: Consent management setup complete');
|
|
91
|
-
}
|
|
92
86
|
_a.label = 3;
|
|
93
87
|
case 3:
|
|
94
88
|
if (options.debug && options.enableLogging) {
|
|
@@ -152,7 +152,7 @@ var addCdpConsent = function (options) {
|
|
|
152
152
|
* or null if consent setup failed or was blocked.
|
|
153
153
|
*/
|
|
154
154
|
var init = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
155
|
-
var canBeTracked,
|
|
155
|
+
var canBeTracked, error_1;
|
|
156
156
|
return __generator(this, function (_a) {
|
|
157
157
|
switch (_a.label) {
|
|
158
158
|
case 0:
|
|
@@ -180,17 +180,10 @@ var addCdpConsent = function (options) {
|
|
|
180
180
|
case 2:
|
|
181
181
|
_a.trys.push([2, 4, , 5]);
|
|
182
182
|
return [4 /*yield*/, setupConsentManagement()];
|
|
183
|
-
case 3:
|
|
184
|
-
result = _a.sent();
|
|
185
|
-
if (options.debug && options.enableLogging) {
|
|
186
|
-
console.log('[Chord Analytics DEBUG]: setupConsentManagement() returned:', JSON.stringify(result));
|
|
187
|
-
}
|
|
188
|
-
return [2 /*return*/, result];
|
|
183
|
+
case 3: return [2 /*return*/, _a.sent()];
|
|
189
184
|
case 4:
|
|
190
185
|
error_1 = _a.sent();
|
|
191
|
-
|
|
192
|
-
console.error('[Chord Analytics DEBUG]: Error setting up consent management:', error_1);
|
|
193
|
-
}
|
|
186
|
+
console.error('Error setting up consent management:', error_1);
|
|
194
187
|
return [2 /*return*/, null];
|
|
195
188
|
case 5: return [2 /*return*/];
|
|
196
189
|
}
|
|
@@ -71,6 +71,16 @@ export declare const getOneTrustActiveGroups: () => string | undefined;
|
|
|
71
71
|
* getNormalizedActiveGroupIds() // ["C0001", "C0003"]
|
|
72
72
|
*/
|
|
73
73
|
export declare const getNormalizedActiveGroupIds: () => string[];
|
|
74
|
+
/**
|
|
75
|
+
* Check if OnetrustActiveGroups is populated with actual consent categories.
|
|
76
|
+
*
|
|
77
|
+
* OneTrust sets window.OnetrustActiveGroups after the API object is available,
|
|
78
|
+
* so this guards against a race condition where the API exists but consent
|
|
79
|
+
* categories have not yet been populated.
|
|
80
|
+
*
|
|
81
|
+
* @returns true if OnetrustActiveGroups is a non-empty string with at least one group ID
|
|
82
|
+
*/
|
|
83
|
+
export declare const hasActiveGroups: () => boolean;
|
|
74
84
|
/**
|
|
75
85
|
* Get all configured consent groups from OneTrust.
|
|
76
86
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Modeled after analytics-next's onetrust-api.ts
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.coerceConsentModel = exports.getNormalizedCategories = exports.getAllGroups = exports.getNormalizedActiveGroupIds = exports.getOneTrustActiveGroups = exports.getOneTrustGlobal = exports.OtConsentModel = void 0;
|
|
11
|
+
exports.coerceConsentModel = exports.getNormalizedCategories = exports.getAllGroups = exports.hasActiveGroups = exports.getNormalizedActiveGroupIds = exports.getOneTrustActiveGroups = exports.getOneTrustGlobal = exports.OtConsentModel = void 0;
|
|
12
12
|
/**
|
|
13
13
|
* OneTrust consent model types
|
|
14
14
|
*/
|
|
@@ -70,6 +70,19 @@ var getNormalizedActiveGroupIds = function () {
|
|
|
70
70
|
return groups.trim().split(',').filter(Boolean);
|
|
71
71
|
};
|
|
72
72
|
exports.getNormalizedActiveGroupIds = getNormalizedActiveGroupIds;
|
|
73
|
+
/**
|
|
74
|
+
* Check if OnetrustActiveGroups is populated with actual consent categories.
|
|
75
|
+
*
|
|
76
|
+
* OneTrust sets window.OnetrustActiveGroups after the API object is available,
|
|
77
|
+
* so this guards against a race condition where the API exists but consent
|
|
78
|
+
* categories have not yet been populated.
|
|
79
|
+
*
|
|
80
|
+
* @returns true if OnetrustActiveGroups is a non-empty string with at least one group ID
|
|
81
|
+
*/
|
|
82
|
+
var hasActiveGroups = function () {
|
|
83
|
+
return (0, exports.getNormalizedActiveGroupIds)().length > 0;
|
|
84
|
+
};
|
|
85
|
+
exports.hasActiveGroups = hasActiveGroups;
|
|
73
86
|
/**
|
|
74
87
|
* Get all configured consent groups from OneTrust.
|
|
75
88
|
*
|
|
@@ -63,7 +63,7 @@ var onetrustConsentAdapter = function (options) {
|
|
|
63
63
|
},
|
|
64
64
|
userCanBeTracked: userCanBeTracked,
|
|
65
65
|
getCategories: function () { return (0, onetrust_api_js_1.getNormalizedCategories)(); },
|
|
66
|
-
isConsentReady: function () { return !!(0, onetrust_api_js_1.getOneTrustGlobal)(); },
|
|
66
|
+
isConsentReady: function () { return !!(0, onetrust_api_js_1.getOneTrustGlobal)() && (0, onetrust_api_js_1.hasActiveGroups)(); },
|
|
67
67
|
getConsentModel: function () {
|
|
68
68
|
var api = (0, onetrust_api_js_1.getOneTrustGlobal)();
|
|
69
69
|
if (!api)
|
package/dist/client/cdp.js
CHANGED
|
@@ -44,13 +44,7 @@ export const addCdpSnippet = (options) => __awaiter(void 0, void 0, void 0, func
|
|
|
44
44
|
yield cdpReadyPromise;
|
|
45
45
|
let initialConsent = null;
|
|
46
46
|
if (options.consent) {
|
|
47
|
-
if (options.debug && options.enableLogging) {
|
|
48
|
-
console.log('[Chord Analytics DEBUG]: Setting up consent management');
|
|
49
|
-
}
|
|
50
47
|
initialConsent = yield addCdpConsent(options).init();
|
|
51
|
-
if (options.debug && options.enableLogging) {
|
|
52
|
-
console.log('[Chord Analytics DEBUG]: Consent management setup complete');
|
|
53
|
-
}
|
|
54
48
|
}
|
|
55
49
|
if (options.debug && options.enableLogging) {
|
|
56
50
|
console.log('[Chord Analytics DEBUG]: CDP snippet added, initialConsent:', JSON.stringify(initialConsent));
|
|
@@ -121,17 +121,12 @@ export const addCdpConsent = (options) => {
|
|
|
121
121
|
return null;
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
+
// Set up consent management and wait for it to complete
|
|
124
125
|
try {
|
|
125
|
-
|
|
126
|
-
if (options.debug && options.enableLogging) {
|
|
127
|
-
console.log('[Chord Analytics DEBUG]: setupConsentManagement() returned:', JSON.stringify(result));
|
|
128
|
-
}
|
|
129
|
-
return result;
|
|
126
|
+
return yield setupConsentManagement();
|
|
130
127
|
}
|
|
131
128
|
catch (error) {
|
|
132
|
-
|
|
133
|
-
console.error('[Chord Analytics DEBUG]: Error setting up consent management:', error);
|
|
134
|
-
}
|
|
129
|
+
console.error('Error setting up consent management:', error);
|
|
135
130
|
return null;
|
|
136
131
|
}
|
|
137
132
|
});
|
|
@@ -71,6 +71,16 @@ export declare const getOneTrustActiveGroups: () => string | undefined;
|
|
|
71
71
|
* getNormalizedActiveGroupIds() // ["C0001", "C0003"]
|
|
72
72
|
*/
|
|
73
73
|
export declare const getNormalizedActiveGroupIds: () => string[];
|
|
74
|
+
/**
|
|
75
|
+
* Check if OnetrustActiveGroups is populated with actual consent categories.
|
|
76
|
+
*
|
|
77
|
+
* OneTrust sets window.OnetrustActiveGroups after the API object is available,
|
|
78
|
+
* so this guards against a race condition where the API exists but consent
|
|
79
|
+
* categories have not yet been populated.
|
|
80
|
+
*
|
|
81
|
+
* @returns true if OnetrustActiveGroups is a non-empty string with at least one group ID
|
|
82
|
+
*/
|
|
83
|
+
export declare const hasActiveGroups: () => boolean;
|
|
74
84
|
/**
|
|
75
85
|
* Get all configured consent groups from OneTrust.
|
|
76
86
|
*
|
|
@@ -64,6 +64,18 @@ export const getNormalizedActiveGroupIds = () => {
|
|
|
64
64
|
return [];
|
|
65
65
|
return groups.trim().split(',').filter(Boolean);
|
|
66
66
|
};
|
|
67
|
+
/**
|
|
68
|
+
* Check if OnetrustActiveGroups is populated with actual consent categories.
|
|
69
|
+
*
|
|
70
|
+
* OneTrust sets window.OnetrustActiveGroups after the API object is available,
|
|
71
|
+
* so this guards against a race condition where the API exists but consent
|
|
72
|
+
* categories have not yet been populated.
|
|
73
|
+
*
|
|
74
|
+
* @returns true if OnetrustActiveGroups is a non-empty string with at least one group ID
|
|
75
|
+
*/
|
|
76
|
+
export const hasActiveGroups = () => {
|
|
77
|
+
return getNormalizedActiveGroupIds().length > 0;
|
|
78
|
+
};
|
|
67
79
|
/**
|
|
68
80
|
* Get all configured consent groups from OneTrust.
|
|
69
81
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getOneTrustGlobal, getNormalizedCategories, coerceConsentModel, } from './onetrust-api.js';
|
|
1
|
+
import { getOneTrustGlobal, getNormalizedCategories, coerceConsentModel, hasActiveGroups, } from './onetrust-api.js';
|
|
2
2
|
/**
|
|
3
3
|
* Returns whether the user can currently be tracked.
|
|
4
4
|
* Uses duck typing to check if OneTrust is fully loaded.
|
|
@@ -60,7 +60,7 @@ export const onetrustConsentAdapter = (options) => {
|
|
|
60
60
|
},
|
|
61
61
|
userCanBeTracked,
|
|
62
62
|
getCategories: () => getNormalizedCategories(),
|
|
63
|
-
isConsentReady: () => !!getOneTrustGlobal(),
|
|
63
|
+
isConsentReady: () => !!getOneTrustGlobal() && hasActiveGroups(),
|
|
64
64
|
getConsentModel: () => {
|
|
65
65
|
const api = getOneTrustGlobal();
|
|
66
66
|
if (!api)
|
package/package.json
CHANGED