bcra
v1.0.1
Published
JavaScript implementation of NCI's Breast Cancer Risk Assessment Tool (BCRAT; Gail Model)
Maintainers
Readme
BCRA - Breast Cancer Risk Assessment Tool
Privacy-preserving, client-side JavaScript implementation of the National Cancer Institute's Breast Cancer Risk Assessment Tool (BCRAT), also known as the Gail Model.
Table of Contents
- Overview
- Installation
- Quick Start
- API Reference
- Usage Examples
- Validation Rules
- Error Handling
- Scientific Background
- Development
- Publishing to NPM
- Disclaimer
Overview
BCRA is a pure JavaScript implementation of the Breast Cancer Risk Assessment Tool (BCRAT), commonly known as the Gail Model. This library calculates the absolute risk of developing invasive breast cancer over a specified time period based on individual's risk factors.
Originally developed by Dr. Mitchell Gail and colleagues at the National Cancer Institute, the Gail Model is one of the most widely validated breast cancer risk assessment tools. This JavaScript implementation maintains full computational fidelity with the original R package while providing a lightweight, client-side solution. The JavaScript implementation facilitates the development of accessible, privacy-preserving, and scalable web applications with BCRAT.
Why BCRA in JavaScript?
- Accessible: Web applications run on any device with an internet connection—requiring no setup or installation.
- Privacy-Preserving: All calculations run entirely in the browser, ensuring no data is ever sent to external servers.
- Scalable: Client-side processing automatically scales to high traffic demands, easily handling viral surges in information-seeking behavior (such as the Angelina Jolie effect).
Installation
NPM
npm install bcraYarn
yarn add bcrapnpm
pnpm add bcraCDN
Multiple CDN options are available for quick integration without a build step:
jsDelivr
ES Module (Modern Browsers):
<script type="module">
import { calculateRisk, RaceCode } from 'https://cdn.jsdelivr.net/npm/bcra@1/dist/bcra.es.js';
// Your code here
const result = calculateRisk({ /* ... */ });
</script>UMD (All Browsers including IE11):
<script src="https://cdn.jsdelivr.net/npm/bcra@1/dist/bcra.umd.js"></script>
<script>
const { calculateRisk, RaceCode } = window.BCRA;
// Your code here
const result = calculateRisk({ /* ... */ });
</script>Specific Version (Recommended for Production):
<!-- Replace 1.0.1 with specific version -->
<script type="module">
import { calculateRisk } from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/bcra.es.js';
</script>unpkg
<!-- ES Module -->
<script type="module">
import { calculateRisk } from 'https://unpkg.com/bcra@1/dist/bcra.es.js';
</script>
<!-- UMD -->
<script src="https://unpkg.com/bcra@1/dist/bcra.umd.js"></script>Skypack (ESM-only, optimized for modern browsers)
<script type="module">
import { calculateRisk, RaceCode } from 'https://cdn.skypack.dev/bcra@1';
</script>Version Pinning:
- Use
@latestfor the latest version (not recommended for production) - Use
@1for the latest v1.x.x version (recommended) - Use
@1.0.1for a specific version (most stable)
Browser Requirements
- Modern browsers with ES6+ support (Chrome, Firefox, Safari, Edge)
- No Internet Explorer support
Quick Start
import { calculateRisk, RaceCode } from 'bcra';
// Define risk factors of the individual
const data = {
id: 1,
initialAge: 40, // Current age: 40 years
projectionEndAge: 45, // Calculate risk up to age 45 (5-year risk)
race: RaceCode.WHITE, // Non-Hispanic White
numBreastBiopsies: 1, // 1 previous biopsy
ageAtMenarche: 12, // First period at age 12
ageAtFirstBirth: 25, // First child at age 25
numRelativesWithBrCa: 1, // 1 first-degree relative with breast cancer
atypicalHyperplasia: 0, // No atypical hyperplasia
};
// Calculate risk
const result = calculateRisk(data, { calculateAverage: true });
if (result.success) {
console.log(`Absolute Risk: ${result.absoluteRisk.toFixed(2)}%`);
console.log(`Average Risk: ${result.averageRisk.toFixed(2)}%`);
console.log(`Relative Risk (age <50): ${result.relativeRiskUnder50.toFixed(2)}`);
} else {
console.error('Validation errors:', result.validation.errors);
}Output:
Absolute Risk: 1.73%
Average Risk: 0.58%
Relative Risk (age <50): 4.78The result suggests that the queried woman has a 1.73% absolute risk of developing invasive breast cancer between the ages 40 and 45. The average risk of individuals of the same age and race/ethnicity in the general US population is 0.58%. This indicates that the queried woman is in an increased risk of developing invasive breast cancer compared to the average for a woman her age and race/ethnicity in the general US population.
API Reference
calculateRisk(data, options)
Calculates breast cancer risk for a single individual.
Parameters
data (Object) - Risk factor profile containing:
| Field | Type | Description | Valid Values |
|-------|------|-------------|--------------|
| id | number | string | Unique identifier | Any |
| initialAge | number | Current age | 20 ≤ initialAge < 90 |
| projectionEndAge | number | End age for risk projection | initialAge < projectionEndAge ≤ 90 |
| race | number | Race/ethnicity code | 1-11 (see Race Codes) |
| numBreastBiopsies | number | Number of breast biopsies | 0, 1, 2, 3, ..., or 99 (unknown) |
| ageAtMenarche | number | Age at first menstrual period | ageAtMenarche ≤ initialAge, or 99 (unknown) |
| ageAtFirstBirth | number | Age at first live birth | ageAtMenarche ≤ ageAtFirstBirth ≤ initialAge, 98 (nulliparous), or 99 (unknown) |
| numRelativesWithBrCa | number | First-degree relatives with breast cancer | 0, 1, 2, 3, ..., or 99 (unknown) |
| atypicalHyperplasia | number | Atypical hyperplasia status | 0 (no), 1 (yes), 99 (unknown/N/A) |
options (Object, optional) - Calculation options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| rawInput | boolean | true | Whether inputs are in raw format (needs recoding) |
| calculateAverage | boolean | false | Calculate average risk for comparison |
Returns
RiskResult (Object) containing:
{
success: boolean, // Whether calculation succeeded
absoluteRisk: number | null, // Absolute risk as percentage (0-100)
averageRisk: number | null, // Average risk (if calculateAverage=true)
relativeRiskUnder50: number | null, // RR multiplier for age < 50
relativeRiskAtOrAbove50: number | null, // RR multiplier for age ≥ 50
patternNumber: number | null, // Risk factor pattern (1-108)
raceEthnicity: string | null, // Race/ethnicity label
projectionInterval: number | null, // Years in projection (projectionEndAge - initialAge)
validation: { // Validation details
isValid: boolean,
errors: string[],
warnings: string[]
},
recodedValues: { // Recoded categorical values
biopsyCategory: number,
menarcheCategory: number,
firstBirthCategory: number,
relativesCategory: number,
hyperplasiaMultiplier: number,
raceLabel: string
} | null,
error: { // Error details (if success=false)
message: string,
stack?: string
} | undefined
}calculateBatchRisk(data, options)
Calculates breast cancer risk for multiple individuals.
Parameters
data (Array) - Array of risk factor profiles (same format as calculateRisk data parameter)
options (Object, optional) - Same options as calculateRisk
Returns
Array of RiskResult objects, one for each individual in the input array.
Example
import { calculateBatchRisk, RaceCode } from 'bcra';
const data = [
{ id: 1, initialAge: 40, projectionEndAge: 50, race: RaceCode.WHITE, /* ... */ },
{ id: 2, initialAge: 35, projectionEndAge: 45, race: RaceCode.AFRICAN_AMERICAN, /* ... */ },
{ id: 3, initialAge: 50, projectionEndAge: 60, race: RaceCode.HISPANIC_US_BORN, /* ... */ },
];
const results = calculateBatchRisk(data);
results.forEach((result, index) => {
console.log(`Subject: ${data[index].id}:`);
if (result.success) {
console.log(` Absolute Risk: ${result.absoluteRisk.toFixed(2)}%`);
} else {
console.log(` Errors:`, result.validation.errors);
}
});Race Codes
The library supports 11 different race/ethnicity groups with population-specific risk models:
| Code | Race/Ethnicity | Model Source | Notes | |------|----------------|--------------|-------| | 1 | Non-Hispanic White | Gail Model (SEER 1983-87) | Original BCRAT model | | 2 | African-American | CARE Study | Age at first birth not in model | | 3 | Hispanic (US Born) | SFBCS (San Francisco Bay Area) | Age at menarche not in model | | 4 | Native American/Other | Same as Non-Hispanic White | Uses White model coefficients | | 5 | Hispanic (Foreign Born) | SFBCS | Different groupings than US-born | | 6 | Chinese-American | AABCS (Asian American) | Shared Asian model | | 7 | Japanese-American | AABCS | Shared Asian model | | 8 | Filipino-American | AABCS | Shared Asian model | | 9 | Hawaiian | AABCS | Shared Asian model | | 10 | Other Pacific Islander | AABCS | Shared Asian model | | 11 | Other Asian | AABCS | Shared Asian model |
Using Race Codes:
import { RaceCode } from 'bcra';
const data = {
// ... other fields
race: RaceCode.AFRICAN_AMERICAN, // Recommended: use enum
// OR
race: 2, // Direct numeric code
};Race-Specific Model Differences:
- African-American (Race 2): Age at first birth is eliminated from the relative risk model
- Hispanic US Born (Race 3): Age at menarche is eliminated from the model
- Hispanic (Races 3, 5): Different category groupings for biopsies, age at first birth, and relatives
- Asian/Pacific Islander (Races 6-11): All use the same beta coefficients and group relatives category 2 with 1
Return Values
Absolute Risk
The absolute risk is the probability (expressed as a percentage from 0-100) that the individual will develop invasive breast cancer during the projection interval.
Example Interpretation:
absoluteRisk: 1.73means a 1.73% chance of developing breast cancer frominitialAgetoprojectionEndAge- For a 5-year projection (age 40 to 45), an absolute risk of 1.73% means approximately 17 out of 1,000 women with similar characteristics in the US population would develop invasive breast cancer
Relative Risk
Relative risk values indicate how much higher (or lower) the individual's risk is compared to a woman with "average" risk factors:
relativeRiskUnder50: 4.78means 4.78× higher risk than average for ages < 50relativeRiskAtOrAbove50: 0.8means 0.8× (20% lower) risk than average for ages ≥ 50
Pattern Number
The pattern number (1-108) uniquely identifies the combination of categorical risk factors:
- 3 biopsy categories × 3 menarche categories × 4 first birth categories × 3 relatives categories = 108 patterns
- Useful for grouping individuals with identical risk factor profiles
Usage Examples
Example 1: Basic Calculation
import { calculateRisk, RaceCode } from 'bcra';
const result = calculateRisk({
id: 1,
initialAge: 45,
projectionEndAge: 50,
race: RaceCode.WHITE,
numBreastBiopsies: 0,
ageAtMenarche: 13,
ageAtFirstBirth: 28,
numRelativesWithBrCa: 0,
atypicalHyperplasia: 99, // Unknown
});
console.log(result);Example 2: Handling Validation Errors
import { calculateRisk, RaceCode } from 'bcra';
const invalidData = {
id: 2,
initialAge: 19, // ERROR: Too young (must be ≥ 20)
projectionEndAge: 25,
race: RaceCode.WHITE,
numBreastBiopsies: 1,
ageAtMenarche: 12,
ageAtFirstBirth: 25,
numRelativesWithBrCa: 1,
atypicalHyperplasia: 1,
};
const result = calculateRisk(invalidData);
if (!result.success) {
console.error('Validation failed:');
result.validation.errors.forEach((error, i) => {
console.error(` ${i + 1}. ${error}`);
});
}
// Output:
// Validation failed:
// 1. Initial age must be between 20 and 89 yearsExample 3: Batch Processing
import { calculateBatchRisk, RaceCode } from 'bcra';
const cohort = [
{
id: 'P001',
initialAge: 40,
projectionEndAge: 50,
race: RaceCode.WHITE,
numBreastBiopsies: 0,
ageAtMenarche: 12,
ageAtFirstBirth: 25,
numRelativesWithBrCa: 0,
atypicalHyperplasia: 99,
},
{
id: 'P002',
initialAge: 35,
projectionEndAge: 40,
race: RaceCode.AFRICAN_AMERICAN,
numBreastBiopsies: 1,
ageAtMenarche: 11,
ageAtFirstBirth: 22,
numRelativesWithBrCa: 1,
atypicalHyperplasia: 0,
},
];
const results = calculateBatchRisk(cohort);
// Create summary report
const summary = results.map((r) => ({
id: r.validation.isValid ? cohort.find((p) => p.id === r.id)?.id : 'N/A',
absoluteRisk: r.absoluteRisk?.toFixed(2) + '%' || 'N/A',
valid: r.success,
}));
console.table(summary);Example 4: Comparing to Average Risk
import { calculateRisk, RaceCode } from 'bcra';
const data = {
id: 3,
initialAge: 50,
projectionEndAge: 60,
race: RaceCode.WHITE,
numBreastBiopsies: 2,
ageAtMenarche: 11,
ageAtFirstBirth: 98, // Nulliparous
numRelativesWithBrCa: 2,
atypicalHyperplasia: 1,
};
const result = calculateRisk(data, { calculateAverage: true });
console.log(`Individual's Risk: ${result.absoluteRisk.toFixed(2)}%`);
console.log(`Average Risk: ${result.averageRisk.toFixed(2)}%`);
console.log(`Risk Ratio: ${(result.absoluteRisk / result.averageRisk).toFixed(2)}×`);
// Output:
// Individual's Risk: 21.60%
// Average Risk: 2.73%
// Risk Ratio: 7.92×Example 5: Different Race Groups
import { calculateRisk, RaceCode, RaceLabels } from 'bcra';
const baseData = {
id: 4,
initialAge: 40,
projectionEndAge: 45,
numBreastBiopsies: 1,
ageAtMenarche: 12,
ageAtFirstBirth: 25,
numRelativesWithBrCa: 1,
atypicalHyperplasia: 0,
};
// Calculate for multiple races
const races = [
RaceCode.WHITE,
RaceCode.AFRICAN_AMERICAN,
RaceCode.HISPANIC_US_BORN,
RaceCode.CHINESE,
];
races.forEach((race) => {
const result = calculateRisk({ ...baseData, race });
console.log(
`${RaceLabels[race]}: ${result.absoluteRisk.toFixed(2)}%`
);
});
// Output:
// Non-Hispanic White: 1.73%
// African-American: 1.01%
// Hispanic (US Born): 0.69%
// Chinese-American: 1.44%Example 6: Handling Unknown Values
import { calculateRisk, RaceCode } from 'bcra';
const dataWithUnknowns = {
id: 5,
initialAge: 55,
projectionEndAge: 65,
race: RaceCode.WHITE,
numBreastBiopsies: 99, // Unknown
ageAtMenarche: 99, // Unknown
ageAtFirstBirth: 99, // Unknown
numRelativesWithBrCa: 99, // Unknown
atypicalHyperplasia: 99, // Unknown/Not applicable
};
const result = calculateRisk(dataWithUnknowns);
// The model treats unknowns as baseline/average values
console.log(`Risk with all unknowns: ${result.absoluteRisk.toFixed(2)}%`);
console.log(`Pattern number: ${result.patternNumber}`);Validation Rules
The library performs comprehensive validation to ensure data integrity and consistency.
Age Constraints
- Initial age: Must be ≥ 20 and < 90 years
- Projection end age: Must be > initial age and ≤ 90 years
- Age at menarche: Must be ≤ initial age (unless unknown = 99)
- Age at first birth: Must be ≥ age at menarche and ≤ initial age (unless nulliparous = 98 or unknown = 99)
Race Validation
- Must be an integer between 1 and 11 (inclusive)
Biopsy and Hyperplasia Consistency
Rule A: If no biopsies performed (numBreastBiopsies = 0 or 99), then atypicalHyperplasia MUST be 99 (not applicable)
Rule B: If biopsies performed (numBreastBiopsies > 0 and < 99), then atypicalHyperplasia MUST be 0, 1, or 99
Special Values
- 98: Nulliparous (never had a live birth) - only valid for
ageAtFirstBirth - 99: Unknown/Not Applicable - valid for most fields
Race-Specific Recoding
The library automatically recodes inputs based on race-specific model requirements:
African-American (Race 2)
- Age at first birth is set to 0 (not used in CARE model)
- Age at menarche category 2 (≤11) is grouped with category 1 (12-13)
Hispanic US Born (Race 3)
- Age at menarche is set to 0 (not used in model)
- Special groupings for age at first birth, biopsies, and relatives
Hispanic Foreign Born (Race 5)
- Special groupings for age at first birth, biopsies, and relatives
Asian/Pacific Islander (Races 6-11)
- Number of relatives category 2 (2+) is grouped with category 1
Error Handling
The library uses structured error handling with user-friendly messages.
Validation Errors
When validation fails, the result object contains detailed error information:
const result = calculateRisk(invalidData);
if (!result.success) {
console.log('Validation errors:');
result.validation.errors.forEach((error) => {
console.log(` - ${error}`);
});
console.log('\nRecoded values:', result.recodedValues);
console.log('Error indicator:', result.validation.isValid ? 0 : 1);
}Common Validation Errors
| Error Message | Cause | Solution |
|---------------|-------|----------|
| "Initial age must be between 20 and 89 years" | initialAge < 20 or ≥ 90 | Use age between 20-89 |
| "Projection end age must be greater than initial age" | projectionEndAge ≤ initialAge | Use larger projection age |
| "Consistency error: If no biopsies, atypical hyperplasia must be not applicable (99)" | Biopsies=0 but hyperplasia≠99 | Set hyperplasia to 99 |
| "Age at first birth cannot be less than age at menarche" | ageAtFirstBirth < ageAtMenarche | Fix chronological order |
| "Invalid race code. Must be between 1 and 11" | race outside valid range | Use race code 1-11 |
Custom Error Classes
The library provides custom error classes for programmatic error handling:
import { calculateRisk, BCRAValidationError, BCRACalculationError } from 'bcra';
try {
const result = calculateRisk(data);
if (!result.success && result.error) {
if (result.error instanceof BCRAValidationError) {
// Handle validation error
console.error('Validation failed:', result.validation.errors);
} else if (result.error instanceof BCRACalculationError) {
// Handle calculation error
console.error('Calculation failed:', result.error.message);
}
}
} catch (error) {
console.error('Unexpected error:', error);
}Scientific Background
The Gail Model
The Gail Model, developed by Dr. Mitchell H. Gail and colleagues at the National Cancer Institute, estimates the absolute risk of developing invasive breast cancer over a specified time period. It combines:
- Relative Risk ($RR$): Individual risk factors compared to average
- Baseline Incidence Rates ($\lambda_1$): Age-specific breast cancer rates for the general population
- Competing Mortality ($\lambda_2$): Risk of death from non-breast cancer causes
- Attributable Risk ($AR$): Proportion of risk explained by known factors
Mathematical Formula
The model uses numerical integration to calculate absolute risk:
$$ \text{AbsoluteRisk} = \int_{t_1}^{t_2} \frac{(1-AR) \cdot RR \cdot \lambda_1(t)}{(1-AR) \cdot RR \cdot \lambda_1(t) + \lambda_2(t)} \cdot \exp\left(-\int_{t_1}^{t} \left[(1-AR) \cdot RR \cdot \lambda_1(s) + \lambda_2(s)\right] ds\right) dt $$
Where:
- $t_1$: Initial age (current age)
- $t_2$: Projection end age
- $\lambda_1(t)$: Breast cancer incidence rate at age $t$
- $\lambda_2(t)$: Competing mortality rate at age $t$
- $AR$: Attributable risk (population attributable risk)
- $RR$: Relative risk based on individual's risk factors
Relative Risk Calculation
The relative risk is calculated using logistic regression:
$$ RR = \exp\left(\beta_0 \cdot \text{biopsies} + \beta_1 \cdot \text{menarche} + \beta_2 \cdot \text{firstBirth} + \beta_3 \cdot \text{relatives} + \beta_4 \cdot \mathbb{1}_{\text{age} \geq 50} \cdot \text{biopsies} + \beta_5 \cdot \text{firstBirth} \cdot \text{relatives} + \ln(\text{hyperplasia})\right) $$
Two-stage calculation:
For ages < 50:
$$ LP_1 = \beta_0 \cdot NB + \beta_1 \cdot AM + \beta_2 \cdot AF + \beta_3 \cdot NR + \beta_5 \cdot (AF \times NR) + \ln(R_{Hyp}) $$
$$ RR_1 = \exp(LP_1) $$
For ages ≥ 50:
$$ LP_2 = LP_1 + \beta_4 \cdot NB $$
$$ RR_2 = \exp(LP_2) $$
Where:
- $NB$: Number of biopsies category (0, 1, or 2)
- $AM$: Age at menarche category (0, 1, or 2)
- $AF$: Age at first birth category (0, 1, 2, or 3)
- $NR$: Number of relatives category (0, 1, or 2)
- $R_{Hyp}$: Hyperplasia multiplier (0.93, 1.00, or 1.82)
- $\beta_i$: Race-specific regression coefficients
Data Sources
Incidence Rates ($\lambda_1$):
- Surveillance, Epidemiology, and End Results (SEER) Program
- Various time periods: 1983-87 (White baseline), 1992-96 (White average), 1995-2004 (Hispanic), 1998-2002 (Asian subgroups)
Mortality Rates ($\lambda_2$):
- National Center for Health Statistics (NCHS)
- Time periods vary by race/ethnicity
Beta Coefficients ($\beta$):
- Non-Hispanic White: Original Gail Model (1989)
- African-American: Contraceptive and Reproductive Experiences (CARE) Study
- Hispanic: San Francisco Bay Area Breast Cancer Study (SFBCS)
- Asian/Pacific Islander: Asian American Breast Cancer Study (AABCS)
Key Publications
Original Gail Model:
- Gail MH, Brinton LA, Byar DP, et al. Projecting individualized probabilities of developing breast cancer for white females who are being examined annually. J Natl Cancer Inst. 1989;81(24):1879-1886.
- PubMed: 2593165
Validation Study:
- Costantino JP, Gail MH, Pee D, et al. Validation studies for models projecting the risk of invasive and total breast cancer incidence. J Natl Cancer Inst. 1999;91(18):1541-1548.
- PubMed: 10491430
African-American Model:
- Gail MH, Costantino JP, Pee D, et al. Projecting individualized absolute invasive breast cancer risk in African American women. J Natl Cancer Inst. 2007;99(23):1782-1792.
- PubMed: 18042936
Asian/Pacific Islander Model:
- Matsuno RK, Costantino JP, Ziegler RG, et al. Projecting individualized absolute invasive breast cancer risk in Asian and Pacific Islander American women. J Natl Cancer Inst. 2011;103(12):951-961.
- PubMed: 21562243
Hispanic Model:
- Banegas MP, John EM, Slattery ML, et al. Projecting individualized absolute invasive breast cancer risk in US Hispanic women. J Natl Cancer Inst. 2017;109(2):djw215.
- PubMed: 28003316
Model Limitations
- Does not include BRCA1/BRCA2 mutations (use other tools for hereditary cancer syndromes)
- Limited to women ≥ 20 years old without prior breast cancer
- May underestimate risk for women with strong family histories
- Does not account for breast density or all environmental factors
- Population-based estimates may not apply to all individuals
Development
Setup
# Clone the repository
git clone https://github.com/epiverse/bcra-js.git
cd bcra-js/packages/bcra
# Install dependencies
npm installRunning Tests
# Run all tests
npm test
# Run tests with UI
npm run test:ui
# Run tests with coverage
npm run test:coverage
# Watch mode
npm run test:watchBuilding
# Build library for distribution
npm run build
# Output: dist/bcra.es.js and dist/bcra.umd.jsCode Quality
# Lint code
npm run lint
# Format code
npm run format
# Type check
npm run type-checkProject Structure
packages/bcra/
├── src/
│ ├── index.js # Main entry point
│ ├── constants/ # Beta, lambda1, lambda2, AR
│ ├── core/ # Risk calculation modules
│ │ ├── recode-check.js # Validation and recoding
│ │ ├── relative-risk.js # Relative risk calculation
│ │ ├── absolute-risk.js # Absolute risk calculation
│ │ └── risk-calculator.js # Main API
│ ├── utils/ # Helper functions
│ │ ├── validators.js # Input validation
│ │ └── error-handler.js # Error handling
│ └── types/ # Type definitions
│ └── index.js # JSDoc types
├── test/ # Test suites
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests
├── types/ # TypeScript definitions
│ └── index.d.ts
├── dist/ # Built library (generated)
├── package.json
├── vite.config.js
└── README.mdContributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
npm test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Coding Standards
- Follow existing code style (enforced by ESLint and Prettier)
- Write comprehensive tests for new features
- Add JSDoc comments for all public functions
- Update TypeScript definitions if API changes
- Keep functions focused and modular
Publishing to NPM
For Maintainers Only
This section describes how to publish new versions of the BCRA package to NPM.
Prerequisites
- Write access to the repository
- NPM account with publish permissions (configured as
NPM_TOKENsecret in GitHub)
Publishing Process
Update Version
# Update version in package.json (following semantic versioning) npm version patch # Bug fixes (1.0.0 → 1.0.1) npm version minor # New features (1.0.0 → 1.1.0) npm version major # Breaking changes (1.0.0 → 2.0.0)Commit Version Change
git add package.json git commit -m "Bump version to X.Y.Z" git push origin mainTrigger GitHub Action
- Go to Actions tab in GitHub repository
- Select "Publish to NPM" workflow
- Click "Run workflow"
- Select branch (usually
main) - Click "Run workflow" button
Automated Process
The GitHub Action will automatically:
- ✅ Run all tests
- ✅ Build the library
- ✅ Check bundle sizes
- ✅ Verify package contents
- ✅ Check if version already exists on NPM
- ✅ Publish to NPM (if version is new)
- ✅ Create Git tag (
vX.Y.Z) - ✅ Create GitHub Release with CDN links
Verify Publication
After successful publication:
- NPM: https://www.npmjs.com/package/bcra
- jsDelivr: https://cdn.jsdelivr.net/npm/[email protected]/
- unpkg: https://app.unpkg.com/[email protected]
- GitHub Releases: https://github.com/epiverse/bcra-js/releases
Local Testing Before Publishing
Test the package locally before publishing:
cd packages/bcra
# Create a package tarball
npm pack
# This creates bcra-X.Y.Z.tgz
# Test in another project
cd /path/to/test-project
npm install /path/to/bcra-X.Y.Z.tgz
# Verify it works
node -e "const { calculateRisk } = require('bcra'); console.log(calculateRisk);"Rollback Procedure
If a published version has critical issues:
Deprecate the problematic version:
npm deprecate [email protected] "Critical bug - use version X.Y.Z+1 instead"Publish a patch version with the fix following the normal process above
Note: NPM does not allow unpublishing packages after 24 hours. Deprecation is the recommended approach.
Version Numbering Guidelines
Follow Semantic Versioning:
- Patch (1.0.x): Bug fixes, performance improvements, documentation updates
- Minor (1.x.0): New features, new race models, API additions (backward compatible)
- Major (x.0.0): Breaking API changes, removed features, major refactoring
For more detailed publishing documentation, see PUBLISHING.md.
Disclaimer
⚠️ IMPORTANT MEDICAL DISCLAIMER
This tool is provided for research, educational, and informational purposes only. It should NOT be used as a substitute for professional medical advice, diagnosis, or treatment.
Key Points:
Not Medical Advice: The breast cancer risk estimates provided by this tool are statistical projections based on population data and may not reflect an individual's actual risk.
Consult Healthcare Providers: Always seek the advice of qualified healthcare providers with any questions you may have regarding breast cancer risk, screening, or medical conditions.
Individual Variation: Individual risk can vary significantly based on factors not included in this model (e.g., BRCA mutations, breast density, detailed family history).
No Warranty: This software is provided "as is" without warranty of any kind. The authors and copyright holders are not liable for any damages arising from the use of this software.
Clinical Validation Required: Before using this tool in any clinical setting, appropriate validation and regulatory compliance must be obtained.
Not for Diagnostic Use: This tool calculates risk estimates only and does not diagnose breast cancer or any other medical condition.
If you have concerns about breast cancer risk, please consult with your healthcare provider, who can consider your complete medical history and recommend appropriate screening and prevention strategies.
Acknowledgments
- Original Model: Dr. Mitchell H. Gail and colleagues at the National Cancer Institute
- R Package: Fanni Zhang and contributors
- Data Sources: SEER Program, NCHS, CARE Study, SFBCS, AABCS
- Scientific Community: Researchers who validated and extended the Gail Model for diverse populations
Support
- Documentation: Full Documentation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
