effortless-aws 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -86,170 +86,115 @@ declare const defineConfig: (config: EffortlessConfig) => EffortlessConfig;
86
86
  type AwsService = "dynamodb" | "s3" | "sqs" | "sns" | "ses" | "ssm" | "lambda" | "events" | "secretsmanager" | "cognito-idp" | "logs";
87
87
  type Permission = `${AwsService}:${string}` | (string & {});
88
88
 
89
- /** HTTP methods supported by API Gateway */
90
- type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
91
- /**
92
- * Incoming HTTP request object passed to the handler
93
- */
94
- type HttpRequest = {
95
- /** HTTP method (GET, POST, etc.) */
96
- method: string;
97
- /** Request path (e.g., "/users/123") */
98
- path: string;
99
- /** Request headers */
100
- headers: Record<string, string | undefined>;
101
- /** Query string parameters */
102
- query: Record<string, string | undefined>;
103
- /** Path parameters extracted from route (e.g., {id} -> params.id) */
104
- params: Record<string, string | undefined>;
105
- /** Parsed request body (JSON parsed if Content-Type is application/json) */
106
- body: unknown;
107
- /** Raw unparsed request body */
108
- rawBody?: string;
109
- };
110
89
  /**
111
- * HTTP response returned from the handler
90
+ * Query parameters for TableClient.query()
112
91
  */
113
- type HttpResponse = {
114
- /** HTTP status code (e.g., 200, 404, 500) */
115
- status: number;
116
- /** Response body (will be JSON serialized) */
117
- body?: unknown;
118
- /** Response headers */
119
- headers?: Record<string, string>;
92
+ type QueryParams = {
93
+ /** Partition key name and value */
94
+ pk: {
95
+ name: string;
96
+ value: unknown;
97
+ };
98
+ /** Optional sort key condition */
99
+ sk?: {
100
+ name: string;
101
+ condition: "=" | "begins_with" | "<" | ">" | "<=" | ">=";
102
+ value: unknown;
103
+ };
104
+ /** Maximum number of items to return */
105
+ limit?: number;
106
+ /** Sort order (true = ascending, false = descending) */
107
+ scanIndexForward?: boolean;
120
108
  };
109
+ /** Extract keys of T whose values are arrays */
110
+ type ArrayKeys<T> = {
111
+ [K in keyof T]: T[K] extends unknown[] ? K : never;
112
+ }[keyof T];
121
113
  /**
122
- * Configuration options extracted from DefineHttpOptions (without onRequest callback)
114
+ * Update actions for TableClient.update()
115
+ *
116
+ * @typeParam T - Type of the table items
123
117
  */
124
- type HttpConfig = {
125
- /** Handler name. Defaults to export name if not specified */
126
- name?: string;
127
- /** HTTP method for the route */
128
- method: HttpMethod;
129
- /** Route path (e.g., "/api/users", "/api/users/{id}") */
130
- path: string;
131
- /** Lambda memory in MB (default: 256) */
132
- memory?: number;
133
- /** Lambda timeout in seconds (default: 30) */
134
- timeout?: number;
135
- /** Additional IAM permissions for the Lambda */
136
- permissions?: Permission[];
118
+ type UpdateActions<T> = {
119
+ /** Set attribute values (overwrites existing) */
120
+ set?: Partial<T>;
121
+ /** Append elements to list attributes (creates the list if it doesn't exist) */
122
+ append?: Pick<Partial<T>, ArrayKeys<T>>;
123
+ /** Remove attributes from the item */
124
+ remove?: (keyof T)[];
137
125
  };
138
126
  /**
139
- * Handler function type for HTTP endpoints
127
+ * Typed DynamoDB table client injected via deps.
140
128
  *
141
- * @typeParam C - Type of the context/dependencies (from context function)
129
+ * @typeParam T - Type of the table items
142
130
  */
143
- type HttpHandlerFn<C = undefined> = C extends undefined ? (args: {
144
- req: HttpRequest;
145
- }) => Promise<HttpResponse> : (args: {
146
- req: HttpRequest;
147
- ctx: C;
148
- }) => Promise<HttpResponse>;
131
+ type TableClient<T = Record<string, unknown>> = {
132
+ /** Put a full item into the table */
133
+ put(item: T): Promise<void>;
134
+ /** Get an item by its key attributes */
135
+ get(key: Partial<T>): Promise<T | undefined>;
136
+ /** Delete an item by its key attributes */
137
+ delete(key: Partial<T>): Promise<void>;
138
+ /** Update specific attributes without reading the full item */
139
+ update(key: Partial<T>, actions: UpdateActions<T>): Promise<void>;
140
+ /** Query by partition key with optional sort key condition */
141
+ query(params: QueryParams): Promise<T[]>;
142
+ /** The underlying DynamoDB table name */
143
+ tableName: string;
144
+ };
145
+
146
+ type AnyParamRef = ParamRef<any>;
149
147
  /**
150
- * Options for defining an HTTP endpoint
151
- *
152
- * @typeParam C - Type of the context/dependencies returned by context function
153
- *
154
- * @example Without context
155
- * ```typescript
156
- * export const getUsers = defineHttp({
157
- * method: "GET",
158
- * path: "/api/users",
159
- * onRequest: async ({ req }) => ({
160
- * status: 200,
161
- * body: { users: [] }
162
- * })
163
- * });
164
- * ```
148
+ * Reference to an SSM Parameter Store parameter.
165
149
  *
166
- * @example With context (e.g., Effect runtime)
167
- * ```typescript
168
- * export const createOrder = defineHttp<typeof orderRuntime>({
169
- * method: "POST",
170
- * path: "/api/orders",
171
- * context: () => ManagedRuntime.make(
172
- * Layer.mergeAll(ConfigLive, DbClientLive)
173
- * ),
174
- * onRequest: async ({ req, ctx }) => {
175
- * const result = await ctx.runPromise(createOrderEffect(req.body));
176
- * return { status: 201, body: result };
177
- * }
178
- * });
179
- * ```
150
+ * @typeParam T - The resolved type after optional transform (default: string)
180
151
  */
181
- type DefineHttpOptions<C = undefined> = HttpConfig & {
182
- /**
183
- * Factory function to create context/dependencies for the request handler.
184
- * Called once on cold start, result is cached and reused across invocations.
185
- */
186
- context?: () => C;
187
- /** HTTP request handler function */
188
- onRequest: HttpHandlerFn<C>;
152
+ type ParamRef<T = string> = {
153
+ readonly __brand: "effortless-param";
154
+ readonly key: string;
155
+ readonly transform?: (raw: string) => T;
189
156
  };
190
157
  /**
191
- * Internal handler object created by defineHttp
192
- * @internal
158
+ * Maps a params declaration to resolved value types.
159
+ *
160
+ * @typeParam P - Record of param names to ParamRef instances
193
161
  */
194
- type HttpHandler<C = undefined> = {
195
- readonly __brand: "effortless-http";
196
- readonly config: HttpConfig;
197
- readonly context?: () => C;
198
- readonly onRequest: HttpHandlerFn<C>;
162
+ type ResolveParams<P> = {
163
+ [K in keyof P]: P[K] extends ParamRef<infer T> ? T : never;
199
164
  };
200
165
  /**
201
- * Define an HTTP endpoint that creates an API Gateway route + Lambda function
166
+ * Declare an SSM Parameter Store parameter.
202
167
  *
203
- * @typeParam C - Type of the context/dependencies (inferred from context function)
204
- * @param options - Configuration, optional context factory, and request handler
205
- * @returns Handler object used by the deployment system
168
+ * The key is combined with project and stage at deploy time to form the full
169
+ * SSM path: `/${project}/${stage}/${key}`.
206
170
  *
207
- * @example Basic GET endpoint
208
- * ```typescript
209
- * export const hello = defineHttp({
210
- * method: "GET",
211
- * path: "/hello",
212
- * onRequest: async ({ req }) => ({
213
- * status: 200,
214
- * body: { message: "Hello World!" }
215
- * })
216
- * });
217
- * ```
171
+ * @param key - Parameter key (e.g., "database-url")
172
+ * @param transform - Optional function to transform the raw string value
173
+ * @returns A ParamRef used by the deployment and runtime systems
218
174
  *
219
- * @example POST endpoint with body parsing
175
+ * @example Simple string parameter
220
176
  * ```typescript
221
- * export const createUser = defineHttp({
222
- * method: "POST",
223
- * path: "/users",
224
- * memory: 512,
225
- * timeout: 30,
226
- * onRequest: async ({ req }) => {
227
- * const { name, email } = req.body as { name: string; email: string };
228
- * // ... create user
229
- * return { status: 201, body: { id: "123", name, email } };
230
- * }
231
- * });
177
+ * params: {
178
+ * dbUrl: param("database-url"),
179
+ * }
232
180
  * ```
233
181
  *
234
- * @example With Effect runtime context
182
+ * @example With transform (e.g., TOML parsing)
235
183
  * ```typescript
236
- * export const processPayment = defineHttp<typeof paymentRuntime>({
237
- * method: "POST",
238
- * path: "/payments",
239
- * context: () => ManagedRuntime.make(
240
- * Layer.mergeAll(ConfigLive, StripeClientLive)
241
- * ),
242
- * onRequest: async ({ req, ctx }) => {
243
- * const result = await ctx.runPromise(
244
- * processPaymentEffect(req.body)
245
- * );
246
- * return { status: 200, body: result };
247
- * }
248
- * });
184
+ * import TOML from "smol-toml";
185
+ *
186
+ * params: {
187
+ * config: param("app-config", TOML.parse),
188
+ * }
249
189
  * ```
250
190
  */
251
- declare const defineHttp: <C = undefined>(options: DefineHttpOptions<C>) => HttpHandler<C>;
191
+ declare const param: <T = string>(key: string, transform?: (raw: string) => T) => ParamRef<T>;
252
192
 
193
+ type AnyTableHandler$1 = TableHandler<any, any, any, any, any>;
194
+ /** Maps a deps declaration to resolved runtime client types */
195
+ type ResolveDeps$1<D> = {
196
+ [K in keyof D]: D[K] extends TableHandler<infer T, any, any, any, any> ? TableClient<T> : never;
197
+ };
253
198
  /** DynamoDB attribute types for keys */
254
199
  type KeyType = "string" | "number" | "binary";
255
200
  /**
@@ -322,99 +267,127 @@ type FailedRecord<T = Record<string, unknown>> = {
322
267
  /** The error that occurred */
323
268
  error: unknown;
324
269
  };
270
+ /**
271
+ * Context factory type — conditional on whether params are declared.
272
+ * Without params: `() => C | Promise<C>`
273
+ * With params: `(args: { params: ResolveParams<P> }) => C | Promise<C>`
274
+ */
275
+ type ContextFactory$1<C, P> = [P] extends [undefined] ? () => C | Promise<C> : (args: {
276
+ params: ResolveParams<P & {}>;
277
+ }) => C | Promise<C>;
325
278
  /**
326
279
  * Callback function type for processing a single DynamoDB stream record
327
- *
328
- * @typeParam T - Type of the table items
329
- * @typeParam C - Type of the context/dependencies (from context function)
330
- * @typeParam R - Return type (can be void or a value to accumulate)
331
280
  */
332
- type TableRecordFn<T = Record<string, unknown>, C = undefined, R = void> = C extends undefined ? (args: {
333
- record: TableRecord<T>;
334
- }) => Promise<R> : (args: {
281
+ type TableRecordFn<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined> = (args: {
335
282
  record: TableRecord<T>;
283
+ table: TableClient<T>;
284
+ } & ([C] extends [undefined] ? {} : {
336
285
  ctx: C;
337
- }) => Promise<R>;
286
+ }) & ([D] extends [undefined] ? {} : {
287
+ deps: ResolveDeps$1<D>;
288
+ }) & ([P] extends [undefined] ? {} : {
289
+ params: ResolveParams<P>;
290
+ })) => Promise<R>;
338
291
  /**
339
292
  * Callback function type for processing accumulated batch results
340
- *
341
- * @typeParam T - Type of the table items
342
- * @typeParam C - Type of the context/dependencies
343
- * @typeParam R - Type of results accumulated from onRecord
344
293
  */
345
- type TableBatchCompleteFn<T = Record<string, unknown>, C = undefined, R = void> = C extends undefined ? (args: {
346
- results: R[];
347
- failures: FailedRecord<T>[];
348
- }) => Promise<void> : (args: {
294
+ type TableBatchCompleteFn<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined> = (args: {
349
295
  results: R[];
350
296
  failures: FailedRecord<T>[];
297
+ table: TableClient<T>;
298
+ } & ([C] extends [undefined] ? {} : {
351
299
  ctx: C;
352
- }) => Promise<void>;
300
+ }) & ([D] extends [undefined] ? {} : {
301
+ deps: ResolveDeps$1<D>;
302
+ }) & ([P] extends [undefined] ? {} : {
303
+ params: ResolveParams<P>;
304
+ })) => Promise<void>;
353
305
  /**
354
- * Options for defining a DynamoDB table with optional stream handler
355
- *
356
- * @typeParam T - Type of the table items for type-safe record access
357
- * @typeParam C - Type of the context/dependencies returned by context function
358
- *
359
- * @example Without context
360
- * ```typescript
361
- * export const users = defineTable<User>({
362
- * pk: { name: "id", type: "string" },
363
- * onRecord: async ({ record }) => {
364
- * console.log(record.new?.name);
365
- * }
366
- * });
367
- * ```
368
- *
369
- * @example With context (e.g., Effect runtime)
370
- * ```typescript
371
- * export const orders = defineTable<Order, ManagedRuntime<...>>({
372
- * pk: { name: "id", type: "string" },
373
- * context: () => ManagedRuntime.make(
374
- * Layer.mergeAll(ConfigLive, DbClientLive)
375
- * ),
376
- * onRecord: async ({ record, ctx }) => {
377
- * await ctx.runPromise(processOrder(record));
378
- * }
379
- * });
380
- * ```
306
+ * Callback function type for processing all records in a batch at once
381
307
  */
382
- type DefineTableOptions<T = Record<string, unknown>, C = undefined, R = void> = TableConfig & {
308
+ type TableBatchFn<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined> = (args: {
309
+ records: TableRecord<T>[];
310
+ table: TableClient<T>;
311
+ } & ([C] extends [undefined] ? {} : {
312
+ ctx: C;
313
+ }) & ([D] extends [undefined] ? {} : {
314
+ deps: ResolveDeps$1<D>;
315
+ }) & ([P] extends [undefined] ? {} : {
316
+ params: ResolveParams<P>;
317
+ })) => Promise<void>;
318
+ /** Base options shared by all defineTable variants */
319
+ type DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined> = TableConfig & {
320
+ /**
321
+ * Decode/validate function for stream record items (new/old images).
322
+ * Called with the unmarshalled DynamoDB item; should return typed data or throw on validation failure.
323
+ * When provided, T is inferred from the return type — no need to specify generic parameters.
324
+ */
325
+ schema?: (input: unknown) => T;
383
326
  /**
384
- * Factory function to create context/dependencies for onRecord callback.
327
+ * Error handler called when onRecord, onBatch, or onBatchComplete throws.
328
+ * Receives the error. If not provided, defaults to `console.error`.
329
+ */
330
+ onError?: (error: unknown) => void;
331
+ /**
332
+ * Factory function to create context/dependencies for callbacks.
385
333
  * Called once on cold start, result is cached and reused across invocations.
334
+ * When params are declared, receives resolved params as argument.
335
+ * Supports both sync and async return values.
336
+ */
337
+ context?: ContextFactory$1<C, P>;
338
+ /**
339
+ * Dependencies on other handlers (tables, queues, etc.).
340
+ * Typed clients are injected into the handler via the `deps` argument.
386
341
  */
387
- context?: () => C;
388
- /** Stream record callback. If omitted, only the table is created (no Lambda) */
389
- onRecord?: TableRecordFn<T, C, R>;
342
+ deps?: D;
390
343
  /**
391
- * Callback invoked after all records in the batch are processed.
392
- * Receives accumulated results from onRecord and list of failures.
344
+ * SSM Parameter Store parameters.
345
+ * Declare with `param()` helper. Values are fetched and cached at cold start.
346
+ * Typed values are injected into the handler via the `params` argument.
393
347
  */
394
- onBatchComplete?: TableBatchCompleteFn<T, C, R>;
348
+ params?: P;
395
349
  };
350
+ /** Per-record processing: onRecord with optional onBatchComplete */
351
+ type DefineTableWithOnRecord<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined> = DefineTableBase<T, C, D, P> & {
352
+ onRecord: TableRecordFn<T, C, R, D, P>;
353
+ onBatchComplete?: TableBatchCompleteFn<T, C, R, D, P>;
354
+ onBatch?: never;
355
+ };
356
+ /** Batch processing: onBatch processes all records at once */
357
+ type DefineTableWithOnBatch<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined> = DefineTableBase<T, C, D, P> & {
358
+ onBatch: TableBatchFn<T, C, D, P>;
359
+ onRecord?: never;
360
+ onBatchComplete?: never;
361
+ };
362
+ /** Resource-only: no handler, just creates the table */
363
+ type DefineTableResourceOnly<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined> = DefineTableBase<T, C, D, P> & {
364
+ onRecord?: never;
365
+ onBatch?: never;
366
+ onBatchComplete?: never;
367
+ };
368
+ type DefineTableOptions<T = Record<string, unknown>, C = undefined, R = void, D extends Record<string, AnyTableHandler$1> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined> = DefineTableWithOnRecord<T, C, R, D, P> | DefineTableWithOnBatch<T, C, D, P> | DefineTableResourceOnly<T, C, D, P>;
396
369
  /**
397
370
  * Internal handler object created by defineTable
398
371
  * @internal
399
372
  */
400
- type TableHandler<T = Record<string, unknown>, C = undefined, R = void> = {
373
+ type TableHandler<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined> = {
401
374
  readonly __brand: "effortless-table";
402
375
  readonly config: TableConfig;
403
- readonly context?: () => C;
404
- readonly onRecord?: TableRecordFn<T, C, R>;
405
- readonly onBatchComplete?: TableBatchCompleteFn<T, C, R>;
376
+ readonly schema?: (input: unknown) => T;
377
+ readonly onError?: (error: unknown) => void;
378
+ readonly context?: (...args: any[]) => C | Promise<C>;
379
+ readonly deps?: D;
380
+ readonly params?: P;
381
+ readonly onRecord?: TableRecordFn<T, C, R, D, P>;
382
+ readonly onBatchComplete?: TableBatchCompleteFn<T, C, R, D, P>;
383
+ readonly onBatch?: TableBatchFn<T, C, D, P>;
406
384
  };
407
385
  /**
408
386
  * Define a DynamoDB table with optional stream handler
409
387
  *
410
388
  * Creates:
411
389
  * - DynamoDB table with specified key schema
412
- * - (If onRecord provided) DynamoDB Stream + Lambda + Event Source Mapping
413
- *
414
- * @typeParam T - Type of the table items for type-safe record access
415
- * @typeParam C - Type of the context/dependencies (inferred from context function)
416
- * @param options - Table configuration, optional context factory, and optional onRecord callback
417
- * @returns Handler object used by the deployment system
390
+ * - (If onRecord or onBatch provided) DynamoDB Stream + Lambda + Event Source Mapping
418
391
  *
419
392
  * @example Table with stream handler (typed)
420
393
  * ```typescript
@@ -432,19 +405,6 @@ type TableHandler<T = Record<string, unknown>, C = undefined, R = void> = {
432
405
  * });
433
406
  * ```
434
407
  *
435
- * @example With Effect runtime context
436
- * ```typescript
437
- * export const expenses = defineTable<Expense, typeof expenseRuntime>({
438
- * pk: { name: "pk", type: "string" },
439
- * context: () => ManagedRuntime.make(
440
- * Layer.mergeAll(ConfigLive, DynamoDBClient.Default())
441
- * ),
442
- * onRecord: async ({ record, ctx }) => {
443
- * await ctx.runPromise(processExpense(record));
444
- * }
445
- * });
446
- * ```
447
- *
448
408
  * @example Table only (no Lambda)
449
409
  * ```typescript
450
410
  * export const users = defineTable({
@@ -453,6 +413,191 @@ type TableHandler<T = Record<string, unknown>, C = undefined, R = void> = {
453
413
  * });
454
414
  * ```
455
415
  */
456
- declare const defineTable: <T = Record<string, unknown>, C = undefined, R = void>(options: DefineTableOptions<T, C, R>) => TableHandler<T, C, R>;
416
+ declare const defineTable: <T = Record<string, unknown>, C = undefined, R = void, D extends Record<string, AnyTableHandler$1> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined>(options: DefineTableOptions<T, C, R, D, P>) => TableHandler<T, C, R, D, P>;
417
+
418
+ type AnyTableHandler = TableHandler<any, any, any, any, any>;
419
+ /** Maps a deps declaration to resolved runtime client types */
420
+ type ResolveDeps<D> = {
421
+ [K in keyof D]: D[K] extends TableHandler<infer T, any, any, any, any> ? TableClient<T> : never;
422
+ };
423
+ /** HTTP methods supported by API Gateway */
424
+ type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
425
+ /**
426
+ * Incoming HTTP request object passed to the handler
427
+ */
428
+ type HttpRequest = {
429
+ /** HTTP method (GET, POST, etc.) */
430
+ method: string;
431
+ /** Request path (e.g., "/users/123") */
432
+ path: string;
433
+ /** Request headers */
434
+ headers: Record<string, string | undefined>;
435
+ /** Query string parameters */
436
+ query: Record<string, string | undefined>;
437
+ /** Path parameters extracted from route (e.g., {id} -> params.id) */
438
+ params: Record<string, string | undefined>;
439
+ /** Parsed request body (JSON parsed if Content-Type is application/json) */
440
+ body: unknown;
441
+ /** Raw unparsed request body */
442
+ rawBody?: string;
443
+ };
444
+ /**
445
+ * HTTP response returned from the handler
446
+ */
447
+ type HttpResponse = {
448
+ /** HTTP status code (e.g., 200, 404, 500) */
449
+ status: number;
450
+ /** Response body (will be JSON serialized) */
451
+ body?: unknown;
452
+ /** Response headers */
453
+ headers?: Record<string, string>;
454
+ };
455
+ /**
456
+ * Configuration options extracted from DefineHttpOptions (without onRequest callback)
457
+ */
458
+ type HttpConfig = {
459
+ /** Handler name. Defaults to export name if not specified */
460
+ name?: string;
461
+ /** HTTP method for the route */
462
+ method: HttpMethod;
463
+ /** Route path (e.g., "/api/users", "/api/users/{id}") */
464
+ path: string;
465
+ /** Lambda memory in MB (default: 256) */
466
+ memory?: number;
467
+ /** Lambda timeout in seconds (default: 30) */
468
+ timeout?: number;
469
+ /** Additional IAM permissions for the Lambda */
470
+ permissions?: Permission[];
471
+ };
472
+ /**
473
+ * Handler function type for HTTP endpoints
474
+ *
475
+ * @typeParam T - Type of the validated request body (from schema function)
476
+ * @typeParam C - Type of the context/dependencies (from context function)
477
+ * @typeParam D - Type of the deps (from deps declaration)
478
+ * @typeParam P - Type of the params (from params declaration)
479
+ */
480
+ type HttpHandlerFn<T = undefined, C = undefined, D = undefined, P = undefined> = (args: {
481
+ req: HttpRequest;
482
+ } & ([T] extends [undefined] ? {} : {
483
+ data: T;
484
+ }) & ([C] extends [undefined] ? {} : {
485
+ ctx: C;
486
+ }) & ([D] extends [undefined] ? {} : {
487
+ deps: ResolveDeps<D>;
488
+ }) & ([P] extends [undefined] ? {} : {
489
+ params: ResolveParams<P>;
490
+ })) => Promise<HttpResponse>;
491
+ /**
492
+ * Context factory type — conditional on whether params are declared.
493
+ * Without params: `() => C | Promise<C>`
494
+ * With params: `(args: { params: ResolveParams<P> }) => C | Promise<C>`
495
+ */
496
+ type ContextFactory<C, P> = [P] extends [undefined] ? () => C | Promise<C> : (args: {
497
+ params: ResolveParams<P & {}>;
498
+ }) => C | Promise<C>;
499
+ /**
500
+ * Options for defining an HTTP endpoint
501
+ *
502
+ * @typeParam T - Type of the validated request body (inferred from schema function)
503
+ * @typeParam C - Type of the context/dependencies returned by context function
504
+ * @typeParam D - Type of the deps (from deps declaration)
505
+ * @typeParam P - Type of the params (from params declaration)
506
+ */
507
+ type DefineHttpOptions<T = undefined, C = undefined, D extends Record<string, AnyTableHandler> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined> = HttpConfig & {
508
+ /**
509
+ * Decode/validate function for the request body.
510
+ * Called with the parsed body; should return typed data or throw on validation failure.
511
+ * When provided, the handler receives validated `data` and invalid requests get a 400 response.
512
+ *
513
+ * Works with any validation library:
514
+ * - Effect: `S.decodeUnknownSync(MySchema)`
515
+ * - Zod: `(body) => myZodSchema.parse(body)`
516
+ */
517
+ schema?: (input: unknown) => T;
518
+ /**
519
+ * Error handler called when schema validation or onRequest throws.
520
+ * Receives the error and request, returns an HttpResponse.
521
+ * If not provided, defaults to 400 for validation errors and 500 for handler errors.
522
+ */
523
+ onError?: (error: unknown, req: HttpRequest) => HttpResponse;
524
+ /**
525
+ * Factory function to create context/dependencies for the request handler.
526
+ * Called once on cold start, result is cached and reused across invocations.
527
+ * When params are declared, receives resolved params as argument.
528
+ * Supports both sync and async return values.
529
+ */
530
+ context?: ContextFactory<C, P>;
531
+ /**
532
+ * Dependencies on other handlers (tables, queues, etc.).
533
+ * Typed clients are injected into the handler via the `deps` argument.
534
+ */
535
+ deps?: D;
536
+ /**
537
+ * SSM Parameter Store parameters.
538
+ * Declare with `param()` helper. Values are fetched and cached at cold start.
539
+ * Typed values are injected into the handler via the `params` argument.
540
+ */
541
+ params?: P;
542
+ /** HTTP request handler function */
543
+ onRequest: HttpHandlerFn<T, C, D, P>;
544
+ };
545
+ /**
546
+ * Internal handler object created by defineHttp
547
+ * @internal
548
+ */
549
+ type HttpHandler<T = undefined, C = undefined, D = undefined, P = undefined> = {
550
+ readonly __brand: "effortless-http";
551
+ readonly config: HttpConfig;
552
+ readonly schema?: (input: unknown) => T;
553
+ readonly onError?: (error: unknown, req: HttpRequest) => HttpResponse;
554
+ readonly context?: (...args: any[]) => C | Promise<C>;
555
+ readonly deps?: D;
556
+ readonly params?: P;
557
+ readonly onRequest: HttpHandlerFn<T, C, D, P>;
558
+ };
559
+ /**
560
+ * Define an HTTP endpoint that creates an API Gateway route + Lambda function
561
+ *
562
+ * @typeParam T - Type of the validated request body (inferred from schema function)
563
+ * @typeParam C - Type of the context/dependencies (inferred from context function)
564
+ * @typeParam D - Type of the deps (from deps declaration)
565
+ * @typeParam P - Type of the params (from params declaration)
566
+ * @param options - Configuration, optional schema, optional context factory, and request handler
567
+ * @returns Handler object used by the deployment system
568
+ *
569
+ * @example Basic GET endpoint
570
+ * ```typescript
571
+ * export const hello = defineHttp({
572
+ * method: "GET",
573
+ * path: "/hello",
574
+ * onRequest: async ({ req }) => ({
575
+ * status: 200,
576
+ * body: { message: "Hello World!" }
577
+ * })
578
+ * });
579
+ * ```
580
+ *
581
+ * @example With SSM parameters
582
+ * ```typescript
583
+ * import { param } from "effortless-aws";
584
+ *
585
+ * export const api = defineHttp({
586
+ * method: "GET",
587
+ * path: "/orders",
588
+ * params: {
589
+ * dbUrl: param("database-url"),
590
+ * },
591
+ * context: async ({ params }) => ({
592
+ * pool: createPool(params.dbUrl),
593
+ * }),
594
+ * onRequest: async ({ req, ctx, params }) => ({
595
+ * status: 200,
596
+ * body: { dbUrl: params.dbUrl }
597
+ * })
598
+ * });
599
+ * ```
600
+ */
601
+ declare const defineHttp: <T = undefined, C = undefined, D extends Record<string, AnyTableHandler> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined>(options: DefineHttpOptions<T, C, D, P>) => HttpHandler<T, C, D, P>;
457
602
 
458
- export { type DefineHttpOptions, type DefineTableOptions, type EffortlessConfig, type FailedRecord, type HttpConfig, type HttpHandler, type HttpHandlerFn, type HttpMethod, type HttpRequest, type HttpResponse, type KeyType, type StreamView, type TableBatchCompleteFn, type TableConfig, type TableHandler, type TableKey, type TableRecord, type TableRecordFn, defineConfig, defineHttp, defineTable };
603
+ export { type DefineHttpOptions, type DefineTableOptions, type EffortlessConfig, type FailedRecord, type HttpConfig, type HttpHandler, type HttpHandlerFn, type HttpMethod, type HttpRequest, type HttpResponse, type KeyType, type ParamRef, type QueryParams, type ResolveDeps, type ResolveParams, type StreamView, type TableBatchCompleteFn, type TableBatchFn, type TableClient, type TableConfig, type TableHandler, type TableKey, type TableRecord, type TableRecordFn, defineConfig, defineHttp, defineTable, param };