Initial commit: add .gitignore and README
This commit is contained in:
12
.changeset/config.json
Normal file
12
.changeset/config.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
|
||||||
|
"changelog": "@changesets/cli/changelog",
|
||||||
|
"commit": false,
|
||||||
|
"fixed": [],
|
||||||
|
"linked": [],
|
||||||
|
"access": "restricted",
|
||||||
|
"baseBranch": "main",
|
||||||
|
"updateInternalDependencies": "patch",
|
||||||
|
"ignore": []
|
||||||
|
}
|
||||||
|
|
||||||
49
.gitignore
vendored
Normal file
49
.gitignore
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
.pnpm-store/
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# Package manager lock files (optional: uncomment to ignore)
|
||||||
|
# package-lock.json
|
||||||
|
# yarn.lock
|
||||||
|
|
||||||
|
# Environment and secrets
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
*.env.backup
|
||||||
|
.env.backup.*
|
||||||
|
|
||||||
|
# Logs and temp
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
*.tmp.*
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Build / output
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.next/
|
||||||
|
out/
|
||||||
|
*.pyc
|
||||||
|
__pycache__/
|
||||||
|
.eggs/
|
||||||
|
*.egg-info/
|
||||||
|
.coverage
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# Optional
|
||||||
|
.reports/
|
||||||
|
reports/
|
||||||
10
.npmrc
Normal file
10
.npmrc
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Private npm registry configuration
|
||||||
|
# Uncomment and configure when registry is set up
|
||||||
|
|
||||||
|
# @workspace:registry=http://verdaccio:4873/
|
||||||
|
# //verdaccio:4873/:_authToken=${NPM_TOKEN}
|
||||||
|
|
||||||
|
# Or for GitHub Packages:
|
||||||
|
# @workspace:registry=https://npm.pkg.github.com
|
||||||
|
# //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
|
||||||
|
|
||||||
142
README.md
Normal file
142
README.md
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
# Workspace Shared Packages
|
||||||
|
|
||||||
|
**Status**: 🚧 **In Development**
|
||||||
|
**Purpose**: Shared packages and libraries for workspace projects
|
||||||
|
**Last Updated**: 2025-01-27
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This monorepo contains shared packages and libraries used across multiple projects in the workspace. It enables code reuse, consistent patterns, and simplified dependency management.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
### @workspace/shared-types
|
||||||
|
**Status**: 🚧 Planned
|
||||||
|
**Purpose**: Common TypeScript types and interfaces
|
||||||
|
**Usage**: Used across dbis_core, the_order, Sankofa, and others
|
||||||
|
|
||||||
|
### @workspace/shared-utils
|
||||||
|
**Status**: 🚧 Planned
|
||||||
|
**Purpose**: Common utility functions
|
||||||
|
**Usage**: Used in 20+ projects
|
||||||
|
|
||||||
|
### @workspace/shared-config
|
||||||
|
**Status**: 🚧 Planned
|
||||||
|
**Purpose**: Shared configuration schemas and validation
|
||||||
|
**Usage**: All projects with configuration
|
||||||
|
|
||||||
|
### @workspace/shared-constants
|
||||||
|
**Status**: 🚧 Planned
|
||||||
|
**Purpose**: Shared constants and enums
|
||||||
|
**Usage**: DBIS projects, DeFi projects
|
||||||
|
|
||||||
|
### @workspace/api-client
|
||||||
|
**Status**: 🚧 Planned
|
||||||
|
**Purpose**: Common API client utilities
|
||||||
|
**Usage**: Frontend projects, API consumers
|
||||||
|
|
||||||
|
### @workspace/validation
|
||||||
|
**Status**: 🚧 Planned
|
||||||
|
**Purpose**: Zod schemas and validators
|
||||||
|
**Usage**: Multiple backend services
|
||||||
|
|
||||||
|
### @workspace/blockchain
|
||||||
|
**Status**: 🚧 Planned
|
||||||
|
**Purpose**: Blockchain utilities and helpers
|
||||||
|
**Usage**: Blockchain projects
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Node.js >= 18.0.0
|
||||||
|
- pnpm >= 8.0.0
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# Build all packages
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
pnpm test
|
||||||
|
|
||||||
|
# Lint all packages
|
||||||
|
pnpm lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Packages
|
||||||
|
|
||||||
|
In your project's `package.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@workspace/shared-types": "workspace:*",
|
||||||
|
"@workspace/shared-utils": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Creating a New Package
|
||||||
|
|
||||||
|
1. Create package directory: `packages/package-name/`
|
||||||
|
2. Add `package.json` with proper name (`@workspace/package-name`)
|
||||||
|
3. Implement package code
|
||||||
|
4. Add to workspace configuration
|
||||||
|
5. Build and test
|
||||||
|
|
||||||
|
### Publishing
|
||||||
|
|
||||||
|
Packages are published to private npm registry (Verdaccio or GitHub Packages).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build package
|
||||||
|
cd packages/package-name
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# Publish
|
||||||
|
pnpm publish --registry=<registry-url>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
workspace-shared/
|
||||||
|
├── packages/ # Shared packages
|
||||||
|
│ ├── shared-types/
|
||||||
|
│ ├── shared-utils/
|
||||||
|
│ ├── shared-config/
|
||||||
|
│ └── ...
|
||||||
|
├── apps/ # Shared applications (if any)
|
||||||
|
├── tools/ # Development tools
|
||||||
|
├── package.json # Root package.json
|
||||||
|
├── pnpm-workspace.yaml
|
||||||
|
└── turbo.json # Turborepo configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Documents
|
||||||
|
|
||||||
|
- [Dependency Consolidation Plan](../docs/DEPENDENCY_CONSOLIDATION_PLAN.md)
|
||||||
|
- [Integration & Streamlining Plan](../INTEGRATION_STREAMLINING_PLAN.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: 2025-01-27
|
||||||
|
|
||||||
28
package.json
Normal file
28
package.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "workspace-shared",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "Shared packages and libraries for workspace projects",
|
||||||
|
"scripts": {
|
||||||
|
"build": "turbo run build",
|
||||||
|
"test": "turbo run test",
|
||||||
|
"lint": "turbo run lint",
|
||||||
|
"type-check": "turbo run type-check",
|
||||||
|
"clean": "turbo run clean"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"turbo": "^2.0.0",
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"@types/node": "^20.11.0",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
|
"eslint": "^9.17.0",
|
||||||
|
"@typescript-eslint/parser": "^7.18.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.18.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0",
|
||||||
|
"pnpm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@8.15.0"
|
||||||
|
}
|
||||||
|
|
||||||
29
packages/api-client/package.json
Normal file
29
packages/api-client/package.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "@workspace/api-client",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Common API client utilities",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"clean": "rm -rf dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.5",
|
||||||
|
"@workspace/shared-types": "workspace:*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"vitest": "^1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "restricted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
32
packages/api-client/src/client.ts
Normal file
32
packages/api-client/src/client.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* API client factory
|
||||||
|
*/
|
||||||
|
|
||||||
|
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||||
|
import { setupInterceptors } from './interceptors';
|
||||||
|
|
||||||
|
export interface ApiClientConfig extends AxiosRequestConfig {
|
||||||
|
baseURL: string;
|
||||||
|
timeout?: number;
|
||||||
|
retries?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create configured API client
|
||||||
|
*/
|
||||||
|
export function createApiClient(config: ApiClientConfig): AxiosInstance {
|
||||||
|
const client = axios.create({
|
||||||
|
baseURL: config.baseURL,
|
||||||
|
timeout: config.timeout || 30000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...config.headers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup interceptors
|
||||||
|
setupInterceptors(client, config.retries || 3);
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
9
packages/api-client/src/index.ts
Normal file
9
packages/api-client/src/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @workspace/api-client
|
||||||
|
* Common API client utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './client';
|
||||||
|
export * from './interceptors';
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
56
packages/api-client/src/interceptors.ts
Normal file
56
packages/api-client/src/interceptors.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Axios interceptors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup request and response interceptors
|
||||||
|
*/
|
||||||
|
export function setupInterceptors(client: AxiosInstance, maxRetries: number = 3): void {
|
||||||
|
// Request interceptor
|
||||||
|
client.interceptors.request.use(
|
||||||
|
(config: InternalAxiosRequestConfig) => {
|
||||||
|
// Add auth token if available
|
||||||
|
const token = process.env.API_TOKEN;
|
||||||
|
if (token && config.headers) {
|
||||||
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Response interceptor with retry logic
|
||||||
|
client.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
async (error: AxiosError) => {
|
||||||
|
const config = error.config as InternalAxiosRequestConfig & { __retryCount?: number };
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.__retryCount = config.__retryCount || 0;
|
||||||
|
|
||||||
|
// Retry on network errors or 5xx errors
|
||||||
|
if (
|
||||||
|
(error.code === 'ECONNABORTED' || (error.response?.status && error.response.status >= 500)) &&
|
||||||
|
config.__retryCount < maxRetries
|
||||||
|
) {
|
||||||
|
config.__retryCount += 1;
|
||||||
|
|
||||||
|
// Exponential backoff
|
||||||
|
const delay = Math.pow(2, config.__retryCount) * 1000;
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||||
|
|
||||||
|
return client(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
21
packages/api-client/src/types.ts
Normal file
21
packages/api-client/src/types.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* API client types
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
|
|
||||||
|
export interface ApiRequestConfig extends AxiosRequestConfig {
|
||||||
|
retries?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiResponse<T = unknown> extends AxiosResponse<T> {
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiError {
|
||||||
|
message: string;
|
||||||
|
code?: string;
|
||||||
|
status?: number;
|
||||||
|
details?: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/api-client/tsconfig.json
Normal file
20
packages/api-client/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
|
}
|
||||||
|
|
||||||
29
packages/blockchain/package.json
Normal file
29
packages/blockchain/package.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "@workspace/blockchain",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Blockchain utilities and helpers",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"clean": "rm -rf dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ethers": "^6.9.0",
|
||||||
|
"@workspace/shared-types": "workspace:*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"vitest": "^1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "restricted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
30
packages/blockchain/src/contracts.ts
Normal file
30
packages/blockchain/src/contracts.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Contract utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get contract instance
|
||||||
|
*/
|
||||||
|
export function getContract(
|
||||||
|
address: string,
|
||||||
|
abi: ethers.InterfaceAbi,
|
||||||
|
signerOrProvider: ethers.Signer | ethers.Provider
|
||||||
|
): ethers.Contract {
|
||||||
|
return new ethers.Contract(address, abi, signerOrProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy contract
|
||||||
|
*/
|
||||||
|
export async function deployContract(
|
||||||
|
signer: ethers.Signer,
|
||||||
|
contractFactory: ethers.ContractFactory,
|
||||||
|
...args: unknown[]
|
||||||
|
): Promise<ethers.Contract> {
|
||||||
|
const contract = await contractFactory.deploy(...args);
|
||||||
|
await contract.waitForDeployment();
|
||||||
|
return contract;
|
||||||
|
}
|
||||||
|
|
||||||
51
packages/blockchain/src/ethers.ts
Normal file
51
packages/blockchain/src/ethers.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Ethers.js utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create provider from RPC URL
|
||||||
|
*/
|
||||||
|
export function createProvider(rpcUrl: string): ethers.JsonRpcProvider {
|
||||||
|
return new ethers.JsonRpcProvider(rpcUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create wallet from private key
|
||||||
|
*/
|
||||||
|
export function createWallet(
|
||||||
|
privateKey: string,
|
||||||
|
provider?: ethers.Provider
|
||||||
|
): ethers.Wallet {
|
||||||
|
return new ethers.Wallet(privateKey, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format ether value
|
||||||
|
*/
|
||||||
|
export function formatEther(value: bigint): string {
|
||||||
|
return ethers.formatEther(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse ether value
|
||||||
|
*/
|
||||||
|
export function parseEther(value: string): bigint {
|
||||||
|
return ethers.parseEther(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format units
|
||||||
|
*/
|
||||||
|
export function formatUnits(value: bigint, decimals: number = 18): string {
|
||||||
|
return ethers.formatUnits(value, decimals);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse units
|
||||||
|
*/
|
||||||
|
export function parseUnits(value: string, decimals: number = 18): bigint {
|
||||||
|
return ethers.parseUnits(value, decimals);
|
||||||
|
}
|
||||||
|
|
||||||
10
packages/blockchain/src/index.ts
Normal file
10
packages/blockchain/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* @workspace/blockchain
|
||||||
|
* Blockchain utilities and helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './ethers';
|
||||||
|
export * from './transactions';
|
||||||
|
export * from './contracts';
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
45
packages/blockchain/src/transactions.ts
Normal file
45
packages/blockchain/src/transactions.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Transaction utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
|
||||||
|
export interface TransactionOptions {
|
||||||
|
gasLimit?: bigint;
|
||||||
|
gasPrice?: bigint;
|
||||||
|
maxFeePerGas?: bigint;
|
||||||
|
maxPriorityFeePerGas?: bigint;
|
||||||
|
value?: bigint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for transaction confirmation
|
||||||
|
*/
|
||||||
|
export async function waitForTransaction(
|
||||||
|
provider: ethers.Provider,
|
||||||
|
txHash: string,
|
||||||
|
confirmations: number = 1
|
||||||
|
): Promise<ethers.TransactionReceipt | null> {
|
||||||
|
return provider.waitForTransaction(txHash, confirmations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get transaction receipt
|
||||||
|
*/
|
||||||
|
export async function getTransactionReceipt(
|
||||||
|
provider: ethers.Provider,
|
||||||
|
txHash: string
|
||||||
|
): Promise<ethers.TransactionReceipt | null> {
|
||||||
|
return provider.getTransactionReceipt(txHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimate gas for transaction
|
||||||
|
*/
|
||||||
|
export async function estimateGas(
|
||||||
|
provider: ethers.Provider,
|
||||||
|
transaction: ethers.TransactionRequest
|
||||||
|
): Promise<bigint> {
|
||||||
|
return provider.estimateGas(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
25
packages/blockchain/src/types.ts
Normal file
25
packages/blockchain/src/types.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Blockchain types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface NetworkConfig {
|
||||||
|
name: string;
|
||||||
|
chainId: number;
|
||||||
|
rpcUrl: string;
|
||||||
|
explorerUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenInfo {
|
||||||
|
address: string;
|
||||||
|
symbol: string;
|
||||||
|
name: string;
|
||||||
|
decimals: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionStatus {
|
||||||
|
hash: string;
|
||||||
|
status: 'pending' | 'confirmed' | 'failed';
|
||||||
|
blockNumber?: number;
|
||||||
|
confirmations: number;
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/blockchain/tsconfig.json
Normal file
20
packages/blockchain/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
|
}
|
||||||
|
|
||||||
31
packages/shared-auth/package.json
Normal file
31
packages/shared-auth/package.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "@workspace/shared-auth",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Shared authentication and authorization utilities",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"clean": "rm -rf dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"bcryptjs": "^2.4.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"@types/jsonwebtoken": "^9.0.4",
|
||||||
|
"@types/bcryptjs": "^2.4.6",
|
||||||
|
"vitest": "^1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "restricted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
10
packages/shared-auth/src/index.ts
Normal file
10
packages/shared-auth/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* @workspace/shared-auth
|
||||||
|
* Shared authentication and authorization utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './jwt';
|
||||||
|
export * from './password';
|
||||||
|
export * from './permissions';
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
55
packages/shared-auth/src/jwt.ts
Normal file
55
packages/shared-auth/src/jwt.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* JWT token utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
export interface TokenPayload {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
roles?: string[];
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenOptions {
|
||||||
|
expiresIn?: string | number;
|
||||||
|
issuer?: string;
|
||||||
|
audience?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate JWT token
|
||||||
|
*/
|
||||||
|
export function generateToken(
|
||||||
|
payload: TokenPayload,
|
||||||
|
secret: string,
|
||||||
|
options?: TokenOptions
|
||||||
|
): string {
|
||||||
|
return jwt.sign(payload, secret, {
|
||||||
|
expiresIn: options?.expiresIn || '24h',
|
||||||
|
issuer: options?.issuer,
|
||||||
|
audience: options?.audience,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify JWT token
|
||||||
|
*/
|
||||||
|
export function verifyToken<T extends TokenPayload>(
|
||||||
|
token: string,
|
||||||
|
secret: string
|
||||||
|
): T {
|
||||||
|
return jwt.verify(token, secret) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode JWT token (without verification)
|
||||||
|
*/
|
||||||
|
export function decodeToken<T extends TokenPayload>(token: string): T | null {
|
||||||
|
try {
|
||||||
|
return jwt.decode(token) as T;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
25
packages/shared-auth/src/password.ts
Normal file
25
packages/shared-auth/src/password.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Password hashing utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import bcrypt from 'bcryptjs';
|
||||||
|
|
||||||
|
const SALT_ROUNDS = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash password
|
||||||
|
*/
|
||||||
|
export async function hashPassword(password: string): Promise<string> {
|
||||||
|
return bcrypt.hash(password, SALT_ROUNDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify password
|
||||||
|
*/
|
||||||
|
export async function verifyPassword(
|
||||||
|
password: string,
|
||||||
|
hash: string
|
||||||
|
): Promise<boolean> {
|
||||||
|
return bcrypt.compare(password, hash);
|
||||||
|
}
|
||||||
|
|
||||||
63
packages/shared-auth/src/permissions.ts
Normal file
63
packages/shared-auth/src/permissions.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* Permission checking utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type Permission = string;
|
||||||
|
export type Role = string;
|
||||||
|
|
||||||
|
export interface UserPermissions {
|
||||||
|
roles: Role[];
|
||||||
|
permissions: Permission[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has role
|
||||||
|
*/
|
||||||
|
export function hasRole(user: UserPermissions, role: Role): boolean {
|
||||||
|
return user.roles.includes(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has permission
|
||||||
|
*/
|
||||||
|
export function hasPermission(
|
||||||
|
user: UserPermissions,
|
||||||
|
permission: Permission
|
||||||
|
): boolean {
|
||||||
|
return user.permissions.includes(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has any of the required roles
|
||||||
|
*/
|
||||||
|
export function hasAnyRole(user: UserPermissions, roles: Role[]): boolean {
|
||||||
|
return roles.some((role) => hasRole(user, role));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has all required roles
|
||||||
|
*/
|
||||||
|
export function hasAllRoles(user: UserPermissions, roles: Role[]): boolean {
|
||||||
|
return roles.every((role) => hasRole(user, role));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has any of the required permissions
|
||||||
|
*/
|
||||||
|
export function hasAnyPermission(
|
||||||
|
user: UserPermissions,
|
||||||
|
permissions: Permission[]
|
||||||
|
): boolean {
|
||||||
|
return permissions.some((permission) => hasPermission(user, permission));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has all required permissions
|
||||||
|
*/
|
||||||
|
export function hasAllPermissions(
|
||||||
|
user: UserPermissions,
|
||||||
|
permissions: Permission[]
|
||||||
|
): boolean {
|
||||||
|
return permissions.every((permission) => hasPermission(user, permission));
|
||||||
|
}
|
||||||
|
|
||||||
23
packages/shared-auth/src/types.ts
Normal file
23
packages/shared-auth/src/types.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Authentication and authorization types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
roles: string[];
|
||||||
|
permissions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuthContext {
|
||||||
|
user: User | null;
|
||||||
|
isAuthenticated: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Session {
|
||||||
|
userId: string;
|
||||||
|
token: string;
|
||||||
|
expiresAt: Date;
|
||||||
|
refreshToken?: string;
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/shared-auth/tsconfig.json
Normal file
20
packages/shared-auth/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
|
}
|
||||||
|
|
||||||
29
packages/shared-config/package.json
Normal file
29
packages/shared-config/package.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "@workspace/shared-config",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Shared configuration schemas and validation",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"clean": "rm -rf dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"zod": "^3.23.8",
|
||||||
|
"dotenv": "^16.4.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"vitest": "^1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "restricted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
55
packages/shared-config/src/env.ts
Normal file
55
packages/shared-config/src/env.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Environment variable utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { config } from 'dotenv';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load environment variables
|
||||||
|
*/
|
||||||
|
export function loadEnv(envFile?: string): void {
|
||||||
|
config({ path: envFile });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get environment variable with default
|
||||||
|
*/
|
||||||
|
export function getEnv(key: string, defaultValue?: string): string {
|
||||||
|
const value = process.env[key];
|
||||||
|
if (value === undefined) {
|
||||||
|
if (defaultValue !== undefined) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
throw new Error(`Environment variable ${key} is not set`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get environment variable as number
|
||||||
|
*/
|
||||||
|
export function getEnvNumber(key: string, defaultValue?: number): number {
|
||||||
|
const value = getEnv(key, defaultValue?.toString());
|
||||||
|
const num = Number(value);
|
||||||
|
if (isNaN(num)) {
|
||||||
|
throw new Error(`Environment variable ${key} is not a valid number`);
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get environment variable as boolean
|
||||||
|
*/
|
||||||
|
export function getEnvBoolean(key: string, defaultValue?: boolean): boolean {
|
||||||
|
const value = getEnv(key, defaultValue?.toString());
|
||||||
|
return value.toLowerCase() === 'true' || value === '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate environment variables against schema
|
||||||
|
*/
|
||||||
|
export function validateEnv<T>(schema: z.ZodSchema<T>): T {
|
||||||
|
return schema.parse(process.env);
|
||||||
|
}
|
||||||
|
|
||||||
9
packages/shared-config/src/index.ts
Normal file
9
packages/shared-config/src/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @workspace/shared-config
|
||||||
|
* Shared configuration schemas and validation
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './env';
|
||||||
|
export * from './schemas';
|
||||||
|
export * from './validation';
|
||||||
|
|
||||||
37
packages/shared-config/src/schemas.ts
Normal file
37
packages/shared-config/src/schemas.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Configuration schemas
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database configuration schema
|
||||||
|
*/
|
||||||
|
export const databaseConfigSchema = z.object({
|
||||||
|
DB_HOST: z.string(),
|
||||||
|
DB_PORT: z.string().transform(Number),
|
||||||
|
DB_NAME: z.string(),
|
||||||
|
DB_USER: z.string(),
|
||||||
|
DB_PASSWORD: z.string(),
|
||||||
|
DB_SSL: z.string().optional().transform((val) => val === 'true'),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server configuration schema
|
||||||
|
*/
|
||||||
|
export const serverConfigSchema = z.object({
|
||||||
|
PORT: z.string().transform(Number).default('3000'),
|
||||||
|
NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),
|
||||||
|
HOST: z.string().default('localhost'),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT configuration schema
|
||||||
|
*/
|
||||||
|
export const jwtConfigSchema = z.object({
|
||||||
|
JWT_SECRET: z.string(),
|
||||||
|
JWT_EXPIRES_IN: z.string().default('24h'),
|
||||||
|
JWT_ISSUER: z.string().optional(),
|
||||||
|
JWT_AUDIENCE: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
27
packages/shared-config/src/validation.ts
Normal file
27
packages/shared-config/src/validation.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Configuration validation utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate configuration object
|
||||||
|
*/
|
||||||
|
export function validateConfig<T>(schema: z.ZodSchema<T>, config: unknown): T {
|
||||||
|
return schema.parse(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate configuration with error handling
|
||||||
|
*/
|
||||||
|
export function validateConfigSafe<T>(
|
||||||
|
schema: z.ZodSchema<T>,
|
||||||
|
config: unknown
|
||||||
|
): { success: true; data: T } | { success: false; error: z.ZodError } {
|
||||||
|
const result = schema.safeParse(config);
|
||||||
|
if (result.success) {
|
||||||
|
return { success: true, data: result.data };
|
||||||
|
}
|
||||||
|
return { success: false, error: result.error };
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/shared-config/tsconfig.json
Normal file
20
packages/shared-config/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
|
}
|
||||||
|
|
||||||
25
packages/shared-types/package.json
Normal file
25
packages/shared-types/package.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "@workspace/shared-types",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Common TypeScript types and interfaces",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"clean": "rm -rf dist"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"vitest": "^1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "restricted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
29
packages/shared-types/src/api.ts
Normal file
29
packages/shared-types/src/api.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* API-related types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface PaginationParams {
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
offset?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaginatedResponse<T> {
|
||||||
|
data: T[];
|
||||||
|
pagination: {
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
total: number;
|
||||||
|
totalPages: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SortParams {
|
||||||
|
field: string;
|
||||||
|
order: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FilterParams {
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
33
packages/shared-types/src/config.ts
Normal file
33
packages/shared-types/src/config.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Configuration-related types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface DatabaseConfig {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
database: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
ssl?: boolean;
|
||||||
|
pool?: {
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerConfig {
|
||||||
|
port: number;
|
||||||
|
host: string;
|
||||||
|
env: 'development' | 'staging' | 'production';
|
||||||
|
cors?: {
|
||||||
|
origin: string | string[];
|
||||||
|
credentials?: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoggingConfig {
|
||||||
|
level: 'debug' | 'info' | 'warn' | 'error';
|
||||||
|
format: 'json' | 'text';
|
||||||
|
destination?: string;
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/shared-types/src/database.ts
Normal file
20
packages/shared-types/src/database.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Database-related types
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface BaseEntity {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
deletedAt?: Date | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SoftDeletable {
|
||||||
|
deletedAt: Date | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Timestamped {
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
54
packages/shared-types/src/index.ts
Normal file
54
packages/shared-types/src/index.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* @workspace/shared-types
|
||||||
|
* Common TypeScript types and interfaces
|
||||||
|
*/
|
||||||
|
|
||||||
|
// API Response Types
|
||||||
|
export interface ApiResponse<T> {
|
||||||
|
data: T;
|
||||||
|
status: number;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiError {
|
||||||
|
code: string;
|
||||||
|
message: string;
|
||||||
|
details?: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database Types
|
||||||
|
export interface BaseEntity {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration Types
|
||||||
|
export interface DatabaseConfig {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
database: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerConfig {
|
||||||
|
port: number;
|
||||||
|
host: string;
|
||||||
|
env: 'development' | 'staging' | 'production';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common Utility Types
|
||||||
|
export type Nullable<T> = T | null;
|
||||||
|
export type Optional<T> = T | undefined;
|
||||||
|
export type Maybe<T> = T | null | undefined;
|
||||||
|
|
||||||
|
// Status Types
|
||||||
|
export type Status = 'active' | 'inactive' | 'pending' | 'archived';
|
||||||
|
export type Priority = 'low' | 'medium' | 'high' | 'critical';
|
||||||
|
|
||||||
|
// Export all types
|
||||||
|
export * from './api';
|
||||||
|
export * from './database';
|
||||||
|
export * from './config';
|
||||||
|
|
||||||
20
packages/shared-types/tsconfig.json
Normal file
20
packages/shared-types/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
|
}
|
||||||
|
|
||||||
30
packages/shared-utils/package.json
Normal file
30
packages/shared-utils/package.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@workspace/shared-utils",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Shared utility functions",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"clean": "rm -rf dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"date-fns": "^3.3.1",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"@types/uuid": "^9.0.7",
|
||||||
|
"vitest": "^1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "restricted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
35
packages/shared-utils/src/date.ts
Normal file
35
packages/shared-utils/src/date.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Date utility functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { format, parseISO, isValid } from 'date-fns';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date to ISO string
|
||||||
|
*/
|
||||||
|
export function formatDate(date: Date | string, formatStr: string = 'yyyy-MM-dd'): string {
|
||||||
|
const dateObj = typeof date === 'string' ? parseISO(date) : date;
|
||||||
|
if (!isValid(dateObj)) {
|
||||||
|
throw new Error('Invalid date');
|
||||||
|
}
|
||||||
|
return format(dateObj, formatStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date to ISO 8601
|
||||||
|
*/
|
||||||
|
export function formatISO(date: Date | string): string {
|
||||||
|
const dateObj = typeof date === 'string' ? parseISO(date) : date;
|
||||||
|
if (!isValid(dateObj)) {
|
||||||
|
throw new Error('Invalid date');
|
||||||
|
}
|
||||||
|
return dateObj.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if date is valid
|
||||||
|
*/
|
||||||
|
export function isValidDate(date: unknown): date is Date {
|
||||||
|
return date instanceof Date && isValid(date);
|
||||||
|
}
|
||||||
|
|
||||||
10
packages/shared-utils/src/index.ts
Normal file
10
packages/shared-utils/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* @workspace/shared-utils
|
||||||
|
* Shared utility functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './date';
|
||||||
|
export * from './string';
|
||||||
|
export * from './validation';
|
||||||
|
export * from './uuid';
|
||||||
|
|
||||||
58
packages/shared-utils/src/string.ts
Normal file
58
packages/shared-utils/src/string.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* String utility functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capitalize first letter
|
||||||
|
*/
|
||||||
|
export function capitalize(str: string): string {
|
||||||
|
if (!str) return str;
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string to camelCase
|
||||||
|
*/
|
||||||
|
export function toCamelCase(str: string): string {
|
||||||
|
return str
|
||||||
|
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
|
||||||
|
return index === 0 ? word.toLowerCase() : word.toUpperCase();
|
||||||
|
})
|
||||||
|
.replace(/\s+/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string to kebab-case
|
||||||
|
*/
|
||||||
|
export function toKebabCase(str: string): string {
|
||||||
|
return str
|
||||||
|
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
||||||
|
.replace(/[\s_]+/g, '-')
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string to snake_case
|
||||||
|
*/
|
||||||
|
export function toSnakeCase(str: string): string {
|
||||||
|
return str
|
||||||
|
.replace(/([a-z])([A-Z])/g, '$1_$2')
|
||||||
|
.replace(/[\s-]+/g, '_')
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncate string with ellipsis
|
||||||
|
*/
|
||||||
|
export function truncate(str: string, length: number, suffix: string = '...'): string {
|
||||||
|
if (str.length <= length) return str;
|
||||||
|
return str.slice(0, length - suffix.length) + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove whitespace
|
||||||
|
*/
|
||||||
|
export function removeWhitespace(str: string): string {
|
||||||
|
return str.replace(/\s+/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/shared-utils/src/uuid.ts
Normal file
20
packages/shared-utils/src/uuid.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* UUID utility functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { v4 as uuidv4, validate as validateUUID } from 'uuid';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate UUID v4
|
||||||
|
*/
|
||||||
|
export function generateUUID(): string {
|
||||||
|
return uuidv4();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate UUID
|
||||||
|
*/
|
||||||
|
export function isValidUUID(uuid: string): boolean {
|
||||||
|
return validateUUID(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
49
packages/shared-utils/src/validation.ts
Normal file
49
packages/shared-utils/src/validation.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Validation utility functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if value is empty
|
||||||
|
*/
|
||||||
|
export function isEmpty(value: unknown): boolean {
|
||||||
|
if (value === null || value === undefined) return true;
|
||||||
|
if (typeof value === 'string') return value.trim().length === 0;
|
||||||
|
if (Array.isArray(value)) return value.length === 0;
|
||||||
|
if (typeof value === 'object') return Object.keys(value).length === 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if value is not empty
|
||||||
|
*/
|
||||||
|
export function isNotEmpty(value: unknown): boolean {
|
||||||
|
return !isEmpty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if email is valid
|
||||||
|
*/
|
||||||
|
export function isValidEmail(email: string): boolean {
|
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||||
|
return emailRegex.test(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if URL is valid
|
||||||
|
*/
|
||||||
|
export function isValidUrl(url: string): boolean {
|
||||||
|
try {
|
||||||
|
new URL(url);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if string is numeric
|
||||||
|
*/
|
||||||
|
export function isNumeric(str: string): boolean {
|
||||||
|
return !isNaN(Number(str)) && !isNaN(parseFloat(str));
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/shared-utils/tsconfig.json
Normal file
20
packages/shared-utils/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
|
}
|
||||||
|
|
||||||
28
packages/validation/package.json
Normal file
28
packages/validation/package.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "@workspace/validation",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Zod schemas and validators",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"clean": "rm -rf dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"zod": "^3.23.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"vitest": "^1.2.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "restricted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
8
packages/validation/src/index.ts
Normal file
8
packages/validation/src/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* @workspace/validation
|
||||||
|
* Zod schemas and validators
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './schemas';
|
||||||
|
export * from './validators';
|
||||||
|
|
||||||
37
packages/validation/src/schemas.ts
Normal file
37
packages/validation/src/schemas.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Common validation schemas
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email validation schema
|
||||||
|
*/
|
||||||
|
export const emailSchema = z.string().email('Invalid email address');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UUID validation schema
|
||||||
|
*/
|
||||||
|
export const uuidSchema = z.string().uuid('Invalid UUID');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL validation schema
|
||||||
|
*/
|
||||||
|
export const urlSchema = z.string().url('Invalid URL');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pagination schema
|
||||||
|
*/
|
||||||
|
export const paginationSchema = z.object({
|
||||||
|
page: z.number().int().positive().default(1),
|
||||||
|
limit: z.number().int().positive().max(100).default(10),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort schema
|
||||||
|
*/
|
||||||
|
export const sortSchema = z.object({
|
||||||
|
field: z.string(),
|
||||||
|
order: z.enum(['asc', 'desc']).default('asc'),
|
||||||
|
});
|
||||||
|
|
||||||
27
packages/validation/src/validators.ts
Normal file
27
packages/validation/src/validators.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Validation utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate data against schema
|
||||||
|
*/
|
||||||
|
export function validate<T>(schema: z.ZodSchema<T>, data: unknown): T {
|
||||||
|
return schema.parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safe validate (returns result instead of throwing)
|
||||||
|
*/
|
||||||
|
export function validateSafe<T>(
|
||||||
|
schema: z.ZodSchema<T>,
|
||||||
|
data: unknown
|
||||||
|
): { success: true; data: T } | { success: false; error: z.ZodError } {
|
||||||
|
const result = schema.safeParse(data);
|
||||||
|
if (result.success) {
|
||||||
|
return { success: true, data: result.data };
|
||||||
|
}
|
||||||
|
return { success: false, error: result.error };
|
||||||
|
}
|
||||||
|
|
||||||
20
packages/validation/tsconfig.json
Normal file
20
packages/validation/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
|
}
|
||||||
|
|
||||||
5
pnpm-workspace.yaml
Normal file
5
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
packages:
|
||||||
|
- 'packages/*'
|
||||||
|
- 'apps/*'
|
||||||
|
- 'tools/*'
|
||||||
|
|
||||||
39
scripts/publish.sh
Executable file
39
scripts/publish.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Publish shared packages to private npm registry
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REGISTRY="${NPM_REGISTRY:-http://localhost:4873}"
|
||||||
|
SCOPE="@workspace"
|
||||||
|
|
||||||
|
echo "📦 Publishing shared packages to registry: $REGISTRY"
|
||||||
|
|
||||||
|
# Check if registry is accessible
|
||||||
|
if ! curl -s "$REGISTRY" > /dev/null; then
|
||||||
|
echo "❌ Registry not accessible at $REGISTRY"
|
||||||
|
echo " Please ensure registry is running or set NPM_REGISTRY environment variable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Publish each package
|
||||||
|
for package in packages/*/; do
|
||||||
|
if [ -f "$package/package.json" ]; then
|
||||||
|
package_name=$(basename "$package")
|
||||||
|
echo "📤 Publishing $package_name..."
|
||||||
|
|
||||||
|
cd "$package"
|
||||||
|
|
||||||
|
# Build package
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# Publish
|
||||||
|
npm publish --registry="$REGISTRY" --access restricted || {
|
||||||
|
echo "⚠️ Failed to publish $package_name (may already be published)"
|
||||||
|
}
|
||||||
|
|
||||||
|
cd - > /dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ Publishing complete!"
|
||||||
|
|
||||||
24
turbo.json
Normal file
24
turbo.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://turbo.build/schema.json",
|
||||||
|
"pipeline": {
|
||||||
|
"build": {
|
||||||
|
"dependsOn": ["^build"],
|
||||||
|
"outputs": ["dist/**", ".next/**", "build/**"]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"dependsOn": ["build"],
|
||||||
|
"outputs": ["coverage/**"]
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
"type-check": {
|
||||||
|
"dependsOn": ["^build"],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
"clean": {
|
||||||
|
"cache": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user