Skip to content

Commit 49b58cc

Browse files
raju-opticlaude
andauthored
[FSSDK-12820] Upgrade to uuid v13 (#1159)
* [FSSDK-12820] Upgrade to uuid v13 Upgrade uuid to v13 (ESM-only). Update rollup config to bundle uuid into CJS outputs instead of keeping it as an external dependency, since CJS consumers cannot require() an ESM-only package. Add a CJS require hook shim so mocha/ts-node tests can still load uuid in CommonJS mode. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1d56eeb commit 49b58cc

16 files changed

Lines changed: 394 additions & 51 deletions

File tree

.github/workflows/javascript.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ jobs:
4242
npm install
4343
npm run test-typescript
4444
45+
commonjs_test:
46+
runs-on: ubuntu-latest
47+
steps:
48+
- uses: actions/checkout@v3
49+
- name: Set up Node
50+
uses: actions/setup-node@v3
51+
with:
52+
node-version: '18'
53+
cache-dependency-path: ./package-lock.json
54+
cache: 'npm'
55+
- name: Run CommonJS example
56+
run: |
57+
npm install
58+
npm run test-commonjs
59+
4560
integration_tests:
4661
uses: optimizely/javascript-sdk/.github/workflows/integration_test.yml@master
4762
secrets:

examples/node-commonjs/index.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright 2026, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
const fs = require('fs');
18+
const path = require('path');
19+
20+
const {
21+
createInstance,
22+
createStaticProjectConfigManager,
23+
createForwardingEventProcessor,
24+
createLogger,
25+
createErrorNotifier,
26+
INFO,
27+
} = require('@optimizely/optimizely-sdk');
28+
29+
const datafilePath = path.join(__dirname, '..', 'shared', 'datafile.json');
30+
const testDatafile = fs.readFileSync(datafilePath, 'utf8');
31+
32+
const TIMEOUT_MS = 10000;
33+
34+
async function testCommonJsRequire() {
35+
let resolveUuid;
36+
const uuidPromise = new Promise((resolve, reject) => {
37+
resolveUuid = resolve;
38+
setTimeout(() => reject(new Error('Timed out waiting for event dispatch')), TIMEOUT_MS);
39+
});
40+
41+
const dispatcher = {
42+
dispatchEvent(logEvent) {
43+
const uuid = logEvent.params.visitors[0].snapshots[0].events[0].uuid;
44+
console.log(`Dispatched event with uuid: ${uuid}`);
45+
46+
if (typeof uuid === 'string' && uuid.length > 0) {
47+
resolveUuid(uuid);
48+
}
49+
50+
return Promise.resolve({});
51+
},
52+
};
53+
54+
const configManager = createStaticProjectConfigManager({
55+
datafile: testDatafile,
56+
});
57+
58+
const eventProcessor = createForwardingEventProcessor(dispatcher);
59+
60+
const client = createInstance({
61+
projectConfigManager: configManager,
62+
eventProcessor: eventProcessor,
63+
});
64+
65+
await client.onReady();
66+
67+
const userContext = client.createUserContext('test_user', { age: 22 });
68+
userContext.decide('flag_1');
69+
70+
const uuid = await uuidPromise;
71+
console.log(`Test passed: event contained valid uuid "${uuid}"`);
72+
73+
client.close();
74+
}
75+
76+
testCommonJsRequire()
77+
.then(() => {
78+
console.log('\n=== CommonJS example completed successfully! ===\n');
79+
process.exit(0);
80+
})
81+
.catch((error) => {
82+
console.error('Test failed:', error);
83+
process.exit(1);
84+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "optimizely-sdk-commonjs-example",
3+
"version": "1.0.0",
4+
"private": true,
5+
"description": "CommonJS example for Optimizely SDK - verifies CJS compatibility",
6+
"scripts": {
7+
"start": "node index.js"
8+
}
9+
}
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,9 @@
2121
* Runs at http://localhost:PORT
2222
*/
2323

24-
import http from 'http';
25-
import fs from 'fs';
26-
import path from 'path';
27-
import { fileURLToPath } from 'url';
28-
import { dirname } from 'path';
29-
30-
const __filename = fileURLToPath(import.meta.url);
31-
const __dirname = dirname(__filename);
24+
const http = require('http');
25+
const fs = require('fs');
26+
const path = require('path');
3227

3328
const PORT = 8910;
3429
const datafilePath = path.join(__dirname, 'datafile.json');

examples/typescript/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@ node_modules/
22
dist/
33
*.log
44
.DS_Store
5-
package-lock.json

examples/typescript/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ This example demonstrates all factory functions from the Optimizely SDK, includi
55
## Files
66

77
- `src/index.ts` - Main example demonstrating all SDK factory functions
8-
- `datafile.json` - Test datafile with Optimizely configuration
9-
- `datafile-server.js` - Simple HTTP server for testing polling datafile manager
108

119
## Running the Example
1210

examples/typescript/package-lock.json

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/typescript/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import { fileURLToPath } from 'url';
5050
const __filename: string = fileURLToPath(import.meta.url);
5151
const __dirname: string = dirname(__filename);
5252

53-
const datafilePath: string = path.join(__dirname, '..', 'datafile.json');
53+
const datafilePath: string = path.join(__dirname, '..', '..', 'shared', 'datafile.json');
5454
const testDatafile: string = fs.readFileSync(datafilePath, 'utf8');
5555

5656
async function testStaticConfigSetup(): Promise<void> {

lib/tests/uuid_cjs_shim.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* CJS require hook that intercepts `require('uuid')` to provide a CJS-compatible
3+
* shim. Needed because uuid v13+ is ESM-only and cannot be loaded via require().
4+
* Uses Node's built-in crypto.randomUUID() which produces identical RFC 4122 v4 UUIDs.
5+
*/
6+
const Module = require('module'); // eslint-disable-line @typescript-eslint/no-var-requires
7+
const crypto = require('crypto'); // eslint-disable-line @typescript-eslint/no-var-requires
8+
9+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
10+
11+
const uuidShim = {
12+
v4: () => crypto.randomUUID(),
13+
validate: (str) => typeof str === 'string' && UUID_REGEX.test(str),
14+
};
15+
16+
const originalLoad = Module._load;
17+
Module._load = function (request, parent, isMain) {
18+
if (request === 'uuid') {
19+
return uuidShim;
20+
}
21+
return originalLoad.call(this, request, parent, isMain);
22+
};

0 commit comments

Comments
 (0)