npm package: @smcuivre/common
Description: Common utilities and libraries for the SMC project
Latest version: 0.1.19

# @smc/common

Common utilities and libraries for the SMC project. This package provides reusable components and utilities that can be shared across different SMC services and applications.

## Installation

```bash
npm install @smc/common
```

or with yarn:

```bash
yarn add @smc/common
```

## Libraries

### SSM Parameters

A focused utility for storing AWS Systems Manager Parameter Store parameters with descriptions and automatic path resolution based on environment context.

#### Features

  - ✅ Store parameters with descriptions/comments for documentation
  - ✅ Automatic path resolution based on environment (dev, prod, staging, etc.)
  - ✅ Support for global parameters shared across all environments
  - ✅ Support for String, StringList, and SecureString parameter types
  - ✅ Batch parameter storage
  - ✅ **Predefined parameter keys** with type-safe enum (SSM_PARAM_KEY)
  - ✅ **Repository pattern** for working with known parameter keys
  - ✅ Automatic type detection (secure vs non-secure parameters)
  - ✅ Full TypeScript support with comprehensive type definitions

#### Quick Start

```typescript
import { SSMParams } from '@smc/common';

// Initialize for development environment
const ssmParams = new SSMParams({
  region: 'us-east-1',
  environment: 'dev',  // 'dev', 'prod', 'staging', etc.
  basePath: '/smc'     // Optional: defaults to '/smc'
});

// Store an environment-specific parameter with description
await ssmParams.storeParameter({
  key: 'database/url',
  value: 'postgresql://localhost:5432/mydb',
  description: 'Database connection URL for the application',
  type: 'String'
});
// Stored at: /smc/dev/database/url

// Store a global parameter (shared across all environments)
await ssmParams.storeParameter({
  key: 'company/name',
  value: 'SMC Corporation',
  description: 'Company name used in all environments',
  isGlobal: true
});
// Stored at: /smc/global/company/name

// Store a secure parameter
await ssmParams.storeParameter({
  key: 'secrets/api-key',
  value: 'super-secret-key',
  description: 'Third-party API key',
  type: 'SecureString',
  keyId: 'alias/aws/ssm'
});
// Stored at: /smc/dev/secrets/api-key

// Store multiple parameters at once
await ssmParams.storeParameters([
  {
    key: 'database/host',
    value: 'localhost',
    description: 'Database host'
  },
  {
    key: 'database/port',
    value: '5432',
    description: 'Database port'
  },
  {
    key: 'api/timeout',
    value: '30',
    description: 'API timeout in seconds'
  }
]);

  
  #### Using the Repository Pattern (Recommended for Runtime)
  
  For better type safety and automatic parameter handling, use `SSMParamsRepository` with predefined keys:
  
  ```typescript
  import { SSMParamsRepository, SSM_PARAM_KEY } from '@smc/common';
  
  // Initialize the repository
  const repository = new SSMParamsRepository({
    region: 'us-east-1',
    environment: 'dev',
    basePath: '/smc'
  });
  
  // Store with predefined keys (auto descriptions and type detection)
  await repository.storeByKey(
    SSM_PARAM_KEY.COGNITO_USER_POOL_ID,
    'us-east-1_abc123DEF'
  );
  // Automatically uses description and String type
  
  // Secure parameters are automatically encrypted
  await repository.storeByKey(
    SSM_PARAM_KEY.DB_PASSWORD,
    'super-secret-password'
  );
  // Automatically stored as SecureString
  
  // Batch store with predefined keys
  await repository.storeByKeys([
    { key: SSM_PARAM_KEY.GRAPHQL_HTTP_URL, value: 'https://api.example.com/graphql' },
    { key: SSM_PARAM_KEY.BASE_HOST, value: 'https://app.smc.com' },
    { key: SSM_PARAM_KEY.DB_USER, value: 'smc_user' }
  ]);
  
  // Check where parameters are stored
  console.log(repository.resolveKeyPath(SSM_PARAM_KEY.COGNITO_USER_POOL_ID));
  // Output: /smc/dev/user-pool-id
  ```
  
  #### Available Parameter Keys
  
  The `SSM_PARAM_KEY` enum includes all predefined keys for the SMC application:
  
  **Authentication**
  - `COGNITO_USER_POOL_ID`
  - `COGNITO_USER_POOL_WEB_CLIENT_ID`
  - `COGNITO_OAUTH_DOMAIN`
  
  **Monitoring (RUM)**
  - `RUM_GUEST_ROLE_ARN`
  - `RUM_IDENTITY_POOL_ID`
  - `RUM_APP_ID`
  
  **GraphQL API**
  - `GRAPHQL_HTTP_URL`
  - `GRAPHQL_WS_URL`
  - `GRAPHQL_HOST`
  - `GRAPHQL_API_ID`
  
  **Medical Assets**
  - `MEDICAL_ASSETS_AWS_CLOUDFRONT_PRIVATE_KEY` (secure)
  - `MEDICAL_ASSETS_AWS_CLOUDFRONT_KEY_ID`
  - `MEDICAL_ASSETS_BUCKET_NAME`
  - `MEDICAL_ASSETS_DISTRIBUTION_DOMAIN_NAME`
  
  **Storage**
  - `PUBLIC_ASSETS_BUCKET_NAME`
  
  **Database**
  - `DB_USER`
  - `DB_PASSWORD` (secure)
  
  **Application**
  - `BASE_HOST`
  - `EMAIL_FROM_ADDRESS`
  
  **Events**
  - `EVENT_API_REAL_TIME_DNS`
  - `EVENT_API_HTTP_DNS`
  - `NOTIFIED_EVENT_ACTIONS`
  
```


#### AWS-Agnostic Path & ARN Utilities

You can build SSM parameter paths and ARNs in a cloud-agnostic way, supporting both environment-specific and shared/global conventions:

```typescript
import { buildSSMParameterPath, buildSSMParameterArn, SSM_PARAM_KEY } from '@smc/common';

// Build a path for a parameter in a specific environment
const path1 = buildSSMParameterPath(SSM_PARAM_KEY.DB_PASSWORD, {
  environment: 'dev',
  basePath: '/myapp',
});
// /myapp/dev/db-password

// Build a path for a global/common parameter
const path2 = buildSSMParameterPath('company-name', {
  isGlobal: true,
  basePath: '/myapp',
});
// /myapp/company-name

// Build a path for a shared service style (e.g., /myapp/dev/param1)
const path3 = buildSSMParameterPath('param1', {
  environment: 'dev',
  basePath: '/myapp',
  sharedServiceStyle: true,
});
// /myapp/dev/param1

// Build the ARN for a parameter (for cross-account access)
const arn = buildSSMParameterArn({
  region: 'us-east-1',
  account: '123456789012',
  paramPath: path1,
});
// arn:aws:ssm:us-east-1:123456789012:parameter/myapp/dev/db-password
```

---

#### API Reference

##### Constructor

```typescript
new SSMParams(config?: SSMParamsConfig)
```

**SSMParamsConfig:**
- `region?: string` - AWS region for SSM client
- `environment?: string` - Environment name (e.g., 'dev', 'prod', 'staging'). Default: 'dev'
- `basePath?: string` - Base path for all parameters. Default: '/smc'

##### Methods

###### resolvePath(key, isGlobal?)

Resolve the full SSM parameter path based on environment context.

```typescript
resolvePath(key: string, isGlobal?: boolean): string
```

**Parameters:**
- `key` - Parameter key (without environment prefix)
- `isGlobal` - Whether this is a global parameter. Default: `false`

**Returns:** Full parameter path

**Examples:**
- `resolvePath('database/host')` → `/smc/dev/database/host`
- `resolvePath('api-key', true)` → `/smc/global/api-key`

###### storeParameter(param)

Store a single parameter in Parameter Store with its description.

```typescript
async storeParameter(param: ParameterDefinition): Promise<number>
```

**ParameterDefinition:**
- `key: string` - Parameter key/name (without environment prefix)
- `value: string` - Parameter value
- `description?: string` - Description/comment for documentation
- `type?: 'String' | 'StringList' | 'SecureString'` - Parameter type. Default: 'String'
- `isGlobal?: boolean` - Whether this is a global parameter. Default: `false`
- `keyId?: string` - KMS key ID for SecureString parameters

**Returns:** Parameter version number

###### storeParameters(params)

Store multiple parameters at once.

```typescript
async storeParameters(params: ParameterDefinition[]): Promise<number[]>
```

**Returns:** Array of version numbers for each stored parameter

###### getEnvironment()

Get the current environment name.

```typescript
getEnvironment(): string
```

###### getBasePath()

Get the base path for parameters.

```typescript
getBasePath(): string
```

###### getClient()

Get the raw SSM client for advanced operations.

```typescript
getClient(): SSMClient
  ##### SSMParamsRepository
  
  Extends `SSMParams` with additional methods for working with predefined keys.
  
  ###### storeByKey(key, value, options?)
  
  Store a parameter using a predefined key with automatic description and type detection.
  
  ```typescript
  async storeByKey(
    key: SSM_PARAM_KEY,
    value: string,
    options?: {
      description?: string;
      isGlobal?: boolean;
      type?: 'String' | 'StringList' | 'SecureString';
      keyId?: string;
    }
  ): Promise<number>
  ```
  
  ###### resolveKeyPath(key, isGlobal?)
  
  Resolve the full path for a predefined parameter key.
  
  ```typescript
  resolveKeyPath(key: SSM_PARAM_KEY, isGlobal?: boolean): string
  ```
  
  ###### storeByKeys(params)
  
  Store multiple parameters by predefined keys.
  
  ```typescript
  async storeByKeys(
    params: Array<{
      key: SSM_PARAM_KEY;
      value: string;
      description?: string;
      isGlobal?: boolean;
      type?: 'String' | 'StringList' | 'SecureString';
      keyId?: string;
    }>
  ): Promise<number[]>
  ```
  
```

#### Examples
  ##### Using Repository Pattern with Predefined Keys
  
  ```typescript
  import { SSMParamsRepository, SSM_PARAM_KEY } from '@smc/common';
  
  const repository = new SSMParamsRepository({
    region: 'us-east-1',
    environment: 'dev',
    basePath: '/smc'
  });
  
  // Store authentication parameters
  await repository.storeByKey(
    SSM_PARAM_KEY.COGNITO_USER_POOL_ID,
    'us-east-1_abc123'
  );
  // Auto description: "AWS Cognito User Pool ID for authentication"
  // Auto type: String
  
  // Store secure parameter (automatically encrypted)
  await repository.storeByKey(
    SSM_PARAM_KEY.DB_PASSWORD,
    'my-secure-password'
  );
  // Auto type: SecureString
  
  // Batch store with type safety
  await repository.storeByKeys([
    { 
      key: SSM_PARAM_KEY.GRAPHQL_HTTP_URL,
      value: 'https://api.example.com/graphql'
    },
    { 
      key: SSM_PARAM_KEY.GRAPHQL_WS_URL,
      value: 'wss://api.example.com/graphql'
    },
    {
      key: SSM_PARAM_KEY.EMAIL_FROM_ADDRESS,
      value: 'noreply@smc.com',
      isGlobal: true  // Store globally
    }
  ]);
  ```
  

##### Environment-Based Configuration

```typescript
// Development environment
const devParams = new SSMParams({
  region: 'us-east-1',
  environment: 'dev',
  basePath: '/smc'
});

await devParams.storeParameter({
  key: 'database/url',
  value: 'postgresql://dev-db:5432/app',
  description: 'Development database connection'
});
// Stored at: /smc/dev/database/url

// Production environment
const prodParams = new SSMParams({
  region: 'us-east-1',
  environment: 'prod',
  basePath: '/smc'
});

await prodParams.storeParameter({
  key: 'database/url',
  value: 'postgresql://prod-db:5432/app',
  description: 'Production database connection'
});
// Stored at: /smc/prod/database/url
```

##### Global Parameters

```typescript
const ssmParams = new SSMParams({
  region: 'us-east-1',
  environment: 'dev'
});

// Global parameters are shared across all environments
await ssmParams.storeParameter({
  key: 'branding/logo-url',
  value: 'https://cdn.example.com/logo.png',
  description: 'Company logo URL used across all environments',
  isGlobal: true
});
// Stored at: /smc/global/branding/logo-url
```

##### Secure Parameters

```typescript
// Store sensitive data as SecureString
await ssmParams.storeParameter({
  key: 'secrets/database-password',
  value: 'super-secret-password',
  description: 'Database master password',
  type: 'SecureString',
  keyId: 'alias/aws/ssm' // Use specific KMS key
});
```

##### Batch Parameter Storage

```typescript
// Store all application configuration at once
const configs = [
  {
    key: 'api/base-url',
    value: 'https://api.dev.example.com',
    description: 'Base URL for API calls'
  },
  {
    key: 'api/timeout',
    value: '30000',
    description: 'API request timeout in milliseconds'
  },
  {
    key: 'features/new-ui-enabled',
    value: 'true',
    description: 'Feature flag for new UI'
  },
  {
    key: 'logging/level',
    value: 'debug',
    description: 'Application logging level'
  }
];

const versions = await ssmParams.storeParameters(configs);
console.log(`Stored ${versions.length} parameters`);
```

##### Path Resolution

```typescript
const ssmParams = new SSMParams({
  environment: 'staging',
  basePath: '/myapp'
});

// Check where parameters will be stored
console.log(ssmParams.resolvePath('config/setting'));
// Output: /myapp/staging/config/setting

console.log(ssmParams.resolvePath('shared/constant', true));
// Output: /myapp/global/shared/constant

console.log(ssmParams.getEnvironment());
// Output: staging

console.log(ssmParams.getBasePath());
// Output: /myapp
```

## Development

### Building

```bash
npm run build
```

### Testing

```bash
npm test
```

### Linting

```bash
npm run eslint
```

## Publishing

This package is configured for automatic publishing to npm. To publish a new version:

1. Update the version in `.projenrc.ts`
2. Run `npx projen` to regenerate files
3. Commit and push changes
4. Create a release tag

## License

Apache-2.0

## Contributing

Contributions are welcome! Please ensure all tests pass and follow the existing code style.

---

**Part of the SMC Project**