effortless-aws 0.12.0 → 0.13.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/{chunk-C3OVOGFE.js → chunk-SSEPES5N.js} +8 -2
- package/dist/index.d.ts +38 -21
- package/dist/index.js.map +1 -1
- package/dist/runtime/wrap-app.js +1 -1
- package/dist/runtime/wrap-bucket.js +1 -1
- package/dist/runtime/wrap-fifo-queue.js +1 -1
- package/dist/runtime/wrap-http.js +1 -1
- package/dist/runtime/wrap-table-stream.js +1 -1
- package/package.json +1 -1
|
@@ -330,7 +330,12 @@ var buildParams = async (params) => {
|
|
|
330
330
|
}
|
|
331
331
|
return result;
|
|
332
332
|
};
|
|
333
|
-
var
|
|
333
|
+
var resolvePath = (filePath) => join(process.cwd(), filePath);
|
|
334
|
+
var staticFiles = {
|
|
335
|
+
read: (filePath) => readFileSync(resolvePath(filePath), "utf-8"),
|
|
336
|
+
readBuffer: (filePath) => readFileSync(resolvePath(filePath)),
|
|
337
|
+
path: resolvePath
|
|
338
|
+
};
|
|
334
339
|
var createHandlerRuntime = (handler, handlerType, logLevel = "info", extraSetupArgs) => {
|
|
335
340
|
const handlerName = process.env.EFF_HANDLER ?? "unknown";
|
|
336
341
|
const rank = LOG_RANK[logLevel];
|
|
@@ -351,6 +356,7 @@ var createHandlerRuntime = (handler, handlerType, logLevel = "info", extraSetupA
|
|
|
351
356
|
const args = {};
|
|
352
357
|
if (params) args.config = params;
|
|
353
358
|
if (deps) args.deps = deps;
|
|
359
|
+
if (handler.static) args.files = staticFiles;
|
|
354
360
|
if (extraSetupArgs) Object.assign(args, extraSetupArgs());
|
|
355
361
|
ctx = await handler.setup(args);
|
|
356
362
|
}
|
|
@@ -363,7 +369,7 @@ var createHandlerRuntime = (handler, handlerType, logLevel = "info", extraSetupA
|
|
|
363
369
|
if (deps) args.deps = deps;
|
|
364
370
|
const params = await getParams();
|
|
365
371
|
if (params) args.config = params;
|
|
366
|
-
if (handler.static) args.
|
|
372
|
+
if (handler.static) args.files = staticFiles;
|
|
367
373
|
return args;
|
|
368
374
|
};
|
|
369
375
|
const logExecution = (startTime, input, output) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -402,12 +402,14 @@ type FailedRecord<T = Record<string, unknown>> = {
|
|
|
402
402
|
* Always receives `table: TableClient<T>` (self-client for the handler's own table).
|
|
403
403
|
* Also receives `deps` and/or `config` when declared.
|
|
404
404
|
*/
|
|
405
|
-
type SetupFactory$3<C, T, D, P> = (args: {
|
|
405
|
+
type SetupFactory$3<C, T, D, P, S extends string[] | undefined = undefined> = (args: {
|
|
406
406
|
table: TableClient<T>;
|
|
407
407
|
} & ([D] extends [undefined] ? {} : {
|
|
408
408
|
deps: ResolveDeps<D>;
|
|
409
409
|
}) & ([P] extends [undefined] ? {} : {
|
|
410
410
|
config: ResolveConfig<P & {}>;
|
|
411
|
+
}) & ([S] extends [undefined] ? {} : {
|
|
412
|
+
files: StaticFiles;
|
|
411
413
|
})) => C | Promise<C>;
|
|
412
414
|
/**
|
|
413
415
|
* Callback function type for processing a single DynamoDB stream record
|
|
@@ -422,7 +424,7 @@ type TableRecordFn<T = Record<string, unknown>, C = undefined, R = void, D = und
|
|
|
422
424
|
}) & ([P] extends [undefined] ? {} : {
|
|
423
425
|
config: ResolveConfig<P>;
|
|
424
426
|
}) & ([S] extends [undefined] ? {} : {
|
|
425
|
-
|
|
427
|
+
files: StaticFiles;
|
|
426
428
|
})) => Promise<R>;
|
|
427
429
|
/**
|
|
428
430
|
* Callback function type for processing accumulated batch results
|
|
@@ -438,7 +440,7 @@ type TableBatchCompleteFn<T = Record<string, unknown>, C = undefined, R = void,
|
|
|
438
440
|
}) & ([P] extends [undefined] ? {} : {
|
|
439
441
|
config: ResolveConfig<P>;
|
|
440
442
|
}) & ([S] extends [undefined] ? {} : {
|
|
441
|
-
|
|
443
|
+
files: StaticFiles;
|
|
442
444
|
})) => Promise<void>;
|
|
443
445
|
/**
|
|
444
446
|
* Callback function type for processing all records in a batch at once
|
|
@@ -453,7 +455,7 @@ type TableBatchFn<T = Record<string, unknown>, C = undefined, D = undefined, P =
|
|
|
453
455
|
}) & ([P] extends [undefined] ? {} : {
|
|
454
456
|
config: ResolveConfig<P>;
|
|
455
457
|
}) & ([S] extends [undefined] ? {} : {
|
|
456
|
-
|
|
458
|
+
files: StaticFiles;
|
|
457
459
|
})) => Promise<void>;
|
|
458
460
|
/** Base options shared by all defineTable variants */
|
|
459
461
|
type DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = Omit<TableConfig, "tagField"> & {
|
|
@@ -476,7 +478,7 @@ type DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined,
|
|
|
476
478
|
* When deps/params are declared, receives them as argument.
|
|
477
479
|
* Supports both sync and async return values.
|
|
478
480
|
*/
|
|
479
|
-
setup?: SetupFactory$3<C, T, D, P>;
|
|
481
|
+
setup?: SetupFactory$3<C, T, D, P, S>;
|
|
480
482
|
/**
|
|
481
483
|
* Dependencies on other handlers (tables, queues, etc.).
|
|
482
484
|
* Typed clients are injected into the handler via the `deps` argument.
|
|
@@ -490,7 +492,7 @@ type DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined,
|
|
|
490
492
|
config?: P;
|
|
491
493
|
/**
|
|
492
494
|
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
493
|
-
* Files are accessible at runtime via the `
|
|
495
|
+
* Files are accessible at runtime via the `files` callback argument.
|
|
494
496
|
*/
|
|
495
497
|
static?: S;
|
|
496
498
|
};
|
|
@@ -624,7 +626,7 @@ type BucketObjectCreatedFn<C = undefined, D = undefined, P = undefined, S extend
|
|
|
624
626
|
}) & ([P] extends [undefined] ? {} : {
|
|
625
627
|
config: ResolveConfig<P>;
|
|
626
628
|
}) & ([S] extends [undefined] ? {} : {
|
|
627
|
-
|
|
629
|
+
files: StaticFiles;
|
|
628
630
|
})) => Promise<void>;
|
|
629
631
|
/**
|
|
630
632
|
* Callback function type for S3 ObjectRemoved events
|
|
@@ -639,19 +641,21 @@ type BucketObjectRemovedFn<C = undefined, D = undefined, P = undefined, S extend
|
|
|
639
641
|
}) & ([P] extends [undefined] ? {} : {
|
|
640
642
|
config: ResolveConfig<P>;
|
|
641
643
|
}) & ([S] extends [undefined] ? {} : {
|
|
642
|
-
|
|
644
|
+
files: StaticFiles;
|
|
643
645
|
})) => Promise<void>;
|
|
644
646
|
/**
|
|
645
647
|
* Setup factory type for bucket handlers.
|
|
646
648
|
* Always receives `bucket: BucketClient` (self-client for the handler's own bucket).
|
|
647
649
|
* Also receives `deps` and/or `config` when declared.
|
|
648
650
|
*/
|
|
649
|
-
type SetupFactory$2<C, D, P> = (args: {
|
|
651
|
+
type SetupFactory$2<C, D, P, S extends string[] | undefined = undefined> = (args: {
|
|
650
652
|
bucket: BucketClient;
|
|
651
653
|
} & ([D] extends [undefined] ? {} : {
|
|
652
654
|
deps: ResolveDeps<D>;
|
|
653
655
|
}) & ([P] extends [undefined] ? {} : {
|
|
654
656
|
config: ResolveConfig<P & {}>;
|
|
657
|
+
}) & ([S] extends [undefined] ? {} : {
|
|
658
|
+
files: StaticFiles;
|
|
655
659
|
})) => C | Promise<C>;
|
|
656
660
|
/** Base options shared by all defineBucket variants */
|
|
657
661
|
type DefineBucketBase<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = BucketConfig & {
|
|
@@ -666,7 +670,7 @@ type DefineBucketBase<C = undefined, D = undefined, P = undefined, S extends str
|
|
|
666
670
|
* Always receives `bucket: BucketClient` (self-client). When deps/config
|
|
667
671
|
* are declared, receives them as well.
|
|
668
672
|
*/
|
|
669
|
-
setup?: SetupFactory$2<C, D, P>;
|
|
673
|
+
setup?: SetupFactory$2<C, D, P, S>;
|
|
670
674
|
/**
|
|
671
675
|
* Dependencies on other handlers (tables, buckets, etc.).
|
|
672
676
|
* Typed clients are injected into the handler via the `deps` argument.
|
|
@@ -679,7 +683,7 @@ type DefineBucketBase<C = undefined, D = undefined, P = undefined, S extends str
|
|
|
679
683
|
config?: P;
|
|
680
684
|
/**
|
|
681
685
|
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
682
|
-
* Files are accessible at runtime via the `
|
|
686
|
+
* Files are accessible at runtime via the `files` callback argument.
|
|
683
687
|
*/
|
|
684
688
|
static?: S;
|
|
685
689
|
};
|
|
@@ -754,6 +758,15 @@ type AnyDepHandler = AnyTableHandler | AnyBucketHandler;
|
|
|
754
758
|
type ResolveDeps<D> = {
|
|
755
759
|
[K in keyof D]: D[K] extends TableHandler<infer T, any, any, any, any> ? TableClient<T> : D[K] extends BucketHandler<any, any, any, any> ? BucketClient : never;
|
|
756
760
|
};
|
|
761
|
+
/** Service for reading static files bundled into the Lambda ZIP */
|
|
762
|
+
type StaticFiles = {
|
|
763
|
+
/** Read file as UTF-8 string */
|
|
764
|
+
read(path: string): string;
|
|
765
|
+
/** Read file as Buffer (for binary content) */
|
|
766
|
+
readBuffer(path: string): Buffer;
|
|
767
|
+
/** Resolve absolute path to the bundled file */
|
|
768
|
+
path(path: string): string;
|
|
769
|
+
};
|
|
757
770
|
|
|
758
771
|
/** HTTP methods supported by API Gateway */
|
|
759
772
|
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
@@ -829,16 +842,18 @@ type HttpHandlerFn<T = undefined, C = undefined, D = undefined, P = undefined, S
|
|
|
829
842
|
}) & ([P] extends [undefined] ? {} : {
|
|
830
843
|
config: ResolveConfig<P>;
|
|
831
844
|
}) & ([S] extends [undefined] ? {} : {
|
|
832
|
-
|
|
845
|
+
files: StaticFiles;
|
|
833
846
|
})) => Promise<HttpResponse>;
|
|
834
847
|
/**
|
|
835
848
|
* Setup factory type — always receives an args object.
|
|
836
849
|
* Args include `deps` and/or `config` when declared (empty `{}` otherwise).
|
|
837
850
|
*/
|
|
838
|
-
type SetupFactory$1<C, D, P> = (args: ([D] extends [undefined] ? {} : {
|
|
851
|
+
type SetupFactory$1<C, D, P, S extends string[] | undefined = undefined> = (args: ([D] extends [undefined] ? {} : {
|
|
839
852
|
deps: ResolveDeps<D>;
|
|
840
853
|
}) & ([P] extends [undefined] ? {} : {
|
|
841
854
|
config: ResolveConfig<P & {}>;
|
|
855
|
+
}) & ([S] extends [undefined] ? {} : {
|
|
856
|
+
files: StaticFiles;
|
|
842
857
|
})) => C | Promise<C>;
|
|
843
858
|
/**
|
|
844
859
|
* Options for defining an HTTP endpoint
|
|
@@ -871,7 +886,7 @@ type DefineHttpOptions<T = undefined, C = undefined, D extends Record<string, An
|
|
|
871
886
|
* When deps/params are declared, receives them as argument.
|
|
872
887
|
* Supports both sync and async return values.
|
|
873
888
|
*/
|
|
874
|
-
setup?: SetupFactory$1<C, D, P>;
|
|
889
|
+
setup?: SetupFactory$1<C, D, P, S>;
|
|
875
890
|
/**
|
|
876
891
|
* Dependencies on other handlers (tables, queues, etc.).
|
|
877
892
|
* Typed clients are injected into the handler via the `deps` argument.
|
|
@@ -885,7 +900,7 @@ type DefineHttpOptions<T = undefined, C = undefined, D extends Record<string, An
|
|
|
885
900
|
config?: P;
|
|
886
901
|
/**
|
|
887
902
|
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
888
|
-
* Files are accessible at runtime via the `
|
|
903
|
+
* Files are accessible at runtime via the `files` callback argument.
|
|
889
904
|
*/
|
|
890
905
|
static?: S;
|
|
891
906
|
/** HTTP request handler function */
|
|
@@ -1127,10 +1142,12 @@ type FifoQueueConfig = LambdaWithPermissions & {
|
|
|
1127
1142
|
* Setup factory type — always receives an args object.
|
|
1128
1143
|
* Args include `deps` and/or `config` when declared (empty `{}` otherwise).
|
|
1129
1144
|
*/
|
|
1130
|
-
type SetupFactory<C, D, P> = (args: ([D] extends [undefined] ? {} : {
|
|
1145
|
+
type SetupFactory<C, D, P, S extends string[] | undefined = undefined> = (args: ([D] extends [undefined] ? {} : {
|
|
1131
1146
|
deps: ResolveDeps<D>;
|
|
1132
1147
|
}) & ([P] extends [undefined] ? {} : {
|
|
1133
1148
|
config: ResolveConfig<P & {}>;
|
|
1149
|
+
}) & ([S] extends [undefined] ? {} : {
|
|
1150
|
+
files: StaticFiles;
|
|
1134
1151
|
})) => C | Promise<C>;
|
|
1135
1152
|
/**
|
|
1136
1153
|
* Per-message handler function.
|
|
@@ -1145,7 +1162,7 @@ type FifoQueueMessageFn<T = unknown, C = undefined, D = undefined, P = undefined
|
|
|
1145
1162
|
}) & ([P] extends [undefined] ? {} : {
|
|
1146
1163
|
config: ResolveConfig<P>;
|
|
1147
1164
|
}) & ([S] extends [undefined] ? {} : {
|
|
1148
|
-
|
|
1165
|
+
files: StaticFiles;
|
|
1149
1166
|
})) => Promise<void>;
|
|
1150
1167
|
/**
|
|
1151
1168
|
* Batch handler function.
|
|
@@ -1160,7 +1177,7 @@ type FifoQueueBatchFn<T = unknown, C = undefined, D = undefined, P = undefined,
|
|
|
1160
1177
|
}) & ([P] extends [undefined] ? {} : {
|
|
1161
1178
|
config: ResolveConfig<P>;
|
|
1162
1179
|
}) & ([S] extends [undefined] ? {} : {
|
|
1163
|
-
|
|
1180
|
+
files: StaticFiles;
|
|
1164
1181
|
})) => Promise<void>;
|
|
1165
1182
|
/** Base options shared by all defineFifoQueue variants */
|
|
1166
1183
|
type DefineFifoQueueBase<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = FifoQueueConfig & {
|
|
@@ -1179,7 +1196,7 @@ type DefineFifoQueueBase<T = unknown, C = undefined, D = undefined, P = undefine
|
|
|
1179
1196
|
* Called once on cold start, result is cached and reused across invocations.
|
|
1180
1197
|
* When deps/params are declared, receives them as argument.
|
|
1181
1198
|
*/
|
|
1182
|
-
setup?: SetupFactory<C, D, P>;
|
|
1199
|
+
setup?: SetupFactory<C, D, P, S>;
|
|
1183
1200
|
/**
|
|
1184
1201
|
* Dependencies on other handlers (tables, queues, etc.).
|
|
1185
1202
|
* Typed clients are injected into the handler via the `deps` argument.
|
|
@@ -1192,7 +1209,7 @@ type DefineFifoQueueBase<T = unknown, C = undefined, D = undefined, P = undefine
|
|
|
1192
1209
|
config?: P;
|
|
1193
1210
|
/**
|
|
1194
1211
|
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
1195
|
-
* Files are accessible at runtime via the `
|
|
1212
|
+
* Files are accessible at runtime via the `files` callback argument.
|
|
1196
1213
|
*/
|
|
1197
1214
|
static?: S;
|
|
1198
1215
|
};
|
|
@@ -1255,4 +1272,4 @@ type FifoQueueHandler<T = unknown, C = undefined, D = undefined, P = undefined,
|
|
|
1255
1272
|
*/
|
|
1256
1273
|
declare const defineFifoQueue: <T = unknown, C = undefined, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined, S extends string[] | undefined = undefined>(options: DefineFifoQueueOptions<T, C, D, P, S>) => FifoQueueHandler<T, C, D, P, S>;
|
|
1257
1274
|
|
|
1258
|
-
export { type AppConfig, type AppHandler, type BucketClient, type BucketConfig, type BucketEvent, type BucketHandler, type BucketObjectCreatedFn, type BucketObjectRemovedFn, type ContentType, type DefineBucketOptions, type DefineFifoQueueOptions, type DefineHttpOptions, type DefineTableOptions, type EffortlessConfig, type FailedRecord, type FifoQueueBatchFn, type FifoQueueConfig, type FifoQueueHandler, type FifoQueueMessage, type FifoQueueMessageFn, type HttpConfig, type HttpHandler, type HttpHandlerFn, type HttpMethod, type HttpRequest, type HttpResponse, type LambdaConfig, type LambdaWithPermissions, type LogLevel, type MiddlewareDeny, type MiddlewareHandler, type MiddlewareRedirect, type MiddlewareRequest, type MiddlewareResult, type ParamRef, type PutInput, type PutOptions, type QueryByTagParams, type QueryParams, type ResolveConfig, type ResolveDeps, type SkCondition, type StaticSiteConfig, type StaticSiteHandler, type StreamView, type TableBatchCompleteFn, type TableBatchFn, type TableClient, type TableConfig, type TableHandler, type TableItem, type TableKey, type TableRecord, type TableRecordFn, type UpdateActions, defineApp, defineBucket, defineConfig, defineFifoQueue, defineHttp, defineStaticSite, defineTable, param, typed };
|
|
1275
|
+
export { type AppConfig, type AppHandler, type BucketClient, type BucketConfig, type BucketEvent, type BucketHandler, type BucketObjectCreatedFn, type BucketObjectRemovedFn, type ContentType, type DefineBucketOptions, type DefineFifoQueueOptions, type DefineHttpOptions, type DefineTableOptions, type EffortlessConfig, type FailedRecord, type FifoQueueBatchFn, type FifoQueueConfig, type FifoQueueHandler, type FifoQueueMessage, type FifoQueueMessageFn, type HttpConfig, type HttpHandler, type HttpHandlerFn, type HttpMethod, type HttpRequest, type HttpResponse, type LambdaConfig, type LambdaWithPermissions, type LogLevel, type MiddlewareDeny, type MiddlewareHandler, type MiddlewareRedirect, type MiddlewareRequest, type MiddlewareResult, type ParamRef, type PutInput, type PutOptions, type QueryByTagParams, type QueryParams, type ResolveConfig, type ResolveDeps, type SkCondition, type StaticFiles, type StaticSiteConfig, type StaticSiteHandler, type StreamView, type TableBatchCompleteFn, type TableBatchFn, type TableClient, type TableConfig, type TableHandler, type TableItem, type TableKey, type TableRecord, type TableRecordFn, type UpdateActions, defineApp, defineBucket, defineConfig, defineFifoQueue, defineHttp, defineStaticSite, defineTable, param, typed };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/handlers/define-http.ts","../src/handlers/define-table.ts","../src/handlers/define-app.ts","../src/handlers/define-static-site.ts","../src/handlers/define-fifo-queue.ts","../src/handlers/define-bucket.ts","../src/helpers.ts"],"sourcesContent":["/**\n * Configuration for an Effortless project.\n *\n * @example\n * ```typescript\n * // effortless.config.ts\n * import { defineConfig } from \"effortless-aws\";\n *\n * export default defineConfig({\n * name: \"my-service\",\n * region: \"eu-central-1\",\n * handlers: \"src\",\n * });\n * ```\n */\nexport type EffortlessConfig = {\n /**\n * Project name used for resource naming and tagging.\n * This becomes part of Lambda function names, IAM roles, etc.\n */\n name: string;\n\n /**\n * Default AWS region for all handlers.\n * Can be overridden per-handler or via CLI `--region` flag.\n * @default \"eu-central-1\"\n */\n region?: string;\n\n /**\n * Deployment stage (e.g., \"dev\", \"staging\", \"prod\").\n * Used for resource isolation and tagging.\n * @default \"dev\"\n */\n stage?: string;\n\n /**\n * Glob patterns or directory paths to scan for handlers.\n * Used by `eff deploy` (without file argument) to auto-discover handlers.\n *\n * @example\n * ```typescript\n * // Single directory - scans for all .ts files\n * handlers: \"src\"\n *\n * // Glob patterns\n * handlers: [\"src/**\\/*.ts\", \"lib/**\\/*.handler.ts\"]\n * ```\n */\n handlers?: string | string[];\n\n /**\n * Default settings applied to all handlers unless overridden.\n *\n * All Lambdas run on ARM64 (Graviton2) architecture — ~20% cheaper than x86_64\n * with better price-performance for most workloads.\n */\n defaults?: {\n /**\n * Lambda memory in MB. AWS allocates proportional CPU —\n * 1769 MB gives one full vCPU.\n * @default 256\n */\n memory?: number;\n\n /**\n * Lambda timeout as a human-readable string.\n * AWS maximum is 15 minutes.\n * @example \"30 seconds\", \"5 minutes\"\n */\n timeout?: string;\n\n /**\n * Node.js Lambda runtime version.\n * @default \"nodejs24.x\"\n */\n runtime?: string;\n };\n};\n\n/**\n * Helper function for type-safe configuration.\n * Returns the config object as-is, but provides TypeScript autocompletion.\n *\n * @example\n * ```typescript\n * import { defineConfig } from \"effortless-aws\";\n *\n * export default defineConfig({\n * name: \"my-service\",\n * region: \"eu-central-1\",\n * handlers: \"src\",\n * });\n * ```\n */\nexport const defineConfig = (config: EffortlessConfig): EffortlessConfig => config;\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps } from \"./shared\";\nexport type { ResolveDeps } from \"./shared\";\n\n/** HTTP methods supported by API Gateway */\nexport type HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** Short content-type aliases for common response formats */\nexport type ContentType = \"json\" | \"html\" | \"text\" | \"css\" | \"js\" | \"xml\" | \"csv\" | \"svg\";\n\n/**\n * Incoming HTTP request object passed to the handler\n */\nexport type HttpRequest = {\n /** HTTP method (GET, POST, etc.) */\n method: string;\n /** Request path (e.g., \"/users/123\") */\n path: string;\n /** Request headers */\n headers: Record<string, string | undefined>;\n /** Query string parameters */\n query: Record<string, string | undefined>;\n /** Path parameters extracted from route (e.g., {id} -> params.id) */\n params: Record<string, string | undefined>;\n /** Parsed request body (JSON parsed if Content-Type is application/json) */\n body: unknown;\n /** Raw unparsed request body */\n rawBody?: string;\n};\n\n/**\n * HTTP response returned from the handler\n */\nexport type HttpResponse = {\n /** HTTP status code (e.g., 200, 404, 500) */\n status: number;\n /** Response body — JSON-serialized by default, or sent as string when contentType is set */\n body?: unknown;\n /**\n * Short content-type alias. Resolves to full MIME type automatically:\n * - `\"json\"` → `application/json` (default if omitted)\n * - `\"html\"` → `text/html; charset=utf-8`\n * - `\"text\"` → `text/plain; charset=utf-8`\n * - `\"css\"` → `text/css; charset=utf-8`\n * - `\"js\"` → `application/javascript; charset=utf-8`\n * - `\"xml\"` → `application/xml; charset=utf-8`\n * - `\"csv\"` → `text/csv; charset=utf-8`\n * - `\"svg\"` → `image/svg+xml; charset=utf-8`\n */\n contentType?: ContentType;\n /** Response headers (use for custom content-types not covered by contentType) */\n headers?: Record<string, string>;\n};\n\n/**\n * Configuration options extracted from DefineHttpOptions (without onRequest callback)\n */\nexport type HttpConfig = LambdaWithPermissions & {\n /** HTTP method for the route */\n method: HttpMethod;\n /** Route path (e.g., \"/api/users\", \"/api/users/{id}\") */\n path: string;\n};\n\n/**\n * Handler function type for HTTP endpoints\n *\n * @typeParam T - Type of the validated request body (from schema function)\n * @typeParam C - Type of the setup result (from setup function)\n * @typeParam D - Type of the deps (from deps declaration)\n * @typeParam P - Type of the params (from params declaration)\n */\nexport type HttpHandlerFn<T = undefined, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { req: HttpRequest }\n & ([T] extends [undefined] ? {} : { data: T })\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<HttpResponse>;\n\n/**\n * Setup factory type — always receives an args object.\n * Args include `deps` and/or `config` when declared (empty `{}` otherwise).\n */\ntype SetupFactory<C, D, P> =\n (args:\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n ) => C | Promise<C>;\n\n/**\n * Options for defining an HTTP endpoint\n *\n * @typeParam T - Type of the validated request body (inferred from schema function)\n * @typeParam C - Type of the setup result returned by setup function\n * @typeParam D - Type of the deps (from deps declaration)\n * @typeParam P - Type of the params (from params declaration)\n */\nexport type DefineHttpOptions<\n T = undefined,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> = HttpConfig & {\n /**\n * Decode/validate function for the request body.\n * Called with the parsed body; should return typed data or throw on validation failure.\n * When provided, the handler receives validated `data` and invalid requests get a 400 response.\n *\n * Works with any validation library:\n * - Effect: `S.decodeUnknownSync(MySchema)`\n * - Zod: `(body) => myZodSchema.parse(body)`\n */\n schema?: (input: unknown) => T;\n /**\n * Error handler called when schema validation or onRequest throws.\n * Receives the error and request, returns an HttpResponse.\n * If not provided, defaults to 400 for validation errors and 500 for handler errors.\n */\n onError?: (error: unknown, req: HttpRequest) => HttpResponse;\n /**\n * Factory function to initialize shared state for the request handler.\n * Called once on cold start, result is cached and reused across invocations.\n * When deps/params are declared, receives them as argument.\n * Supports both sync and async return values.\n */\n setup?: SetupFactory<C, D, P>;\n /**\n * Dependencies on other handlers (tables, queues, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n * Typed values are injected into the handler via the `config` argument.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `readStatic` callback argument.\n */\n static?: S;\n /** HTTP request handler function */\n onRequest: HttpHandlerFn<T, C, D, P, S>;\n};\n\n/**\n * Internal handler object created by defineHttp\n * @internal\n */\nexport type HttpHandler<T = undefined, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-http\";\n readonly __spec: HttpConfig;\n readonly schema?: (input: unknown) => T;\n readonly onError?: (error: unknown, req: HttpRequest) => HttpResponse;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onRequest: HttpHandlerFn<T, C, D, P, S>;\n};\n\n/**\n * Define an HTTP endpoint that creates an API Gateway route + Lambda function\n *\n * @typeParam T - Type of the validated request body (inferred from schema function)\n * @typeParam C - Type of the setup result (inferred from setup function)\n * @typeParam D - Type of the deps (from deps declaration)\n * @typeParam P - Type of the params (from params declaration)\n * @param options - Configuration, optional schema, optional setup factory, and request handler\n * @returns Handler object used by the deployment system\n *\n * @example Basic GET endpoint\n * ```typescript\n * export const hello = defineHttp({\n * method: \"GET\",\n * path: \"/hello\",\n * onRequest: async ({ req }) => ({\n * status: 200,\n * body: { message: \"Hello World!\" }\n * })\n * });\n * ```\n *\n * @example With SSM parameters\n * ```typescript\n * import { param } from \"effortless-aws\";\n *\n * export const api = defineHttp({\n * method: \"GET\",\n * path: \"/orders\",\n * config: {\n * dbUrl: param(\"database-url\"),\n * },\n * setup: async ({ config }) => ({\n * pool: createPool(config.dbUrl),\n * }),\n * onRequest: async ({ req, ctx, config }) => ({\n * status: 200,\n * body: { dbUrl: config.dbUrl }\n * })\n * });\n * ```\n */\nexport const defineHttp = <\n T = undefined,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineHttpOptions<T, C, D, P, S>\n): HttpHandler<T, C, D, P, S> => {\n const { onRequest, onError, setup, schema, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-http\",\n __spec,\n ...(schema ? { schema } : {}),\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n onRequest\n } as HttpHandler<T, C, D, P, S>;\n};\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig, TableKey, TableItem } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps } from \"./shared\";\nimport type { TableClient } from \"../runtime/table-client\";\n\n/** DynamoDB Streams view type - determines what data is captured in stream records */\nexport type StreamView = \"NEW_AND_OLD_IMAGES\" | \"NEW_IMAGE\" | \"OLD_IMAGE\" | \"KEYS_ONLY\";\n\n/**\n * Configuration options for defineTable (single-table design).\n *\n * Tables always use `pk (S)` + `sk (S)` keys, `tag (S)` discriminator,\n * `data (M)` for domain fields, and `ttl (N)` for optional expiration.\n */\nexport type TableConfig = LambdaWithPermissions & {\n /** DynamoDB billing mode (default: \"PAY_PER_REQUEST\") */\n billingMode?: \"PAY_PER_REQUEST\" | \"PROVISIONED\";\n /** Stream view type - what data to include in stream records (default: \"NEW_AND_OLD_IMAGES\") */\n streamView?: StreamView;\n /** Number of records to process in each Lambda invocation (1-10000, default: 100) */\n batchSize?: number;\n /** Maximum time in seconds to gather records before invoking (0-300, default: 2) */\n batchWindow?: number;\n /** Where to start reading the stream (default: \"LATEST\") */\n startingPosition?: \"LATEST\" | \"TRIM_HORIZON\";\n /**\n * Name of the field in `data` that serves as the entity type discriminant.\n * Effortless auto-copies `data[tagField]` to the top-level DynamoDB `tag` attribute on `put()`.\n * Defaults to `\"tag\"`.\n *\n * @example\n * ```typescript\n * export const orders = defineTable({\n * tagField: \"type\",\n * schema: typed<{ type: \"order\"; amount: number }>(),\n * onRecord: async ({ record }) => { ... }\n * });\n * ```\n */\n tagField?: string;\n};\n\n/**\n * DynamoDB stream record passed to onRecord callback.\n *\n * `new` and `old` are full `TableItem<T>` objects with the single-table envelope.\n *\n * @typeParam T - Type of the domain data (inside `data`)\n */\nexport type TableRecord<T = Record<string, unknown>> = {\n /** Type of modification: INSERT, MODIFY, or REMOVE */\n eventName: \"INSERT\" | \"MODIFY\" | \"REMOVE\";\n /** New item value (present for INSERT and MODIFY) */\n new?: TableItem<T>;\n /** Old item value (present for MODIFY and REMOVE) */\n old?: TableItem<T>;\n /** Primary key of the affected item */\n keys: TableKey;\n /** Sequence number for ordering */\n sequenceNumber?: string;\n /** Approximate timestamp when the modification occurred */\n timestamp?: number;\n};\n\n/**\n * Information about a failed record during batch processing\n *\n * @typeParam T - Type of the domain data\n */\nexport type FailedRecord<T = Record<string, unknown>> = {\n /** The record that failed to process */\n record: TableRecord<T>;\n /** The error that occurred */\n error: unknown;\n};\n\n/**\n * Setup factory type for table handlers.\n * Always receives `table: TableClient<T>` (self-client for the handler's own table).\n * Also receives `deps` and/or `config` when declared.\n */\ntype SetupFactory<C, T, D, P> = (args:\n & { table: TableClient<T> }\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n ) => C | Promise<C>;\n\n/**\n * Callback function type for processing a single DynamoDB stream record\n */\nexport type TableRecordFn<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { record: TableRecord<T>; table: TableClient<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<R>;\n\n/**\n * Callback function type for processing accumulated batch results\n */\nexport type TableBatchCompleteFn<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { results: R[]; failures: FailedRecord<T>[]; table: TableClient<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<void>;\n\n/**\n * Callback function type for processing all records in a batch at once\n */\nexport type TableBatchFn<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { records: TableRecord<T>[]; table: TableClient<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<void>;\n\n/** Base options shared by all defineTable variants */\ntype DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = Omit<TableConfig, \"tagField\"> & {\n /** Name of the field in `data` that serves as the entity type discriminant (default: `\"tag\"`). */\n tagField?: Extract<keyof T, string>;\n /**\n * Decode/validate function for the `data` portion of stream record items.\n * Called with the unmarshalled `data` attribute; should return typed data or throw on validation failure.\n * When provided, T is inferred from the return type — no need to specify generic parameters.\n */\n schema?: (input: unknown) => T;\n /**\n * Error handler called when onRecord, onBatch, or onBatchComplete throws.\n * Receives the error. If not provided, defaults to `console.error`.\n */\n onError?: (error: unknown) => void;\n /**\n * Factory function to initialize shared state for callbacks.\n * Called once on cold start, result is cached and reused across invocations.\n * When deps/params are declared, receives them as argument.\n * Supports both sync and async return values.\n */\n setup?: SetupFactory<C, T, D, P>;\n /**\n * Dependencies on other handlers (tables, queues, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n * Typed values are injected into the handler via the `config` argument.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `readStatic` callback argument.\n */\n static?: S;\n};\n\n/** Per-record processing: onRecord with optional onBatchComplete */\ntype DefineTableWithOnRecord<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {\n onRecord: TableRecordFn<T, C, R, D, P, S>;\n onBatchComplete?: TableBatchCompleteFn<T, C, R, D, P, S>;\n onBatch?: never;\n};\n\n/** Batch processing: onBatch processes all records at once */\ntype DefineTableWithOnBatch<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {\n onBatch: TableBatchFn<T, C, D, P, S>;\n onRecord?: never;\n onBatchComplete?: never;\n};\n\n/** Resource-only: no handler, just creates the table */\ntype DefineTableResourceOnly<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {\n onRecord?: never;\n onBatch?: never;\n onBatchComplete?: never;\n};\n\nexport type DefineTableOptions<\n T = Record<string, unknown>,\n C = undefined,\n R = void,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> =\n | DefineTableWithOnRecord<T, C, R, D, P, S>\n | DefineTableWithOnBatch<T, C, D, P, S>\n | DefineTableResourceOnly<T, C, D, P, S>;\n\n/**\n * Internal handler object created by defineTable\n * @internal\n */\nexport type TableHandler<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-table\";\n readonly __spec: TableConfig;\n readonly schema?: (input: unknown) => T;\n readonly onError?: (error: unknown) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onRecord?: TableRecordFn<T, C, R, D, P, S>;\n readonly onBatchComplete?: TableBatchCompleteFn<T, C, R, D, P, S>;\n readonly onBatch?: TableBatchFn<T, C, D, P, S>;\n};\n\n/**\n * Define a DynamoDB table with optional stream handler (single-table design).\n *\n * Creates a table with fixed key schema: `pk (S)` + `sk (S)`, plus `tag (S)`,\n * `data (M)`, and `ttl (N)` attributes. TTL is always enabled.\n *\n * @example Table with stream handler (typed)\n * ```typescript\n * type OrderData = { amount: number; status: string };\n *\n * export const orders = defineTable({\n * schema: typed<OrderData>(),\n * streamView: \"NEW_AND_OLD_IMAGES\",\n * batchSize: 10,\n * onRecord: async ({ record }) => {\n * if (record.eventName === \"INSERT\") {\n * console.log(\"New order:\", record.new?.data.amount);\n * }\n * }\n * });\n * ```\n *\n * @example Table only (no Lambda)\n * ```typescript\n * export const users = defineTable({});\n * ```\n */\nexport const defineTable = <\n T = Record<string, unknown>,\n C = undefined,\n R = void,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineTableOptions<T, C, R, D, P, S>\n): TableHandler<T, C, R, D, P, S> => {\n const { onRecord, onBatchComplete, onBatch, onError, schema, setup, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-table\",\n __spec,\n ...(schema ? { schema } : {}),\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n ...(onRecord ? { onRecord } : {}),\n ...(onBatchComplete ? { onBatchComplete } : {}),\n ...(onBatch ? { onBatch } : {})\n } as TableHandler<T, C, R, D, P, S>;\n};\n","import type { LambdaConfig } from \"../helpers\";\n\n/**\n * Configuration for a Lambda-served static site (API Gateway + Lambda)\n */\nexport type AppConfig = LambdaConfig & {\n /** Base URL path the site is served under (e.g., \"/app\") */\n path?: string;\n /** Directory containing the static site files, relative to project root */\n dir: string;\n /** Default file for directory requests (default: \"index.html\") */\n index?: string;\n /** SPA mode: serve index.html for all paths that don't match a file (default: false) */\n spa?: boolean;\n /** Shell command to run before deploy to generate site content (e.g., \"npx astro build\") */\n build?: string;\n};\n\n/**\n * Internal handler object created by defineApp\n * @internal\n */\nexport type AppHandler = {\n readonly __brand: \"effortless-app\";\n readonly __spec: AppConfig;\n};\n\n/**\n * Deploy a static site via Lambda + API Gateway.\n * Files are bundled into the Lambda ZIP and served with auto-detected content types.\n *\n * For CDN-backed sites (S3 + CloudFront), use {@link defineStaticSite} instead.\n *\n * @param options - Site configuration: path, directory, optional SPA mode\n * @returns Handler object used by the deployment system\n *\n * @example Basic static site\n * ```typescript\n * export const app = defineApp({\n * path: \"/app\",\n * dir: \"src/webapp\",\n * });\n * ```\n */\nexport const defineApp = (options: AppConfig): AppHandler => ({\n __brand: \"effortless-app\",\n __spec: options,\n});\n","/** Simplified request object passed to middleware */\nexport type MiddlewareRequest = {\n uri: string;\n method: string;\n querystring: string;\n headers: Record<string, string>;\n cookies: Record<string, string>;\n};\n\n/** Redirect the user to another URL */\nexport type MiddlewareRedirect = {\n redirect: string;\n status?: 301 | 302 | 307 | 308;\n};\n\n/** Deny access with a 403 status */\nexport type MiddlewareDeny = {\n status: 403;\n body?: string;\n};\n\n/** Middleware return type: redirect, deny, or void (continue serving) */\nexport type MiddlewareResult = MiddlewareRedirect | MiddlewareDeny | void;\n\n/** Function that runs before serving static files via Lambda@Edge */\nexport type MiddlewareHandler = (\n request: MiddlewareRequest\n) => Promise<MiddlewareResult> | MiddlewareResult;\n\n/**\n * Configuration for a static site handler (S3 + CloudFront)\n */\nexport type StaticSiteConfig = {\n /** Handler name. Defaults to export name if not specified */\n name?: string;\n /** Directory containing the static site files, relative to project root */\n dir: string;\n /** Default file for directory requests (default: \"index.html\") */\n index?: string;\n /** SPA mode: serve index.html for all paths that don't match a file (default: false) */\n spa?: boolean;\n /** Shell command to run before deploy to generate site content (e.g., \"npx astro build\") */\n build?: string;\n /** Custom domain name (e.g., \"effortless-aws.website\"). Requires an ACM certificate in us-east-1. If the cert also covers www, a 301 redirect from www to non-www is set up automatically. */\n domain?: string;\n /** Lambda@Edge middleware that runs before serving pages. Use for auth checks, redirects, etc. */\n middleware?: MiddlewareHandler;\n};\n\n/**\n * Internal handler object created by defineStaticSite\n * @internal\n */\nexport type StaticSiteHandler = {\n readonly __brand: \"effortless-static-site\";\n readonly __spec: StaticSiteConfig;\n};\n\n/**\n * Deploy a static site via S3 + CloudFront CDN.\n *\n * @param options - Static site configuration: directory, optional SPA mode, build command\n * @returns Handler object used by the deployment system\n *\n * @example Documentation site\n * ```typescript\n * export const docs = defineStaticSite({\n * dir: \"dist\",\n * build: \"npx astro build\",\n * });\n * ```\n *\n * @example SPA with client-side routing\n * ```typescript\n * export const app = defineStaticSite({\n * dir: \"dist\",\n * spa: true,\n * build: \"npm run build\",\n * });\n * ```\n *\n * @example Protected site with middleware (Lambda@Edge)\n * ```typescript\n * export const admin = defineStaticSite({\n * dir: \"admin/dist\",\n * middleware: async (request) => {\n * if (!request.cookies.session) {\n * return { redirect: \"/login\" };\n * }\n * },\n * });\n * ```\n */\nexport const defineStaticSite = (options: StaticSiteConfig): StaticSiteHandler => ({\n __brand: \"effortless-static-site\",\n __spec: options,\n});\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps } from \"./shared\";\n\n/**\n * Parsed SQS FIFO message passed to the handler callbacks.\n *\n * @typeParam T - Type of the decoded message body (from schema function)\n */\nexport type FifoQueueMessage<T = unknown> = {\n /** Unique message identifier */\n messageId: string;\n /** Receipt handle for acknowledgement */\n receiptHandle: string;\n /** Parsed message body (JSON-decoded, then optionally schema-validated) */\n body: T;\n /** Raw unparsed message body string */\n rawBody: string;\n /** Message group ID (FIFO ordering key) */\n messageGroupId: string;\n /** Message deduplication ID */\n messageDeduplicationId?: string;\n /** SQS message attributes */\n messageAttributes: Record<string, { dataType?: string; stringValue?: string }>;\n /** Approximate first receive timestamp */\n approximateFirstReceiveTimestamp?: string;\n /** Approximate receive count */\n approximateReceiveCount?: string;\n /** Sent timestamp */\n sentTimestamp?: string;\n};\n\n/**\n * Configuration options for a FIFO queue handler\n */\nexport type FifoQueueConfig = LambdaWithPermissions & {\n /** Number of messages per Lambda invocation (1-10 for FIFO, default: 10) */\n batchSize?: number;\n /** Maximum time in seconds to gather messages before invoking (0-300, default: 0) */\n batchWindow?: number;\n /** Visibility timeout in seconds (default: max of timeout or 30) */\n visibilityTimeout?: number;\n /** Message retention period in seconds (60-1209600, default: 345600 = 4 days) */\n retentionPeriod?: number;\n /** Enable content-based deduplication (default: true) */\n contentBasedDeduplication?: boolean;\n};\n\n/**\n * Setup factory type — always receives an args object.\n * Args include `deps` and/or `config` when declared (empty `{}` otherwise).\n */\ntype SetupFactory<C, D, P> =\n (args:\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n ) => C | Promise<C>;\n\n/**\n * Per-message handler function.\n * Called once per message in the batch. Failures are reported individually.\n */\nexport type FifoQueueMessageFn<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { message: FifoQueueMessage<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<void>;\n\n/**\n * Batch handler function.\n * Called once with all messages in the batch.\n */\nexport type FifoQueueBatchFn<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { messages: FifoQueueMessage<T>[] }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<void>;\n\n/** Base options shared by all defineFifoQueue variants */\ntype DefineFifoQueueBase<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = FifoQueueConfig & {\n /**\n * Decode/validate function for the message body.\n * Called with the JSON-parsed body; should return typed data or throw on validation failure.\n */\n schema?: (input: unknown) => T;\n /**\n * Error handler called when onMessage or onBatch throws.\n * If not provided, defaults to `console.error`.\n */\n onError?: (error: unknown) => void;\n /**\n * Factory function to initialize shared state for the handler.\n * Called once on cold start, result is cached and reused across invocations.\n * When deps/params are declared, receives them as argument.\n */\n setup?: SetupFactory<C, D, P>;\n /**\n * Dependencies on other handlers (tables, queues, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `readStatic` callback argument.\n */\n static?: S;\n};\n\n/** Per-message processing */\ntype DefineFifoQueueWithOnMessage<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {\n onMessage: FifoQueueMessageFn<T, C, D, P, S>;\n onBatch?: never;\n};\n\n/** Batch processing: all messages at once */\ntype DefineFifoQueueWithOnBatch<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {\n onBatch: FifoQueueBatchFn<T, C, D, P, S>;\n onMessage?: never;\n};\n\nexport type DefineFifoQueueOptions<\n T = unknown,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> =\n | DefineFifoQueueWithOnMessage<T, C, D, P, S>\n | DefineFifoQueueWithOnBatch<T, C, D, P, S>;\n\n/**\n * Internal handler object created by defineFifoQueue\n * @internal\n */\nexport type FifoQueueHandler<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-fifo-queue\";\n readonly __spec: FifoQueueConfig;\n readonly schema?: (input: unknown) => T;\n readonly onError?: (error: unknown) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onMessage?: FifoQueueMessageFn<T, C, D, P, S>;\n readonly onBatch?: FifoQueueBatchFn<T, C, D, P, S>;\n};\n\n/**\n * Define a FIFO SQS queue with a Lambda message handler\n *\n * Creates:\n * - SQS FIFO queue (with `.fifo` suffix)\n * - Lambda function triggered by the queue\n * - Event source mapping with partial batch failure support\n *\n * @example Per-message processing\n * ```typescript\n * type OrderEvent = { orderId: string; action: string };\n *\n * export const orderQueue = defineFifoQueue<OrderEvent>({\n * onMessage: async ({ message }) => {\n * console.log(\"Processing order:\", message.body.orderId);\n * }\n * });\n * ```\n *\n * @example Batch processing with schema\n * ```typescript\n * export const notifications = defineFifoQueue({\n * schema: (input) => NotificationSchema.parse(input),\n * batchSize: 5,\n * onBatch: async ({ messages }) => {\n * await sendAll(messages.map(m => m.body));\n * }\n * });\n * ```\n */\nexport const defineFifoQueue = <\n T = unknown,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineFifoQueueOptions<T, C, D, P, S>\n): FifoQueueHandler<T, C, D, P, S> => {\n const { onMessage, onBatch, onError, schema, setup, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-fifo-queue\",\n __spec,\n ...(schema ? { schema } : {}),\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n ...(onMessage ? { onMessage } : {}),\n ...(onBatch ? { onBatch } : {})\n } as FifoQueueHandler<T, C, D, P, S>;\n};\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps } from \"./shared\";\nimport type { BucketClient } from \"../runtime/bucket-client\";\n\n/**\n * Configuration options for defineBucket.\n */\nexport type BucketConfig = LambdaWithPermissions & {\n /** S3 key prefix filter for event notifications (e.g., \"uploads/\") */\n prefix?: string;\n /** S3 key suffix filter for event notifications (e.g., \".jpg\") */\n suffix?: string;\n};\n\n/**\n * S3 event record passed to onObjectCreated/onObjectRemoved callbacks.\n */\nexport type BucketEvent = {\n /** S3 event name (e.g., \"ObjectCreated:Put\", \"ObjectRemoved:Delete\") */\n eventName: string;\n /** Object key (path within the bucket) */\n key: string;\n /** Object size in bytes (present for created events) */\n size?: number;\n /** Object ETag (present for created events) */\n eTag?: string;\n /** ISO 8601 timestamp of when the event occurred */\n eventTime?: string;\n /** S3 bucket name */\n bucketName: string;\n};\n\n/**\n * Callback function type for S3 ObjectCreated events\n */\nexport type BucketObjectCreatedFn<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { event: BucketEvent; bucket: BucketClient }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<void>;\n\n/**\n * Callback function type for S3 ObjectRemoved events\n */\nexport type BucketObjectRemovedFn<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { event: BucketEvent; bucket: BucketClient }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { readStatic: (path: string) => string })\n ) => Promise<void>;\n\n/**\n * Setup factory type for bucket handlers.\n * Always receives `bucket: BucketClient` (self-client for the handler's own bucket).\n * Also receives `deps` and/or `config` when declared.\n */\ntype SetupFactory<C, D, P> = (args:\n & { bucket: BucketClient }\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n ) => C | Promise<C>;\n\n/** Base options shared by all defineBucket variants */\ntype DefineBucketBase<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = BucketConfig & {\n /**\n * Error handler called when onObjectCreated or onObjectRemoved throws.\n * If not provided, defaults to `console.error`.\n */\n onError?: (error: unknown) => void;\n /**\n * Factory function to initialize shared state for callbacks.\n * Called once on cold start, result is cached and reused across invocations.\n * Always receives `bucket: BucketClient` (self-client). When deps/config\n * are declared, receives them as well.\n */\n setup?: SetupFactory<C, D, P>;\n /**\n * Dependencies on other handlers (tables, buckets, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `readStatic` callback argument.\n */\n static?: S;\n};\n\n/** With event handlers (at least one callback) */\ntype DefineBucketWithHandlers<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {\n onObjectCreated?: BucketObjectCreatedFn<C, D, P, S>;\n onObjectRemoved?: BucketObjectRemovedFn<C, D, P, S>;\n};\n\n/** Resource-only: no Lambda, just creates the bucket */\ntype DefineBucketResourceOnly<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {\n onObjectCreated?: never;\n onObjectRemoved?: never;\n};\n\nexport type DefineBucketOptions<\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> =\n | DefineBucketWithHandlers<C, D, P, S>\n | DefineBucketResourceOnly<C, D, P, S>;\n\n/**\n * Internal handler object created by defineBucket\n * @internal\n */\nexport type BucketHandler<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-bucket\";\n readonly __spec: BucketConfig;\n readonly onError?: (error: unknown) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onObjectCreated?: BucketObjectCreatedFn<C, D, P, S>;\n readonly onObjectRemoved?: BucketObjectRemovedFn<C, D, P, S>;\n};\n\n/**\n * Define an S3 bucket with optional event handlers.\n *\n * Creates an S3 bucket. When event handlers are provided, also creates a Lambda\n * function triggered by S3 event notifications.\n *\n * @example Bucket with event handler\n * ```typescript\n * export const uploads = defineBucket({\n * prefix: \"images/\",\n * suffix: \".jpg\",\n * onObjectCreated: async ({ event, bucket }) => {\n * const file = await bucket.get(event.key);\n * console.log(\"New upload:\", event.key, file?.body.length);\n * }\n * });\n * ```\n *\n * @example Resource-only bucket (no Lambda)\n * ```typescript\n * export const assets = defineBucket({});\n * ```\n *\n * @example As a dependency\n * ```typescript\n * export const processImage = defineHttp({\n * method: \"POST\",\n * path: \"/process\",\n * deps: { uploads },\n * onRequest: async ({ req, deps }) => {\n * await deps.uploads.put(\"output.jpg\", buffer);\n * return { status: 200, body: \"OK\" };\n * }\n * });\n * ```\n */\nexport const defineBucket = <\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineBucketOptions<C, D, P, S>\n): BucketHandler<C, D, P, S> => {\n const { onObjectCreated, onObjectRemoved, onError, setup, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-bucket\",\n __spec,\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n ...(onObjectCreated ? { onObjectCreated } : {}),\n ...(onObjectRemoved ? { onObjectRemoved } : {}),\n } as BucketHandler<C, D, P, S>;\n};\n","// Public helpers — this file must have ZERO heavy imports (no effect, no AWS SDK, no deploy code).\n// It is the source of truth for param(), typed(), and related types used by the public API.\n\n// ============ Permissions ============\n\ntype AwsService =\n | \"dynamodb\"\n | \"s3\"\n | \"sqs\"\n | \"sns\"\n | \"ses\"\n | \"ssm\"\n | \"lambda\"\n | \"events\"\n | \"secretsmanager\"\n | \"cognito-idp\"\n | \"logs\";\n\nexport type Permission = `${AwsService}:${string}` | (string & {});\n\n// ============ Lambda config ============\n\n/** Logging verbosity level for Lambda handlers */\nexport type LogLevel = \"error\" | \"info\" | \"debug\";\n\n/**\n * Common Lambda configuration shared by all handler types.\n */\nexport type LambdaConfig = {\n /** Lambda memory in MB (default: 256) */\n memory?: number;\n /** Lambda timeout in seconds (default: 30) */\n timeout?: number;\n /** Logging verbosity: \"error\" (errors only), \"info\" (+ execution summary), \"debug\" (+ input/output). Default: \"info\" */\n logLevel?: LogLevel;\n};\n\n/**\n * Lambda configuration with additional IAM permissions.\n * Used by handler types that support custom permissions (http, table, fifo-queue).\n */\nexport type LambdaWithPermissions = LambdaConfig & {\n /** Additional IAM permissions for the Lambda */\n permissions?: Permission[];\n};\n\n// ============ Params ============\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyParamRef = ParamRef<any> | string;\n\n/**\n * Reference to an SSM Parameter Store parameter.\n *\n * @typeParam T - The resolved type after optional transform (default: string)\n */\nexport type ParamRef<T = string> = {\n readonly __brand: \"effortless-param\";\n readonly key: string;\n readonly transform?: (raw: string) => T;\n};\n\n/**\n * Maps a config declaration to resolved value types.\n * Plain strings resolve to `string`, `ParamRef<T>` resolves to `T`.\n *\n * @typeParam P - Record of config keys to string or ParamRef instances\n */\nexport type ResolveConfig<P> = {\n [K in keyof P]: P[K] extends ParamRef<infer T> ? T : string;\n};\n\n/**\n * Declare an SSM Parameter Store parameter.\n *\n * The key is combined with project and stage at deploy time to form the full\n * SSM path: `/${project}/${stage}/${key}`.\n *\n * @param key - Parameter key (e.g., \"database-url\")\n * @param transform - Optional function to transform the raw string value\n * @returns A ParamRef used by the deployment and runtime systems\n *\n * @example Simple string parameter\n * ```typescript\n * config: {\n * dbUrl: param(\"database-url\"),\n * }\n * ```\n *\n * @example With transform (e.g., TOML parsing)\n * ```typescript\n * import TOML from \"smol-toml\";\n *\n * config: {\n * appConfig: param(\"app-config\", TOML.parse),\n * }\n * ```\n */\nexport function param(key: string): ParamRef<string>;\nexport function param<T>(key: string, transform: (raw: string) => T): ParamRef<T>;\nexport function param<T = string>(\n key: string,\n transform?: (raw: string) => T\n): ParamRef<T> {\n return {\n __brand: \"effortless-param\",\n key,\n ...(transform ? { transform } : {}),\n } as ParamRef<T>;\n}\n\n// ============ Single-table types ============\n\n/**\n * DynamoDB table key (always pk + sk strings in single-table design).\n */\nexport type TableKey = { pk: string; sk: string };\n\n/**\n * Full DynamoDB item in the single-table design.\n *\n * Every item has a fixed envelope: `pk`, `sk`, `tag`, `data`, and optional `ttl`.\n * `tag` is stored as a top-level DynamoDB attribute (GSI-ready).\n * If your domain type `T` includes a `tag` field, effortless auto-copies\n * `data.tag` to the top-level `tag` on `put()`, so you don't have to pass it twice.\n *\n * @typeParam T - The domain data type stored in the `data` attribute\n */\nexport type TableItem<T> = {\n pk: string;\n sk: string;\n tag: string;\n data: T;\n ttl?: number;\n};\n\n/**\n * Input type for `TableClient.put()`.\n *\n * Unlike `TableItem<T>`, this does NOT include `tag` — effortless auto-extracts\n * the top-level DynamoDB `tag` attribute from your data using the configured\n * tag field (defaults to `data.tag`, configurable via `defineTable({ tag: \"type\" })`).\n *\n * @typeParam T - The domain data type stored in the `data` attribute\n */\nexport type PutInput<T> = {\n pk: string;\n sk: string;\n data: T;\n ttl?: number;\n};\n\n// ============ Typed helper ============\n\n/**\n * Type-only schema helper for handlers.\n *\n * Use this instead of explicit generic parameters like `defineTable<Order>(...)`.\n * It enables TypeScript to infer all generic types from the options object,\n * avoiding the partial-inference problem where specifying one generic\n * forces all others to their defaults.\n *\n * At runtime this is a no-op identity function — it simply returns the input unchanged.\n * The type narrowing happens entirely at the TypeScript level.\n *\n * @example Resource-only table\n * ```typescript\n * type User = { id: string; email: string };\n *\n * export const users = defineTable({\n * schema: typed<User>(),\n * });\n * ```\n *\n * @example Table with stream handler\n * ```typescript\n * export const orders = defineTable({\n * schema: typed<Order>(),\n * setup: async () => ({ db: createClient() }),\n * onRecord: async ({ record, ctx }) => {\n * // record.new.data is Order, ctx is { db: Client } — all inferred\n * },\n * });\n * ```\n */\nexport function typed<T>(): (input: unknown) => T {\n return (input: unknown) => input as T;\n}\n"],"mappings":";AA+FO,IAAM,eAAe,CAAC,WAA+C;;;ACiHrE,IAAM,aAAa,CAOxB,YAC+B;AAC/B,QAAM,EAAE,WAAW,SAAS,OAAO,QAAQ,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AAC5F,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;;;ACSO,IAAM,cAAc,CAQzB,YACmC;AACnC,QAAM,EAAE,UAAU,iBAAiB,SAAS,SAAS,QAAQ,OAAO,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AACrH,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IAC/B,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7C,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/B;AACF;;;AC1NO,IAAM,YAAY,CAAC,aAAoC;AAAA,EAC5D,SAAS;AAAA,EACT,QAAQ;AACV;;;AC8CO,IAAM,mBAAmB,CAAC,aAAkD;AAAA,EACjF,SAAS;AAAA,EACT,QAAQ;AACV;;;AC0FO,IAAM,kBAAkB,CAO7B,YACoC;AACpC,QAAM,EAAE,WAAW,SAAS,SAAS,QAAQ,OAAO,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AACrG,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IACjC,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/B;AACF;;;ACtCO,IAAM,eAAe,CAM1B,YAC8B;AAC9B,QAAM,EAAE,iBAAiB,iBAAiB,SAAS,OAAO,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AAC3G,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7C,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,EAC/C;AACF;;;AC1FO,SAAS,MACd,KACA,WACa;AACb,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,EACnC;AACF;AA4EO,SAAS,QAAkC;AAChD,SAAO,CAAC,UAAmB;AAC7B;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/handlers/define-http.ts","../src/handlers/define-table.ts","../src/handlers/define-app.ts","../src/handlers/define-static-site.ts","../src/handlers/define-fifo-queue.ts","../src/handlers/define-bucket.ts","../src/helpers.ts"],"sourcesContent":["/**\n * Configuration for an Effortless project.\n *\n * @example\n * ```typescript\n * // effortless.config.ts\n * import { defineConfig } from \"effortless-aws\";\n *\n * export default defineConfig({\n * name: \"my-service\",\n * region: \"eu-central-1\",\n * handlers: \"src\",\n * });\n * ```\n */\nexport type EffortlessConfig = {\n /**\n * Project name used for resource naming and tagging.\n * This becomes part of Lambda function names, IAM roles, etc.\n */\n name: string;\n\n /**\n * Default AWS region for all handlers.\n * Can be overridden per-handler or via CLI `--region` flag.\n * @default \"eu-central-1\"\n */\n region?: string;\n\n /**\n * Deployment stage (e.g., \"dev\", \"staging\", \"prod\").\n * Used for resource isolation and tagging.\n * @default \"dev\"\n */\n stage?: string;\n\n /**\n * Glob patterns or directory paths to scan for handlers.\n * Used by `eff deploy` (without file argument) to auto-discover handlers.\n *\n * @example\n * ```typescript\n * // Single directory - scans for all .ts files\n * handlers: \"src\"\n *\n * // Glob patterns\n * handlers: [\"src/**\\/*.ts\", \"lib/**\\/*.handler.ts\"]\n * ```\n */\n handlers?: string | string[];\n\n /**\n * Default settings applied to all handlers unless overridden.\n *\n * All Lambdas run on ARM64 (Graviton2) architecture — ~20% cheaper than x86_64\n * with better price-performance for most workloads.\n */\n defaults?: {\n /**\n * Lambda memory in MB. AWS allocates proportional CPU —\n * 1769 MB gives one full vCPU.\n * @default 256\n */\n memory?: number;\n\n /**\n * Lambda timeout as a human-readable string.\n * AWS maximum is 15 minutes.\n * @example \"30 seconds\", \"5 minutes\"\n */\n timeout?: string;\n\n /**\n * Node.js Lambda runtime version.\n * @default \"nodejs24.x\"\n */\n runtime?: string;\n };\n};\n\n/**\n * Helper function for type-safe configuration.\n * Returns the config object as-is, but provides TypeScript autocompletion.\n *\n * @example\n * ```typescript\n * import { defineConfig } from \"effortless-aws\";\n *\n * export default defineConfig({\n * name: \"my-service\",\n * region: \"eu-central-1\",\n * handlers: \"src\",\n * });\n * ```\n */\nexport const defineConfig = (config: EffortlessConfig): EffortlessConfig => config;\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps, StaticFiles } from \"./shared\";\nexport type { ResolveDeps } from \"./shared\";\n\n/** HTTP methods supported by API Gateway */\nexport type HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/** Short content-type aliases for common response formats */\nexport type ContentType = \"json\" | \"html\" | \"text\" | \"css\" | \"js\" | \"xml\" | \"csv\" | \"svg\";\n\n/**\n * Incoming HTTP request object passed to the handler\n */\nexport type HttpRequest = {\n /** HTTP method (GET, POST, etc.) */\n method: string;\n /** Request path (e.g., \"/users/123\") */\n path: string;\n /** Request headers */\n headers: Record<string, string | undefined>;\n /** Query string parameters */\n query: Record<string, string | undefined>;\n /** Path parameters extracted from route (e.g., {id} -> params.id) */\n params: Record<string, string | undefined>;\n /** Parsed request body (JSON parsed if Content-Type is application/json) */\n body: unknown;\n /** Raw unparsed request body */\n rawBody?: string;\n};\n\n/**\n * HTTP response returned from the handler\n */\nexport type HttpResponse = {\n /** HTTP status code (e.g., 200, 404, 500) */\n status: number;\n /** Response body — JSON-serialized by default, or sent as string when contentType is set */\n body?: unknown;\n /**\n * Short content-type alias. Resolves to full MIME type automatically:\n * - `\"json\"` → `application/json` (default if omitted)\n * - `\"html\"` → `text/html; charset=utf-8`\n * - `\"text\"` → `text/plain; charset=utf-8`\n * - `\"css\"` → `text/css; charset=utf-8`\n * - `\"js\"` → `application/javascript; charset=utf-8`\n * - `\"xml\"` → `application/xml; charset=utf-8`\n * - `\"csv\"` → `text/csv; charset=utf-8`\n * - `\"svg\"` → `image/svg+xml; charset=utf-8`\n */\n contentType?: ContentType;\n /** Response headers (use for custom content-types not covered by contentType) */\n headers?: Record<string, string>;\n};\n\n/**\n * Configuration options extracted from DefineHttpOptions (without onRequest callback)\n */\nexport type HttpConfig = LambdaWithPermissions & {\n /** HTTP method for the route */\n method: HttpMethod;\n /** Route path (e.g., \"/api/users\", \"/api/users/{id}\") */\n path: string;\n};\n\n/**\n * Handler function type for HTTP endpoints\n *\n * @typeParam T - Type of the validated request body (from schema function)\n * @typeParam C - Type of the setup result (from setup function)\n * @typeParam D - Type of the deps (from deps declaration)\n * @typeParam P - Type of the params (from params declaration)\n */\nexport type HttpHandlerFn<T = undefined, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { req: HttpRequest }\n & ([T] extends [undefined] ? {} : { data: T })\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<HttpResponse>;\n\n/**\n * Setup factory type — always receives an args object.\n * Args include `deps` and/or `config` when declared (empty `{}` otherwise).\n */\ntype SetupFactory<C, D, P, S extends string[] | undefined = undefined> =\n (args:\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => C | Promise<C>;\n\n/**\n * Options for defining an HTTP endpoint\n *\n * @typeParam T - Type of the validated request body (inferred from schema function)\n * @typeParam C - Type of the setup result returned by setup function\n * @typeParam D - Type of the deps (from deps declaration)\n * @typeParam P - Type of the params (from params declaration)\n */\nexport type DefineHttpOptions<\n T = undefined,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> = HttpConfig & {\n /**\n * Decode/validate function for the request body.\n * Called with the parsed body; should return typed data or throw on validation failure.\n * When provided, the handler receives validated `data` and invalid requests get a 400 response.\n *\n * Works with any validation library:\n * - Effect: `S.decodeUnknownSync(MySchema)`\n * - Zod: `(body) => myZodSchema.parse(body)`\n */\n schema?: (input: unknown) => T;\n /**\n * Error handler called when schema validation or onRequest throws.\n * Receives the error and request, returns an HttpResponse.\n * If not provided, defaults to 400 for validation errors and 500 for handler errors.\n */\n onError?: (error: unknown, req: HttpRequest) => HttpResponse;\n /**\n * Factory function to initialize shared state for the request handler.\n * Called once on cold start, result is cached and reused across invocations.\n * When deps/params are declared, receives them as argument.\n * Supports both sync and async return values.\n */\n setup?: SetupFactory<C, D, P, S>;\n /**\n * Dependencies on other handlers (tables, queues, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n * Typed values are injected into the handler via the `config` argument.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `files` callback argument.\n */\n static?: S;\n /** HTTP request handler function */\n onRequest: HttpHandlerFn<T, C, D, P, S>;\n};\n\n/**\n * Internal handler object created by defineHttp\n * @internal\n */\nexport type HttpHandler<T = undefined, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-http\";\n readonly __spec: HttpConfig;\n readonly schema?: (input: unknown) => T;\n readonly onError?: (error: unknown, req: HttpRequest) => HttpResponse;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onRequest: HttpHandlerFn<T, C, D, P, S>;\n};\n\n/**\n * Define an HTTP endpoint that creates an API Gateway route + Lambda function\n *\n * @typeParam T - Type of the validated request body (inferred from schema function)\n * @typeParam C - Type of the setup result (inferred from setup function)\n * @typeParam D - Type of the deps (from deps declaration)\n * @typeParam P - Type of the params (from params declaration)\n * @param options - Configuration, optional schema, optional setup factory, and request handler\n * @returns Handler object used by the deployment system\n *\n * @example Basic GET endpoint\n * ```typescript\n * export const hello = defineHttp({\n * method: \"GET\",\n * path: \"/hello\",\n * onRequest: async ({ req }) => ({\n * status: 200,\n * body: { message: \"Hello World!\" }\n * })\n * });\n * ```\n *\n * @example With SSM parameters\n * ```typescript\n * import { param } from \"effortless-aws\";\n *\n * export const api = defineHttp({\n * method: \"GET\",\n * path: \"/orders\",\n * config: {\n * dbUrl: param(\"database-url\"),\n * },\n * setup: async ({ config }) => ({\n * pool: createPool(config.dbUrl),\n * }),\n * onRequest: async ({ req, ctx, config }) => ({\n * status: 200,\n * body: { dbUrl: config.dbUrl }\n * })\n * });\n * ```\n */\nexport const defineHttp = <\n T = undefined,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineHttpOptions<T, C, D, P, S>\n): HttpHandler<T, C, D, P, S> => {\n const { onRequest, onError, setup, schema, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-http\",\n __spec,\n ...(schema ? { schema } : {}),\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n onRequest\n } as HttpHandler<T, C, D, P, S>;\n};\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig, TableKey, TableItem } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps, StaticFiles } from \"./shared\";\nimport type { TableClient } from \"../runtime/table-client\";\n\n/** DynamoDB Streams view type - determines what data is captured in stream records */\nexport type StreamView = \"NEW_AND_OLD_IMAGES\" | \"NEW_IMAGE\" | \"OLD_IMAGE\" | \"KEYS_ONLY\";\n\n/**\n * Configuration options for defineTable (single-table design).\n *\n * Tables always use `pk (S)` + `sk (S)` keys, `tag (S)` discriminator,\n * `data (M)` for domain fields, and `ttl (N)` for optional expiration.\n */\nexport type TableConfig = LambdaWithPermissions & {\n /** DynamoDB billing mode (default: \"PAY_PER_REQUEST\") */\n billingMode?: \"PAY_PER_REQUEST\" | \"PROVISIONED\";\n /** Stream view type - what data to include in stream records (default: \"NEW_AND_OLD_IMAGES\") */\n streamView?: StreamView;\n /** Number of records to process in each Lambda invocation (1-10000, default: 100) */\n batchSize?: number;\n /** Maximum time in seconds to gather records before invoking (0-300, default: 2) */\n batchWindow?: number;\n /** Where to start reading the stream (default: \"LATEST\") */\n startingPosition?: \"LATEST\" | \"TRIM_HORIZON\";\n /**\n * Name of the field in `data` that serves as the entity type discriminant.\n * Effortless auto-copies `data[tagField]` to the top-level DynamoDB `tag` attribute on `put()`.\n * Defaults to `\"tag\"`.\n *\n * @example\n * ```typescript\n * export const orders = defineTable({\n * tagField: \"type\",\n * schema: typed<{ type: \"order\"; amount: number }>(),\n * onRecord: async ({ record }) => { ... }\n * });\n * ```\n */\n tagField?: string;\n};\n\n/**\n * DynamoDB stream record passed to onRecord callback.\n *\n * `new` and `old` are full `TableItem<T>` objects with the single-table envelope.\n *\n * @typeParam T - Type of the domain data (inside `data`)\n */\nexport type TableRecord<T = Record<string, unknown>> = {\n /** Type of modification: INSERT, MODIFY, or REMOVE */\n eventName: \"INSERT\" | \"MODIFY\" | \"REMOVE\";\n /** New item value (present for INSERT and MODIFY) */\n new?: TableItem<T>;\n /** Old item value (present for MODIFY and REMOVE) */\n old?: TableItem<T>;\n /** Primary key of the affected item */\n keys: TableKey;\n /** Sequence number for ordering */\n sequenceNumber?: string;\n /** Approximate timestamp when the modification occurred */\n timestamp?: number;\n};\n\n/**\n * Information about a failed record during batch processing\n *\n * @typeParam T - Type of the domain data\n */\nexport type FailedRecord<T = Record<string, unknown>> = {\n /** The record that failed to process */\n record: TableRecord<T>;\n /** The error that occurred */\n error: unknown;\n};\n\n/**\n * Setup factory type for table handlers.\n * Always receives `table: TableClient<T>` (self-client for the handler's own table).\n * Also receives `deps` and/or `config` when declared.\n */\ntype SetupFactory<C, T, D, P, S extends string[] | undefined = undefined> = (args:\n & { table: TableClient<T> }\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => C | Promise<C>;\n\n/**\n * Callback function type for processing a single DynamoDB stream record\n */\nexport type TableRecordFn<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { record: TableRecord<T>; table: TableClient<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<R>;\n\n/**\n * Callback function type for processing accumulated batch results\n */\nexport type TableBatchCompleteFn<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { results: R[]; failures: FailedRecord<T>[]; table: TableClient<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<void>;\n\n/**\n * Callback function type for processing all records in a batch at once\n */\nexport type TableBatchFn<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { records: TableRecord<T>[]; table: TableClient<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<void>;\n\n/** Base options shared by all defineTable variants */\ntype DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = Omit<TableConfig, \"tagField\"> & {\n /** Name of the field in `data` that serves as the entity type discriminant (default: `\"tag\"`). */\n tagField?: Extract<keyof T, string>;\n /**\n * Decode/validate function for the `data` portion of stream record items.\n * Called with the unmarshalled `data` attribute; should return typed data or throw on validation failure.\n * When provided, T is inferred from the return type — no need to specify generic parameters.\n */\n schema?: (input: unknown) => T;\n /**\n * Error handler called when onRecord, onBatch, or onBatchComplete throws.\n * Receives the error. If not provided, defaults to `console.error`.\n */\n onError?: (error: unknown) => void;\n /**\n * Factory function to initialize shared state for callbacks.\n * Called once on cold start, result is cached and reused across invocations.\n * When deps/params are declared, receives them as argument.\n * Supports both sync and async return values.\n */\n setup?: SetupFactory<C, T, D, P, S>;\n /**\n * Dependencies on other handlers (tables, queues, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n * Typed values are injected into the handler via the `config` argument.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `files` callback argument.\n */\n static?: S;\n};\n\n/** Per-record processing: onRecord with optional onBatchComplete */\ntype DefineTableWithOnRecord<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {\n onRecord: TableRecordFn<T, C, R, D, P, S>;\n onBatchComplete?: TableBatchCompleteFn<T, C, R, D, P, S>;\n onBatch?: never;\n};\n\n/** Batch processing: onBatch processes all records at once */\ntype DefineTableWithOnBatch<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {\n onBatch: TableBatchFn<T, C, D, P, S>;\n onRecord?: never;\n onBatchComplete?: never;\n};\n\n/** Resource-only: no handler, just creates the table */\ntype DefineTableResourceOnly<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {\n onRecord?: never;\n onBatch?: never;\n onBatchComplete?: never;\n};\n\nexport type DefineTableOptions<\n T = Record<string, unknown>,\n C = undefined,\n R = void,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> =\n | DefineTableWithOnRecord<T, C, R, D, P, S>\n | DefineTableWithOnBatch<T, C, D, P, S>\n | DefineTableResourceOnly<T, C, D, P, S>;\n\n/**\n * Internal handler object created by defineTable\n * @internal\n */\nexport type TableHandler<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-table\";\n readonly __spec: TableConfig;\n readonly schema?: (input: unknown) => T;\n readonly onError?: (error: unknown) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onRecord?: TableRecordFn<T, C, R, D, P, S>;\n readonly onBatchComplete?: TableBatchCompleteFn<T, C, R, D, P, S>;\n readonly onBatch?: TableBatchFn<T, C, D, P, S>;\n};\n\n/**\n * Define a DynamoDB table with optional stream handler (single-table design).\n *\n * Creates a table with fixed key schema: `pk (S)` + `sk (S)`, plus `tag (S)`,\n * `data (M)`, and `ttl (N)` attributes. TTL is always enabled.\n *\n * @example Table with stream handler (typed)\n * ```typescript\n * type OrderData = { amount: number; status: string };\n *\n * export const orders = defineTable({\n * schema: typed<OrderData>(),\n * streamView: \"NEW_AND_OLD_IMAGES\",\n * batchSize: 10,\n * onRecord: async ({ record }) => {\n * if (record.eventName === \"INSERT\") {\n * console.log(\"New order:\", record.new?.data.amount);\n * }\n * }\n * });\n * ```\n *\n * @example Table only (no Lambda)\n * ```typescript\n * export const users = defineTable({});\n * ```\n */\nexport const defineTable = <\n T = Record<string, unknown>,\n C = undefined,\n R = void,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineTableOptions<T, C, R, D, P, S>\n): TableHandler<T, C, R, D, P, S> => {\n const { onRecord, onBatchComplete, onBatch, onError, schema, setup, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-table\",\n __spec,\n ...(schema ? { schema } : {}),\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n ...(onRecord ? { onRecord } : {}),\n ...(onBatchComplete ? { onBatchComplete } : {}),\n ...(onBatch ? { onBatch } : {})\n } as TableHandler<T, C, R, D, P, S>;\n};\n","import type { LambdaConfig } from \"../helpers\";\n\n/**\n * Configuration for a Lambda-served static site (API Gateway + Lambda)\n */\nexport type AppConfig = LambdaConfig & {\n /** Base URL path the site is served under (e.g., \"/app\") */\n path?: string;\n /** Directory containing the static site files, relative to project root */\n dir: string;\n /** Default file for directory requests (default: \"index.html\") */\n index?: string;\n /** SPA mode: serve index.html for all paths that don't match a file (default: false) */\n spa?: boolean;\n /** Shell command to run before deploy to generate site content (e.g., \"npx astro build\") */\n build?: string;\n};\n\n/**\n * Internal handler object created by defineApp\n * @internal\n */\nexport type AppHandler = {\n readonly __brand: \"effortless-app\";\n readonly __spec: AppConfig;\n};\n\n/**\n * Deploy a static site via Lambda + API Gateway.\n * Files are bundled into the Lambda ZIP and served with auto-detected content types.\n *\n * For CDN-backed sites (S3 + CloudFront), use {@link defineStaticSite} instead.\n *\n * @param options - Site configuration: path, directory, optional SPA mode\n * @returns Handler object used by the deployment system\n *\n * @example Basic static site\n * ```typescript\n * export const app = defineApp({\n * path: \"/app\",\n * dir: \"src/webapp\",\n * });\n * ```\n */\nexport const defineApp = (options: AppConfig): AppHandler => ({\n __brand: \"effortless-app\",\n __spec: options,\n});\n","/** Simplified request object passed to middleware */\nexport type MiddlewareRequest = {\n uri: string;\n method: string;\n querystring: string;\n headers: Record<string, string>;\n cookies: Record<string, string>;\n};\n\n/** Redirect the user to another URL */\nexport type MiddlewareRedirect = {\n redirect: string;\n status?: 301 | 302 | 307 | 308;\n};\n\n/** Deny access with a 403 status */\nexport type MiddlewareDeny = {\n status: 403;\n body?: string;\n};\n\n/** Middleware return type: redirect, deny, or void (continue serving) */\nexport type MiddlewareResult = MiddlewareRedirect | MiddlewareDeny | void;\n\n/** Function that runs before serving static files via Lambda@Edge */\nexport type MiddlewareHandler = (\n request: MiddlewareRequest\n) => Promise<MiddlewareResult> | MiddlewareResult;\n\n/**\n * Configuration for a static site handler (S3 + CloudFront)\n */\nexport type StaticSiteConfig = {\n /** Handler name. Defaults to export name if not specified */\n name?: string;\n /** Directory containing the static site files, relative to project root */\n dir: string;\n /** Default file for directory requests (default: \"index.html\") */\n index?: string;\n /** SPA mode: serve index.html for all paths that don't match a file (default: false) */\n spa?: boolean;\n /** Shell command to run before deploy to generate site content (e.g., \"npx astro build\") */\n build?: string;\n /** Custom domain name (e.g., \"effortless-aws.website\"). Requires an ACM certificate in us-east-1. If the cert also covers www, a 301 redirect from www to non-www is set up automatically. */\n domain?: string;\n /** Lambda@Edge middleware that runs before serving pages. Use for auth checks, redirects, etc. */\n middleware?: MiddlewareHandler;\n};\n\n/**\n * Internal handler object created by defineStaticSite\n * @internal\n */\nexport type StaticSiteHandler = {\n readonly __brand: \"effortless-static-site\";\n readonly __spec: StaticSiteConfig;\n};\n\n/**\n * Deploy a static site via S3 + CloudFront CDN.\n *\n * @param options - Static site configuration: directory, optional SPA mode, build command\n * @returns Handler object used by the deployment system\n *\n * @example Documentation site\n * ```typescript\n * export const docs = defineStaticSite({\n * dir: \"dist\",\n * build: \"npx astro build\",\n * });\n * ```\n *\n * @example SPA with client-side routing\n * ```typescript\n * export const app = defineStaticSite({\n * dir: \"dist\",\n * spa: true,\n * build: \"npm run build\",\n * });\n * ```\n *\n * @example Protected site with middleware (Lambda@Edge)\n * ```typescript\n * export const admin = defineStaticSite({\n * dir: \"admin/dist\",\n * middleware: async (request) => {\n * if (!request.cookies.session) {\n * return { redirect: \"/login\" };\n * }\n * },\n * });\n * ```\n */\nexport const defineStaticSite = (options: StaticSiteConfig): StaticSiteHandler => ({\n __brand: \"effortless-static-site\",\n __spec: options,\n});\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps, StaticFiles } from \"./shared\";\n\n/**\n * Parsed SQS FIFO message passed to the handler callbacks.\n *\n * @typeParam T - Type of the decoded message body (from schema function)\n */\nexport type FifoQueueMessage<T = unknown> = {\n /** Unique message identifier */\n messageId: string;\n /** Receipt handle for acknowledgement */\n receiptHandle: string;\n /** Parsed message body (JSON-decoded, then optionally schema-validated) */\n body: T;\n /** Raw unparsed message body string */\n rawBody: string;\n /** Message group ID (FIFO ordering key) */\n messageGroupId: string;\n /** Message deduplication ID */\n messageDeduplicationId?: string;\n /** SQS message attributes */\n messageAttributes: Record<string, { dataType?: string; stringValue?: string }>;\n /** Approximate first receive timestamp */\n approximateFirstReceiveTimestamp?: string;\n /** Approximate receive count */\n approximateReceiveCount?: string;\n /** Sent timestamp */\n sentTimestamp?: string;\n};\n\n/**\n * Configuration options for a FIFO queue handler\n */\nexport type FifoQueueConfig = LambdaWithPermissions & {\n /** Number of messages per Lambda invocation (1-10 for FIFO, default: 10) */\n batchSize?: number;\n /** Maximum time in seconds to gather messages before invoking (0-300, default: 0) */\n batchWindow?: number;\n /** Visibility timeout in seconds (default: max of timeout or 30) */\n visibilityTimeout?: number;\n /** Message retention period in seconds (60-1209600, default: 345600 = 4 days) */\n retentionPeriod?: number;\n /** Enable content-based deduplication (default: true) */\n contentBasedDeduplication?: boolean;\n};\n\n/**\n * Setup factory type — always receives an args object.\n * Args include `deps` and/or `config` when declared (empty `{}` otherwise).\n */\ntype SetupFactory<C, D, P, S extends string[] | undefined = undefined> =\n (args:\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => C | Promise<C>;\n\n/**\n * Per-message handler function.\n * Called once per message in the batch. Failures are reported individually.\n */\nexport type FifoQueueMessageFn<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { message: FifoQueueMessage<T> }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<void>;\n\n/**\n * Batch handler function.\n * Called once with all messages in the batch.\n */\nexport type FifoQueueBatchFn<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { messages: FifoQueueMessage<T>[] }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<void>;\n\n/** Base options shared by all defineFifoQueue variants */\ntype DefineFifoQueueBase<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = FifoQueueConfig & {\n /**\n * Decode/validate function for the message body.\n * Called with the JSON-parsed body; should return typed data or throw on validation failure.\n */\n schema?: (input: unknown) => T;\n /**\n * Error handler called when onMessage or onBatch throws.\n * If not provided, defaults to `console.error`.\n */\n onError?: (error: unknown) => void;\n /**\n * Factory function to initialize shared state for the handler.\n * Called once on cold start, result is cached and reused across invocations.\n * When deps/params are declared, receives them as argument.\n */\n setup?: SetupFactory<C, D, P, S>;\n /**\n * Dependencies on other handlers (tables, queues, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `files` callback argument.\n */\n static?: S;\n};\n\n/** Per-message processing */\ntype DefineFifoQueueWithOnMessage<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {\n onMessage: FifoQueueMessageFn<T, C, D, P, S>;\n onBatch?: never;\n};\n\n/** Batch processing: all messages at once */\ntype DefineFifoQueueWithOnBatch<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {\n onBatch: FifoQueueBatchFn<T, C, D, P, S>;\n onMessage?: never;\n};\n\nexport type DefineFifoQueueOptions<\n T = unknown,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> =\n | DefineFifoQueueWithOnMessage<T, C, D, P, S>\n | DefineFifoQueueWithOnBatch<T, C, D, P, S>;\n\n/**\n * Internal handler object created by defineFifoQueue\n * @internal\n */\nexport type FifoQueueHandler<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-fifo-queue\";\n readonly __spec: FifoQueueConfig;\n readonly schema?: (input: unknown) => T;\n readonly onError?: (error: unknown) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onMessage?: FifoQueueMessageFn<T, C, D, P, S>;\n readonly onBatch?: FifoQueueBatchFn<T, C, D, P, S>;\n};\n\n/**\n * Define a FIFO SQS queue with a Lambda message handler\n *\n * Creates:\n * - SQS FIFO queue (with `.fifo` suffix)\n * - Lambda function triggered by the queue\n * - Event source mapping with partial batch failure support\n *\n * @example Per-message processing\n * ```typescript\n * type OrderEvent = { orderId: string; action: string };\n *\n * export const orderQueue = defineFifoQueue<OrderEvent>({\n * onMessage: async ({ message }) => {\n * console.log(\"Processing order:\", message.body.orderId);\n * }\n * });\n * ```\n *\n * @example Batch processing with schema\n * ```typescript\n * export const notifications = defineFifoQueue({\n * schema: (input) => NotificationSchema.parse(input),\n * batchSize: 5,\n * onBatch: async ({ messages }) => {\n * await sendAll(messages.map(m => m.body));\n * }\n * });\n * ```\n */\nexport const defineFifoQueue = <\n T = unknown,\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineFifoQueueOptions<T, C, D, P, S>\n): FifoQueueHandler<T, C, D, P, S> => {\n const { onMessage, onBatch, onError, schema, setup, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-fifo-queue\",\n __spec,\n ...(schema ? { schema } : {}),\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n ...(onMessage ? { onMessage } : {}),\n ...(onBatch ? { onBatch } : {})\n } as FifoQueueHandler<T, C, D, P, S>;\n};\n","import type { LambdaWithPermissions, AnyParamRef, ResolveConfig } from \"../helpers\";\nimport type { AnyDepHandler, ResolveDeps, StaticFiles } from \"./shared\";\nimport type { BucketClient } from \"../runtime/bucket-client\";\n\n/**\n * Configuration options for defineBucket.\n */\nexport type BucketConfig = LambdaWithPermissions & {\n /** S3 key prefix filter for event notifications (e.g., \"uploads/\") */\n prefix?: string;\n /** S3 key suffix filter for event notifications (e.g., \".jpg\") */\n suffix?: string;\n};\n\n/**\n * S3 event record passed to onObjectCreated/onObjectRemoved callbacks.\n */\nexport type BucketEvent = {\n /** S3 event name (e.g., \"ObjectCreated:Put\", \"ObjectRemoved:Delete\") */\n eventName: string;\n /** Object key (path within the bucket) */\n key: string;\n /** Object size in bytes (present for created events) */\n size?: number;\n /** Object ETag (present for created events) */\n eTag?: string;\n /** ISO 8601 timestamp of when the event occurred */\n eventTime?: string;\n /** S3 bucket name */\n bucketName: string;\n};\n\n/**\n * Callback function type for S3 ObjectCreated events\n */\nexport type BucketObjectCreatedFn<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { event: BucketEvent; bucket: BucketClient }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<void>;\n\n/**\n * Callback function type for S3 ObjectRemoved events\n */\nexport type BucketObjectRemovedFn<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> =\n (args: { event: BucketEvent; bucket: BucketClient }\n & ([C] extends [undefined] ? {} : { ctx: C })\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => Promise<void>;\n\n/**\n * Setup factory type for bucket handlers.\n * Always receives `bucket: BucketClient` (self-client for the handler's own bucket).\n * Also receives `deps` and/or `config` when declared.\n */\ntype SetupFactory<C, D, P, S extends string[] | undefined = undefined> = (args:\n & { bucket: BucketClient }\n & ([D] extends [undefined] ? {} : { deps: ResolveDeps<D> })\n & ([P] extends [undefined] ? {} : { config: ResolveConfig<P & {}> })\n & ([S] extends [undefined] ? {} : { files: StaticFiles })\n ) => C | Promise<C>;\n\n/** Base options shared by all defineBucket variants */\ntype DefineBucketBase<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = BucketConfig & {\n /**\n * Error handler called when onObjectCreated or onObjectRemoved throws.\n * If not provided, defaults to `console.error`.\n */\n onError?: (error: unknown) => void;\n /**\n * Factory function to initialize shared state for callbacks.\n * Called once on cold start, result is cached and reused across invocations.\n * Always receives `bucket: BucketClient` (self-client). When deps/config\n * are declared, receives them as well.\n */\n setup?: SetupFactory<C, D, P, S>;\n /**\n * Dependencies on other handlers (tables, buckets, etc.).\n * Typed clients are injected into the handler via the `deps` argument.\n */\n deps?: D;\n /**\n * SSM Parameter Store parameters.\n * Declare with `param()` helper. Values are fetched and cached at cold start.\n */\n config?: P;\n /**\n * Static file glob patterns to bundle into the Lambda ZIP.\n * Files are accessible at runtime via the `files` callback argument.\n */\n static?: S;\n};\n\n/** With event handlers (at least one callback) */\ntype DefineBucketWithHandlers<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {\n onObjectCreated?: BucketObjectCreatedFn<C, D, P, S>;\n onObjectRemoved?: BucketObjectRemovedFn<C, D, P, S>;\n};\n\n/** Resource-only: no Lambda, just creates the bucket */\ntype DefineBucketResourceOnly<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {\n onObjectCreated?: never;\n onObjectRemoved?: never;\n};\n\nexport type DefineBucketOptions<\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n> =\n | DefineBucketWithHandlers<C, D, P, S>\n | DefineBucketResourceOnly<C, D, P, S>;\n\n/**\n * Internal handler object created by defineBucket\n * @internal\n */\nexport type BucketHandler<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = {\n readonly __brand: \"effortless-bucket\";\n readonly __spec: BucketConfig;\n readonly onError?: (error: unknown) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly setup?: (...args: any[]) => C | Promise<C>;\n readonly deps?: D;\n readonly config?: P;\n readonly static?: string[];\n readonly onObjectCreated?: BucketObjectCreatedFn<C, D, P, S>;\n readonly onObjectRemoved?: BucketObjectRemovedFn<C, D, P, S>;\n};\n\n/**\n * Define an S3 bucket with optional event handlers.\n *\n * Creates an S3 bucket. When event handlers are provided, also creates a Lambda\n * function triggered by S3 event notifications.\n *\n * @example Bucket with event handler\n * ```typescript\n * export const uploads = defineBucket({\n * prefix: \"images/\",\n * suffix: \".jpg\",\n * onObjectCreated: async ({ event, bucket }) => {\n * const file = await bucket.get(event.key);\n * console.log(\"New upload:\", event.key, file?.body.length);\n * }\n * });\n * ```\n *\n * @example Resource-only bucket (no Lambda)\n * ```typescript\n * export const assets = defineBucket({});\n * ```\n *\n * @example As a dependency\n * ```typescript\n * export const processImage = defineHttp({\n * method: \"POST\",\n * path: \"/process\",\n * deps: { uploads },\n * onRequest: async ({ req, deps }) => {\n * await deps.uploads.put(\"output.jpg\", buffer);\n * return { status: 200, body: \"OK\" };\n * }\n * });\n * ```\n */\nexport const defineBucket = <\n C = undefined,\n D extends Record<string, AnyDepHandler> | undefined = undefined,\n P extends Record<string, AnyParamRef> | undefined = undefined,\n S extends string[] | undefined = undefined\n>(\n options: DefineBucketOptions<C, D, P, S>\n): BucketHandler<C, D, P, S> => {\n const { onObjectCreated, onObjectRemoved, onError, setup, deps, config, static: staticFiles, ...__spec } = options;\n return {\n __brand: \"effortless-bucket\",\n __spec,\n ...(onError ? { onError } : {}),\n ...(setup ? { setup } : {}),\n ...(deps ? { deps } : {}),\n ...(config ? { config } : {}),\n ...(staticFiles ? { static: staticFiles } : {}),\n ...(onObjectCreated ? { onObjectCreated } : {}),\n ...(onObjectRemoved ? { onObjectRemoved } : {}),\n } as BucketHandler<C, D, P, S>;\n};\n","// Public helpers — this file must have ZERO heavy imports (no effect, no AWS SDK, no deploy code).\n// It is the source of truth for param(), typed(), and related types used by the public API.\n\n// ============ Permissions ============\n\ntype AwsService =\n | \"dynamodb\"\n | \"s3\"\n | \"sqs\"\n | \"sns\"\n | \"ses\"\n | \"ssm\"\n | \"lambda\"\n | \"events\"\n | \"secretsmanager\"\n | \"cognito-idp\"\n | \"logs\";\n\nexport type Permission = `${AwsService}:${string}` | (string & {});\n\n// ============ Lambda config ============\n\n/** Logging verbosity level for Lambda handlers */\nexport type LogLevel = \"error\" | \"info\" | \"debug\";\n\n/**\n * Common Lambda configuration shared by all handler types.\n */\nexport type LambdaConfig = {\n /** Lambda memory in MB (default: 256) */\n memory?: number;\n /** Lambda timeout in seconds (default: 30) */\n timeout?: number;\n /** Logging verbosity: \"error\" (errors only), \"info\" (+ execution summary), \"debug\" (+ input/output). Default: \"info\" */\n logLevel?: LogLevel;\n};\n\n/**\n * Lambda configuration with additional IAM permissions.\n * Used by handler types that support custom permissions (http, table, fifo-queue).\n */\nexport type LambdaWithPermissions = LambdaConfig & {\n /** Additional IAM permissions for the Lambda */\n permissions?: Permission[];\n};\n\n// ============ Params ============\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyParamRef = ParamRef<any> | string;\n\n/**\n * Reference to an SSM Parameter Store parameter.\n *\n * @typeParam T - The resolved type after optional transform (default: string)\n */\nexport type ParamRef<T = string> = {\n readonly __brand: \"effortless-param\";\n readonly key: string;\n readonly transform?: (raw: string) => T;\n};\n\n/**\n * Maps a config declaration to resolved value types.\n * Plain strings resolve to `string`, `ParamRef<T>` resolves to `T`.\n *\n * @typeParam P - Record of config keys to string or ParamRef instances\n */\nexport type ResolveConfig<P> = {\n [K in keyof P]: P[K] extends ParamRef<infer T> ? T : string;\n};\n\n/**\n * Declare an SSM Parameter Store parameter.\n *\n * The key is combined with project and stage at deploy time to form the full\n * SSM path: `/${project}/${stage}/${key}`.\n *\n * @param key - Parameter key (e.g., \"database-url\")\n * @param transform - Optional function to transform the raw string value\n * @returns A ParamRef used by the deployment and runtime systems\n *\n * @example Simple string parameter\n * ```typescript\n * config: {\n * dbUrl: param(\"database-url\"),\n * }\n * ```\n *\n * @example With transform (e.g., TOML parsing)\n * ```typescript\n * import TOML from \"smol-toml\";\n *\n * config: {\n * appConfig: param(\"app-config\", TOML.parse),\n * }\n * ```\n */\nexport function param(key: string): ParamRef<string>;\nexport function param<T>(key: string, transform: (raw: string) => T): ParamRef<T>;\nexport function param<T = string>(\n key: string,\n transform?: (raw: string) => T\n): ParamRef<T> {\n return {\n __brand: \"effortless-param\",\n key,\n ...(transform ? { transform } : {}),\n } as ParamRef<T>;\n}\n\n// ============ Single-table types ============\n\n/**\n * DynamoDB table key (always pk + sk strings in single-table design).\n */\nexport type TableKey = { pk: string; sk: string };\n\n/**\n * Full DynamoDB item in the single-table design.\n *\n * Every item has a fixed envelope: `pk`, `sk`, `tag`, `data`, and optional `ttl`.\n * `tag` is stored as a top-level DynamoDB attribute (GSI-ready).\n * If your domain type `T` includes a `tag` field, effortless auto-copies\n * `data.tag` to the top-level `tag` on `put()`, so you don't have to pass it twice.\n *\n * @typeParam T - The domain data type stored in the `data` attribute\n */\nexport type TableItem<T> = {\n pk: string;\n sk: string;\n tag: string;\n data: T;\n ttl?: number;\n};\n\n/**\n * Input type for `TableClient.put()`.\n *\n * Unlike `TableItem<T>`, this does NOT include `tag` — effortless auto-extracts\n * the top-level DynamoDB `tag` attribute from your data using the configured\n * tag field (defaults to `data.tag`, configurable via `defineTable({ tag: \"type\" })`).\n *\n * @typeParam T - The domain data type stored in the `data` attribute\n */\nexport type PutInput<T> = {\n pk: string;\n sk: string;\n data: T;\n ttl?: number;\n};\n\n// ============ Typed helper ============\n\n/**\n * Type-only schema helper for handlers.\n *\n * Use this instead of explicit generic parameters like `defineTable<Order>(...)`.\n * It enables TypeScript to infer all generic types from the options object,\n * avoiding the partial-inference problem where specifying one generic\n * forces all others to their defaults.\n *\n * At runtime this is a no-op identity function — it simply returns the input unchanged.\n * The type narrowing happens entirely at the TypeScript level.\n *\n * @example Resource-only table\n * ```typescript\n * type User = { id: string; email: string };\n *\n * export const users = defineTable({\n * schema: typed<User>(),\n * });\n * ```\n *\n * @example Table with stream handler\n * ```typescript\n * export const orders = defineTable({\n * schema: typed<Order>(),\n * setup: async () => ({ db: createClient() }),\n * onRecord: async ({ record, ctx }) => {\n * // record.new.data is Order, ctx is { db: Client } — all inferred\n * },\n * });\n * ```\n */\nexport function typed<T>(): (input: unknown) => T {\n return (input: unknown) => input as T;\n}\n"],"mappings":";AA+FO,IAAM,eAAe,CAAC,WAA+C;;;ACkHrE,IAAM,aAAa,CAOxB,YAC+B;AAC/B,QAAM,EAAE,WAAW,SAAS,OAAO,QAAQ,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AAC5F,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;;;ACSO,IAAM,cAAc,CAQzB,YACmC;AACnC,QAAM,EAAE,UAAU,iBAAiB,SAAS,SAAS,QAAQ,OAAO,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AACrH,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IAC/B,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7C,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/B;AACF;;;AC3NO,IAAM,YAAY,CAAC,aAAoC;AAAA,EAC5D,SAAS;AAAA,EACT,QAAQ;AACV;;;AC8CO,IAAM,mBAAmB,CAAC,aAAkD;AAAA,EACjF,SAAS;AAAA,EACT,QAAQ;AACV;;;AC2FO,IAAM,kBAAkB,CAO7B,YACoC;AACpC,QAAM,EAAE,WAAW,SAAS,SAAS,QAAQ,OAAO,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AACrG,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IACjC,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/B;AACF;;;ACtCO,IAAM,eAAe,CAM1B,YAC8B;AAC9B,QAAM,EAAE,iBAAiB,iBAAiB,SAAS,OAAO,MAAM,QAAQ,QAAQ,aAAa,GAAG,OAAO,IAAI;AAC3G,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC7C,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7C,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,EAC/C;AACF;;;AC3FO,SAAS,MACd,KACA,WACa;AACb,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,EACnC;AACF;AA4EO,SAAS,QAAkC;AAChD,SAAO,CAAC,UAAmB;AAC7B;","names":[]}
|
package/dist/runtime/wrap-app.js
CHANGED