diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd0c5ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +node_modules/ + +# Build artifacts +*.tgz +dist/ + +# Environment variables +.env +.env.local + +# OS generated files +.DS_Store +Thumbs.db + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo \ No newline at end of file diff --git a/README.md b/README.md index d101457..71d694c 100644 --- a/README.md +++ b/README.md @@ -1 +1,107 @@ -# cutedynamodb \ No newline at end of file +# cute-dynamo + +A minimalistic DynamoDB client library with a cute API design for Node.js applications. + +## Features + +- 🎯 Simple and intuitive API +- 🔐 Supports both client-side (Cognito Identity Pool) and server-side (Access Key) authentication +- 📦 Lightweight with minimal dependencies +- 🚀 Built on AWS SDK v3 +- 💡 Environment variable support for easy configuration + +## Installation + +```bash +npm install cute-dynamo +``` + +## Quick Start + +### Initialize the client + +```javascript +import { init, table } from 'cute-dynamo'; + +// Server-side authentication (reads from environment variables) +await init(); + +// Or provide credentials explicitly +await init({ + region: 'us-east-1', + accessKeyId: 'YOUR_ACCESS_KEY', + secretAccessKey: 'YOUR_SECRET_KEY' +}); + +// Client-side authentication with Cognito Identity Pool +await init({ + region: 'us-east-1', + identityPoolId: 'us-east-1:your-identity-pool-id' +}); +``` + +### Environment Variables + +The library can automatically read from these environment variables: + +- `AWS_REGION` - AWS region +- `AWS_ACCESS_KEY_ID` - AWS access key ID (for server-side) +- `AWS_SECRET_ACCESS_KEY` - AWS secret access key (for server-side) +- `AWS_IDENTITY_POOL_ID` - Cognito Identity Pool ID (for client-side) +- `DYNAMODB_TABLE` - Default table name + +### Basic Operations + +```javascript +// Get an item +const item = await table('your-table-name') + .at({ pk: 'user123', sk: 'profile' }) + .get(); + +// Put an item +await table('your-table-name') + .at({ pk: 'user123', sk: 'profile' }) + .put({ name: 'John Doe', email: 'john@example.com' }); + +// Using environment variable for table name +await table() // Uses DYNAMODB_TABLE env var + .at({ pk: 'user123', sk: 'profile' }) + .get(); +``` + +## API Reference + +### `init(options)` + +Initializes the DynamoDB client. + +**Parameters:** +- `options.region` - AWS region (default: `process.env.AWS_REGION`) +- `options.accessKeyId` - AWS access key ID (default: `process.env.AWS_ACCESS_KEY_ID`) +- `options.secretAccessKey` - AWS secret access key (default: `process.env.AWS_SECRET_ACCESS_KEY`) +- `options.identityPoolId` - Cognito Identity Pool ID (default: `process.env.AWS_IDENTITY_POOL_ID`) + +### `table(tableName)` + +Creates a table instance for operations. + +**Parameters:** +- `tableName` - Name of the DynamoDB table (default: `process.env.DYNAMODB_TABLE`) + +**Returns:** Table instance with `at()` method + +### Table Methods + +#### `.at(key).get()` +Retrieves an item from the table. + +#### `.at(key).put(data)` +Stores an item in the table. + +## License + +MIT + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..e4c5705 --- /dev/null +++ b/index.js @@ -0,0 +1,94 @@ +import {DynamoDBDocumentClient} from "@aws-sdk/lib-dynamodb"; +import {DynamoDBClient} from "@aws-sdk/client-dynamodb"; + +let client; + +/** + * Initializes the DynamoDB client for cute-dynamo library usage. It configures the client based on the environment and credentials provided. + * This function supports two authentication methods: + * 1. Client-side authentication using an AWS Identity Pool ID for applications where AWS credentials are managed client-side. + * 2. Server-side authentication using AWS Access Key ID and AWS Secret Access Key for server-side applications. + * + * By adhering to cute-dynamo's minimalistic design, this initialization sets the stage for interacting with DynamoDB tables that conform to the specified naming conventions and data structure rules. + * + * @param {Object} options - Configuration options for the DynamoDB client. Includes region, identityPoolId, accessKeyId, and secretAccessKey. + * @param {string} [options.region=process.env.AWS_REGION] - The AWS region where the DynamoDB instance is hosted. + * @param {string} [options.identityPoolId=process.env.AWS_IDENTITY_POOL_ID] - The AWS Cognito Identity Pool ID for client-side authentication. Optional if server-side credentials are provided. + * @param {string} [options.accessKeyId=process.env.AWS_ACCESS_KEY_ID] - The AWS Access Key ID for server-side authentication. Required if not using client-side authentication with an Identity Pool ID. + * @param {string} [options.secretAccessKey=process.env.AWS_SECRET_ACCESS_KEY] - The AWS Secret Access Key for server-side authentication. Required if not using client-side authentication. + * + * @throws {Error} Throws an error if insufficient credentials are provided for either authentication method. + * + * @example + * // Initialize for server-side usage or client-side with an identity pool ID + * // Server-side reads env vars: AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY + * // Client-side reads env vars: AWS_REGION, AWS_IDENTITY_POOL_ID, + * await init(); + * + * @example + * // Initialize for client-side usage with an identity pool ID + * await init({ region: 'us-east-1', identityPoolId: 'us-east-1:exampleId' }); + * + * @example + * // Initialize for server-side usage with access key and secret key + * await init({ region: 'us-east-1', accessKeyId: 'AKIAEXAMPLE', secretAccessKey: 'secret' }); + */ +export async function init({ + region = typeof process !== 'undefined' ? process.env.AWS_REGION : undefined, + identityPoolId = typeof process !== 'undefined' ? process.env.AWS_IDENTITY_POOL_ID : undefined, + accessKeyId = typeof process !== 'undefined' ? process.env.AWS_ACCESS_KEY_ID : undefined, + secretAccessKey = typeof process !== 'undefined' ? process.env.AWS_SECRET_ACCESS_KEY : undefined +} = {}) { + let credentials; + + if (identityPoolId) { + const {CognitoIdentityClient} = await import("@aws-sdk/client-cognito-identity"); + const {fromCognitoIdentityPool} = await import("@aws-sdk/credential-provider-cognito-identity"); + credentials = fromCognitoIdentityPool({ + client: new CognitoIdentityClient({region}), + identityPoolId, + }); + } else if (accessKeyId && secretAccessKey) { + credentials = { + accessKeyId, + secretAccessKey + }; + } else { + throw new Error("Insufficient credentials provided"); + } + + client = DynamoDBDocumentClient.from(new DynamoDBClient({region, credentials})); +} + +/** + * Creates a DynamoDB table instance for performing operations on items. + * + * @param {string} [tablename] - The name of the DynamoDB table. If not provided, the value of the `DYNAMODB_TABLE` environment variable is used. + * @returns {Object} An object with an `at` method for specifying the primary key and sort key of an item. + * + * @example + * const item = await table('yourtablename').at({'yourPKkeyName': 'PKvalue', 'yourSKname': 1711900504}).get(); + */ +export const table = (tablename) => { + return { + at: (PKorPKSK) => { + return { + get: async () => { + const {GetCommand} = await import("@aws-sdk/lib-dynamodb"); + const response = await client.send(new GetCommand({ + TableName: tablename || (typeof process !== 'undefined' ? process.env.DYNAMODB_TABLE : undefined), + Key: PKorPKSK, + })); + return response.Item && response.Item.JSON ? JSON.parse(response.Item.JSON) : response.Item || null; + }, + put: async (data) => { + const {PutCommand} = await import("@aws-sdk/lib-dynamodb"); + return await client.send(new PutCommand({ + TableName: tablename || (typeof process !== 'undefined' ? process.env.DYNAMODB_TABLE : undefined), + Item: {...PKorPKSK, JSON: JSON.stringify(data)}, + })); + } + }; + } + }; +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..e188973 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "cutedynamodb", + "version": "0.1.0", + "description": "A minimalistic DynamoDB client library with a cute API design", + "main": "dist/index.js", + "type": "module", + "scripts": { + "bundle": "npx esbuild index.js --bundle --outfile=dist/index.js --platform=browser --target=es2022 --format=esm" + }, + "author": "PlanetRenox", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/PlanetRenox/cute-dynamo.git" + }, + "bugs": { + "url": "https://github.com/PlanetRenox/cute-dynamo/issues" + }, + "homepage": "https://github.com/PlanetRenox/cute-dynamo#readme", + "dependencies": { + "@aws-sdk/lib-dynamodb": "^3.0.0", + "@aws-sdk/client-dynamodb": "^3.0.0", + "@aws-sdk/client-cognito-identity": "^3.0.0", + "@aws-sdk/credential-provider-cognito-identity": "^3.0.0" + }, + "devDependencies": { + "esbuild": "^0.20.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "files": [ + "index.js", + "README.md" + ] +}