Skip to content
Merged
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,74 @@ When publishing releases, the following rules apply:
**Note**: The release will not be published if:
- A pre-release is marked as "latest"
- A pre-release label is used without checking "Set as pre-release"

## Tools

### Bootstrap Configuration

You can generate a bootstrap configuration string from either the command line or programmatically via the
ConfigurationWireHelper class.

The tool allows you to specify the target SDK this configuration will be used on. It is important to correctly specify
the intended SDK, as this determines whether the configuration is obfuscated (for client SDKs) or not (for server SDKs).

#### Command Line Usage

**Install as a project dependency:**
```bash
# Install as a dependency
npm install --save-dev @eppo/js-client-sdk-common
# or, with yarn
yarn add --dev @eppo/js-client-sdk-common

# Or via yarn
yarn bootstrap-config --key <sdkKey>
```

Common usage examples:
```bash
# Basic usage
yarn bootstrap-config --key <sdkKey>

# With custom SDK name (default is 'android')
yarn bootstrap-config --key <sdkKey> --sdk js-client

# With custom base URL
yarn bootstrap-config --key <sdkKey> --base-url https://api.custom-domain.com

# Save configuration to a file
yarn bootstrap-config --key <sdkKey> --output bootstrap-config.json

# Show help
yarn bootstrap-config --help
```

The tool accepts the following arguments:
- `--key, -k`: SDK key (required, can also be set via EPPO_SDK_KEY environment variable)
- `--sdk`: Target SDK name (default: 'android')
- `--base-url`: Custom base URL for the API
- `--output, -o`: Output file path (if not specified, outputs to console)
- `--help, -h`: Show help

#### Programmatic Usage
```typescript
import { ConfigurationHelper } from '@eppo/js-client-sdk-common';

async function getBootstrapConfig() {
// Initialize the helper
const helper = ConfigurationHelper.build(
'your-sdk-key',
'js-client', // optional: target SDK name (default: 'android')
'https://api.custom-domain.com' // optional: custom base URL
);

// Fetch the configuration
const configBuilder = await helper.getBootstrapConfigurationString();
const configString = configBuilder.toString();

// Use the configuration string to initialize your SDK
console.log(configString);
}
```

The tool will output a JSON string containing the configuration wire format that can be used to bootstrap Eppo SDKs.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"typecheck": "tsc",
"test": "yarn test:unit",
"test:unit": "NODE_ENV=test jest '.*\\.spec\\.ts'",
"obfuscate-mock-ufc": "ts-node test/writeObfuscatedMockUFC"
"obfuscate-mock-ufc": "ts-node test/writeObfuscatedMockUFC",
"bootstrap-config": "ts-node src/tools/get-bootstrap-config.ts"
},
"jsdelivr": "dist/eppo-sdk.js",
"repository": {
Expand Down
73 changes: 73 additions & 0 deletions src/tools/commands/bootstrap-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import * as fs from 'fs';

import type { CommandModule } from 'yargs';

import { ConfigurationWireHelper } from '../../configuration-wire/configuration-wire-helper';
import { process } from '../node-shim';

export const bootstrapConfigCommand: CommandModule = {
command: 'bootstrap-config',
describe: 'Generate a bootstrap configuration string',
builder: (yargs) => {
return yargs.options({
key: {
type: 'string',
description: 'SDK key',
alias: 'k',
default: process.env.EPPO_SDK_KEY,
},
sdk: {
type: 'string',
description: 'Target SDK name',
default: 'android',
},
'base-url': {
type: 'string',
description: 'Base URL for the API',
},
output: {
type: 'string',
description: 'Output file path',
alias: 'o',
},
});
},
handler: async (argv) => {
if (!argv.key) {
console.error('Error: SDK key is required');
console.error('Provide it either as:');
console.error('- Command line argument: --key <sdkKey> or -k <sdkKey>');
console.error('- Environment variable: EPPO_SDK_KEY');
process.exit(1);
}

try {
const helper = ConfigurationWireHelper.build(argv.key as string, {
sdkName: argv.sdk as string,
sdkVersion: 'v5.0.0',
baseUrl: argv['base-url'] as string,
});
const config = await helper.fetchBootstrapConfiguration();

if (!config) {
console.error('Error: Failed to fetch configuration');
process.exit(1);
}

const jsonConfig = JSON.stringify(config);

if (argv.output && typeof argv.output === 'string') {
fs.writeFileSync(argv.output, jsonConfig);
console.log(`Configuration written to ${argv.output}`);
} else {
console.log('Configuration:');
console.log('--------------------------------');
console.log(jsonConfig);
console.log('--------------------------------');
}
} catch (error) {
console.error('Error fetching configuration:', error);
process.exit(1);
}
},
};
26 changes: 26 additions & 0 deletions src/tools/get-bootstrap-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

import { bootstrapConfigCommand } from './commands/bootstrap-config';
import { process } from './node-shim';

/**
* Script to run the bootstrap-config command directly.
*/
async function main() {
await yargs(hideBin(process.argv))
.command({
command: '$0',
describe: bootstrapConfigCommand.describe,
builder: bootstrapConfigCommand.builder,
handler: bootstrapConfigCommand.handler,
})
.help()
.alias('help', 'h')
.parse();
}

main().catch((error) => {
console.error('Error in main:', error);
process.exit(1);
});
8 changes: 8 additions & 0 deletions src/tools/node-shim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Required type shape for `process`.
// We don't pin this project to node so eslint complains about the use of `process`. We declare a type shape here to
// appease the linter.
export declare const process: {
exit: (code: number) => void;
env: { [key: string]: string | undefined };
argv: string[];
};
Loading