All files / src/handlers direct-hello.ts

100% Statements 10/10
100% Branches 3/3
100% Functions 2/2
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157                                                                                                                                                                                      4x 5x   5x 2x           3x                                                                                 4x       3x   3x                
import type { Context } from 'aws-lambda'
 
/**
 * @interface DirectHelloEvent
 *
 * Raw event payload for direct Lambda invocation.
 * Contains optional user-provided name for greeting customization.
 * Public contract expected by consumers invoking the Lambda directly via AWS API.
 *
 * @property {string} [name] - Optional name to use in the greeting message
 *
 * @author Bayu Dwiyan Satria
 * @since 1.0.0
 * @see {@link directHelloHandler}
 * @see {@link resolveDirectHelloInput}
 */
export interface DirectHelloEvent {
  name?: string
}
 
/**
 * @interface DirectHelloInput
 *
 * Normalized input resolved from a {@link DirectHelloEvent}.
 * Abstracts name resolution logic and tracks the source of the value
 * for observability and debugging purposes.
 *
 * @property {string} name - Resolved display name (provided or default "world")
 * @property {('event' | 'default')} source - Origin: 'event' if provided, 'default' if fallback used
 *
 * @author Bayu Dwiyan Satria
 * @since 1.0.0
 * @see {@link resolveDirectHelloInput}
 * @see {@link directHelloHandler}
 */
export interface DirectHelloInput {
  name: string
  source: 'event' | 'default'
}
 
/**
 * @interface DirectHelloResponse
 *
 * Response returned by {@link directHelloHandler} for direct Lambda invocations.
 * Includes greeting message, request metadata, and input resolution details
 * for logging and observability.
 *
 * @property {string} message - The greeting message (e.g., "Hello, Bayu!")
 * @property {string} requestId - AWS request ID from Lambda context
 * @property {string} timestamp - ISO 8601 timestamp of the invocation
 * @property {DirectHelloInput} input - Normalized input including name source
 *
 * @author Bayu Dwiyan Satria
 * @since 1.0.0
 * @see {@link directHelloHandler}
 */
export interface DirectHelloResponse {
  message: string
  requestId: string
  timestamp: string
  input: DirectHelloInput
}
 
/**
 * @function resolveDirectHelloInput
 *
 * Resolves the name used by the directly invoked sample Lambda.
 * Extracts and validates the name from the event, falling back to "world"
 * if not provided or if the provided value is empty after trimming.
 *
 * @returns {DirectHelloInput} Normalized input with resolved name and source tracking
 *
 * @example
 * // With provided name
 * const input = resolveDirectHelloInput({ name: 'Bayu' });
 * // { name: 'Bayu', source: 'event' }
 *
 * @example
 * // Empty string falls back to default
 * const input = resolveDirectHelloInput({ name: '   ' });
 * // { name: 'world', source: 'default' }
 *
 * @example
 * // Undefined/missing event falls back to default
 * const input = resolveDirectHelloInput();
 * // { name: 'world', source: 'default' }
 *
 * @author Bayu Dwiyan Satria
 * @since 1.0.0
 * @see {@link directHelloHandler}
 */
export const resolveDirectHelloInput = (event: DirectHelloEvent = {}): DirectHelloInput => {
  const eventName = event.name?.trim()
 
  if (eventName) {
    return {
      name: eventName,
      source: 'event'
    }
  }
 
  return {
    name: 'world',
    source: 'default'
  }
}
 
/**
 * @function directHelloHandler
 *
 * Sample AWS Lambda handler for direct invocation through AWS Lambda APIs or console.
 * No API Gateway or EventBridge trigger; invoked directly via `aws lambda invoke` or
 * through the Serverless Framework. Accepts a JSON event with optional name field
 * and returns a greeting response with metadata.
 *
 * @param {DirectHelloEvent} [event] - Direct invocation event payload (optional name, defaults to `{}`)
 * @param {Context} context - Lambda invocation context
 * @returns {Promise<DirectHelloResponse>} Greeting response with message and metadata
 *
 * @example
 * // AWS CLI direct invocation
 * ```typescript
 * // aws lambda invoke --function-name my-function --payload '{"name":"Bayu"}' response.json
 * const response = await directHelloHandler(
 *   { name: 'Bayu' },
 *   context
 * );
 * // { message: 'Hello, Bayu!', requestId: 'xxx', timestamp: '...', input: {...} }
 * ```
 *
 * @example
 * // Invocation without name (uses default)
 * ```typescript
 * const response = await directHelloHandler({}, context);
 * // { message: 'Hello, world!', requestId: 'xxx', timestamp: '...', input: {...} }
 * ```
 *
 * @author Bayu Dwiyan Satria
 * @since 1.0.0
 * @see {@link resolveDirectHelloInput}
 * @see {@link DirectHelloResponse}
 */
export const directHelloHandler = async (
  event: DirectHelloEvent = {},
  context: Context
): Promise<DirectHelloResponse> => {
  const input = resolveDirectHelloInput(event)
 
  return {
    message: `Hello, ${input.name}!`,
    requestId: context.awsRequestId,
    timestamp: new Date().toISOString(),
    input
  }
}