effortless-aws 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +422 -439
- package/dist/index.js +275 -83
- package/dist/index.js.map +1 -1
- package/dist/runtime/wrap-api.js +8 -6
- package/dist/runtime/wrap-bucket.js +3 -3
- package/dist/runtime/wrap-fifo-queue.js +3 -3
- package/dist/runtime/wrap-table-stream.js +3 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -253,111 +253,6 @@ type PutInput<T> = {
|
|
|
253
253
|
*/
|
|
254
254
|
declare function unsafeAs<T>(): (input: unknown) => T;
|
|
255
255
|
|
|
256
|
-
/**
|
|
257
|
-
* Sort key condition for TableClient.query()
|
|
258
|
-
*/
|
|
259
|
-
type SkCondition = string | {
|
|
260
|
-
begins_with: string;
|
|
261
|
-
} | {
|
|
262
|
-
gt: string;
|
|
263
|
-
} | {
|
|
264
|
-
gte: string;
|
|
265
|
-
} | {
|
|
266
|
-
lt: string;
|
|
267
|
-
} | {
|
|
268
|
-
lte: string;
|
|
269
|
-
} | {
|
|
270
|
-
between: [string, string];
|
|
271
|
-
};
|
|
272
|
-
/**
|
|
273
|
-
* Query parameters for TableClient.query()
|
|
274
|
-
*/
|
|
275
|
-
type QueryParams = {
|
|
276
|
-
/** Partition key value */
|
|
277
|
-
pk: string;
|
|
278
|
-
/** Optional sort key condition */
|
|
279
|
-
sk?: SkCondition;
|
|
280
|
-
/** Maximum number of items to return */
|
|
281
|
-
limit?: number;
|
|
282
|
-
/** Sort order (true = ascending, false = descending) */
|
|
283
|
-
scanIndexForward?: boolean;
|
|
284
|
-
};
|
|
285
|
-
/**
|
|
286
|
-
* Query parameters for TableClient.queryByTag() — cross-partition query via GSI.
|
|
287
|
-
* Uses the built-in `tag-pk-index` GSI (tag as partition key, pk as sort key).
|
|
288
|
-
*/
|
|
289
|
-
type QueryByTagParams = {
|
|
290
|
-
/** Tag value (GSI partition key) — the entity type discriminant */
|
|
291
|
-
tag: string;
|
|
292
|
-
/** Optional pk condition (GSI sort key) */
|
|
293
|
-
pk?: SkCondition;
|
|
294
|
-
/** Maximum number of items to return */
|
|
295
|
-
limit?: number;
|
|
296
|
-
/** Sort order (true = ascending, false = descending) */
|
|
297
|
-
scanIndexForward?: boolean;
|
|
298
|
-
};
|
|
299
|
-
/** Extract keys of T whose values are arrays */
|
|
300
|
-
type ArrayKeys<T> = {
|
|
301
|
-
[K in keyof T]: T[K] extends unknown[] ? K : never;
|
|
302
|
-
}[keyof T];
|
|
303
|
-
/** Extract keys of T whose values are numbers */
|
|
304
|
-
type NumberKeys<T> = {
|
|
305
|
-
[K in keyof T]: T[K] extends number ? K : never;
|
|
306
|
-
}[keyof T];
|
|
307
|
-
/**
|
|
308
|
-
* Update actions for TableClient.update()
|
|
309
|
-
*
|
|
310
|
-
* `set`, `append`, and `remove` target fields inside the `data` attribute.
|
|
311
|
-
* Effortless auto-prefixes `data.` in the DynamoDB expression.
|
|
312
|
-
*
|
|
313
|
-
* @typeParam T - Type of the domain data (the `data` attribute)
|
|
314
|
-
*/
|
|
315
|
-
type UpdateActions<T> = {
|
|
316
|
-
/** Set domain data fields (inside `data` attribute) */
|
|
317
|
-
set?: Partial<T>;
|
|
318
|
-
/** Atomically increment/decrement numeric fields inside `data` (use negative values to decrement) */
|
|
319
|
-
increment?: Pick<Partial<T>, NumberKeys<T>>;
|
|
320
|
-
/** Append elements to list fields inside `data` (creates the list if it doesn't exist) */
|
|
321
|
-
append?: Pick<Partial<T>, ArrayKeys<T>>;
|
|
322
|
-
/** Remove fields from `data` */
|
|
323
|
-
remove?: (keyof T)[];
|
|
324
|
-
/** Update the top-level `tag` attribute */
|
|
325
|
-
tag?: string;
|
|
326
|
-
/** Update TTL (set number or null to remove) */
|
|
327
|
-
ttl?: number | null;
|
|
328
|
-
};
|
|
329
|
-
/**
|
|
330
|
-
* Typed DynamoDB table client for single-table design.
|
|
331
|
-
*
|
|
332
|
-
* All items follow the `{ pk, sk, tag, data, ttl? }` structure.
|
|
333
|
-
* `T` is the domain data type stored in the `data` attribute.
|
|
334
|
-
*
|
|
335
|
-
* @typeParam T - Type of the domain data
|
|
336
|
-
*/
|
|
337
|
-
/**
|
|
338
|
-
* Options for `put()` operation.
|
|
339
|
-
*/
|
|
340
|
-
type PutOptions = {
|
|
341
|
-
/** When true, the put fails if an item with the same pk+sk already exists. */
|
|
342
|
-
ifNotExists?: boolean;
|
|
343
|
-
};
|
|
344
|
-
type TableClient<T = Record<string, unknown>> = {
|
|
345
|
-
/** Put an item. Tag is auto-extracted from `data[tagField]`. Use `ifNotExists` to prevent overwrites. */
|
|
346
|
-
put(item: PutInput<T>, options?: PutOptions): Promise<void>;
|
|
347
|
-
/** Get an item by pk + sk */
|
|
348
|
-
get(key: TableKey): Promise<TableItem<T> | undefined>;
|
|
349
|
-
/** Delete an item by pk + sk */
|
|
350
|
-
delete(key: TableKey): Promise<void>;
|
|
351
|
-
/** Update domain data fields without reading the full item */
|
|
352
|
-
update(key: TableKey, actions: UpdateActions<T>): Promise<void>;
|
|
353
|
-
/** Query by partition key with optional sort key condition */
|
|
354
|
-
query(params: QueryParams): Promise<TableItem<T>[]>;
|
|
355
|
-
/** Query by tag across all partitions via GSI (tag-pk-index). */
|
|
356
|
-
queryByTag(params: QueryByTagParams): Promise<TableItem<T>[]>;
|
|
357
|
-
/** The underlying DynamoDB table name */
|
|
358
|
-
tableName: string;
|
|
359
|
-
};
|
|
360
|
-
|
|
361
256
|
/** HTTP methods supported by Lambda Function URLs */
|
|
362
257
|
type HttpMethod$1 = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "ANY";
|
|
363
258
|
/** Short content-type aliases for common response formats */
|
|
@@ -411,13 +306,6 @@ type HttpResponse = {
|
|
|
411
306
|
*/
|
|
412
307
|
binary?: boolean;
|
|
413
308
|
};
|
|
414
|
-
/** Response helpers for defineApi handlers */
|
|
415
|
-
declare const result: {
|
|
416
|
-
/** Return a JSON response */
|
|
417
|
-
json: (body: unknown, status?: number) => HttpResponse;
|
|
418
|
-
/** Return a binary response. Accepts a Buffer and converts to base64 automatically. */
|
|
419
|
-
binary: (body: Buffer, contentType: string, headers?: Record<string, string>) => HttpResponse;
|
|
420
|
-
};
|
|
421
309
|
/** Stream helper injected into route args when `stream: true` is set on defineApi */
|
|
422
310
|
type ResponseStream = {
|
|
423
311
|
/** Write a raw string chunk to the response stream */
|
|
@@ -470,7 +358,12 @@ type BucketClient = {
|
|
|
470
358
|
*/
|
|
471
359
|
type BucketConfig = {
|
|
472
360
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
473
|
-
lambda?:
|
|
361
|
+
lambda?: {
|
|
362
|
+
memory?: number;
|
|
363
|
+
timeout?: Duration;
|
|
364
|
+
logLevel?: LogLevel;
|
|
365
|
+
permissions?: Permission[];
|
|
366
|
+
};
|
|
474
367
|
/** S3 key prefix filter for event notifications (e.g., "uploads/") */
|
|
475
368
|
prefix?: string;
|
|
476
369
|
/** S3 key suffix filter for event notifications (e.g., ".jpg") */
|
|
@@ -495,6 +388,16 @@ type BucketEvent = {
|
|
|
495
388
|
};
|
|
496
389
|
/** Spread ctx into callback args (empty when no setup) */
|
|
497
390
|
type SpreadCtx$3<C> = [C] extends [undefined] ? {} : C & {};
|
|
391
|
+
/** Setup factory — receives bucket/deps/config/files based on what was declared */
|
|
392
|
+
type SetupArgs$3<D, P, HasFiles extends boolean> = {
|
|
393
|
+
bucket: BucketClient;
|
|
394
|
+
} & ([D] extends [undefined] ? {} : {
|
|
395
|
+
deps: ResolveDeps<D>;
|
|
396
|
+
}) & ([P] extends [undefined] ? {} : {
|
|
397
|
+
config: ResolveConfig<P & {}>;
|
|
398
|
+
}) & (HasFiles extends true ? {
|
|
399
|
+
files: StaticFiles;
|
|
400
|
+
} : {});
|
|
498
401
|
/**
|
|
499
402
|
* Callback function type for S3 ObjectCreated events
|
|
500
403
|
*/
|
|
@@ -507,66 +410,6 @@ type BucketObjectCreatedFn<C = undefined> = (args: {
|
|
|
507
410
|
type BucketObjectRemovedFn<C = undefined> = (args: {
|
|
508
411
|
event: BucketEvent;
|
|
509
412
|
} & SpreadCtx$3<C>) => Promise<void>;
|
|
510
|
-
/**
|
|
511
|
-
* Setup factory type for bucket handlers.
|
|
512
|
-
* Always receives `bucket: BucketClient` (self-client for the handler's own bucket).
|
|
513
|
-
* Also receives `deps` and/or `config` when declared.
|
|
514
|
-
*/
|
|
515
|
-
type SetupFactory$3<C, D, P, S extends string[] | undefined = undefined> = (args: {
|
|
516
|
-
bucket: BucketClient;
|
|
517
|
-
} & ([D] extends [undefined] ? {} : {
|
|
518
|
-
deps: ResolveDeps<D>;
|
|
519
|
-
}) & ([P] extends [undefined] ? {} : {
|
|
520
|
-
config: ResolveConfig<P & {}>;
|
|
521
|
-
}) & ([S] extends [undefined] ? {} : {
|
|
522
|
-
files: StaticFiles;
|
|
523
|
-
})) => C | Promise<C>;
|
|
524
|
-
/** Base options shared by all defineBucket variants */
|
|
525
|
-
type DefineBucketBase<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = BucketConfig & {
|
|
526
|
-
/**
|
|
527
|
-
* Error handler called when onObjectCreated or onObjectRemoved throws.
|
|
528
|
-
* If not provided, defaults to `console.error`.
|
|
529
|
-
*/
|
|
530
|
-
onError?: (args: {
|
|
531
|
-
error: unknown;
|
|
532
|
-
} & SpreadCtx$3<C>) => void;
|
|
533
|
-
/** Called after each invocation completes, right before Lambda freezes the process */
|
|
534
|
-
onAfterInvoke?: (args: SpreadCtx$3<C>) => void | Promise<void>;
|
|
535
|
-
/**
|
|
536
|
-
* Factory function to initialize shared state for callbacks.
|
|
537
|
-
* Called once on cold start, result is cached and reused across invocations.
|
|
538
|
-
* Always receives `bucket: BucketClient` (self-client). When deps/config
|
|
539
|
-
* are declared, receives them as well.
|
|
540
|
-
*/
|
|
541
|
-
setup?: SetupFactory$3<C, NoInfer<D>, NoInfer<P>, NoInfer<S>>;
|
|
542
|
-
/**
|
|
543
|
-
* Dependencies on other handlers (tables, buckets, etc.).
|
|
544
|
-
* Typed clients are injected into the handler via the `deps` argument.
|
|
545
|
-
* Pass a function returning the deps object: `deps: () => ({ uploads })`.
|
|
546
|
-
*/
|
|
547
|
-
deps?: () => D & {};
|
|
548
|
-
/**
|
|
549
|
-
* SSM Parameter Store parameters.
|
|
550
|
-
* Declare with `defineSecret()` helper. Values are fetched and cached at cold start.
|
|
551
|
-
*/
|
|
552
|
-
config?: ConfigFactory<P>;
|
|
553
|
-
/**
|
|
554
|
-
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
555
|
-
* Files are accessible at runtime via the `files` callback argument.
|
|
556
|
-
*/
|
|
557
|
-
static?: S;
|
|
558
|
-
};
|
|
559
|
-
/** With event handlers (at least one callback) */
|
|
560
|
-
type DefineBucketWithHandlers<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {
|
|
561
|
-
onObjectCreated?: BucketObjectCreatedFn<C>;
|
|
562
|
-
onObjectRemoved?: BucketObjectRemovedFn<C>;
|
|
563
|
-
};
|
|
564
|
-
/** Resource-only: no Lambda, just creates the bucket */
|
|
565
|
-
type DefineBucketResourceOnly<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {
|
|
566
|
-
onObjectCreated?: never;
|
|
567
|
-
onObjectRemoved?: never;
|
|
568
|
-
};
|
|
569
|
-
type DefineBucketOptions<C = undefined, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnySecretRef> | undefined = undefined, S extends string[] | undefined = undefined> = DefineBucketWithHandlers<C, D, P, S> | DefineBucketResourceOnly<C, D, P, S>;
|
|
570
413
|
/**
|
|
571
414
|
* Internal handler object created by defineBucket
|
|
572
415
|
* @internal
|
|
@@ -575,7 +418,7 @@ type BucketHandler<C = any> = {
|
|
|
575
418
|
readonly __brand: "effortless-bucket";
|
|
576
419
|
readonly __spec: BucketConfig;
|
|
577
420
|
readonly onError?: (...args: any[]) => any;
|
|
578
|
-
readonly
|
|
421
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
579
422
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
580
423
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
581
424
|
readonly config?: Record<string, unknown>;
|
|
@@ -583,42 +426,65 @@ type BucketHandler<C = any> = {
|
|
|
583
426
|
readonly onObjectCreated?: (...args: any[]) => any;
|
|
584
427
|
readonly onObjectRemoved?: (...args: any[]) => any;
|
|
585
428
|
};
|
|
429
|
+
/** Options passed to `defineBucket()` — static config */
|
|
430
|
+
type BucketOptions = {
|
|
431
|
+
/** Lambda memory in MB (default: 256) */
|
|
432
|
+
memory?: number;
|
|
433
|
+
/** Lambda timeout (default: 30s) */
|
|
434
|
+
timeout?: Duration;
|
|
435
|
+
/** Additional IAM permissions for the Lambda */
|
|
436
|
+
permissions?: Permission[];
|
|
437
|
+
/** Logging verbosity */
|
|
438
|
+
logLevel?: LogLevel;
|
|
439
|
+
/** S3 key prefix filter for event notifications (e.g., "uploads/") */
|
|
440
|
+
prefix?: string;
|
|
441
|
+
/** S3 key suffix filter for event notifications (e.g., ".jpg") */
|
|
442
|
+
suffix?: string;
|
|
443
|
+
/** Static file glob patterns to bundle into the Lambda ZIP */
|
|
444
|
+
static?: string[];
|
|
445
|
+
};
|
|
446
|
+
interface BucketBuilder<D = undefined, P = undefined, C = undefined, HasFiles extends boolean = false> {
|
|
447
|
+
/** Declare handler dependencies */
|
|
448
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): BucketBuilder<D2, P, C, HasFiles>;
|
|
449
|
+
/** Declare SSM secrets */
|
|
450
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): BucketBuilder<D, P2, C, HasFiles>;
|
|
451
|
+
/** Initialize shared state on cold start. Receives bucket (self-client), deps, config, files. */
|
|
452
|
+
setup<C2>(fn: (args: SetupArgs$3<D, P, HasFiles>) => C2 | Promise<C2>): BucketBuilder<D, P, C2, HasFiles>;
|
|
453
|
+
/** Handle errors thrown by callbacks */
|
|
454
|
+
onError(fn: (args: {
|
|
455
|
+
error: unknown;
|
|
456
|
+
} & SpreadCtx$3<C>) => void): BucketBuilder<D, P, C, HasFiles>;
|
|
457
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
458
|
+
onCleanup(fn: (args: SpreadCtx$3<C>) => void | Promise<void>): BucketBuilder<D, P, C, HasFiles>;
|
|
459
|
+
/** Handle S3 ObjectCreated events (terminal — returns finalized handler) */
|
|
460
|
+
onObjectCreated(fn: BucketObjectCreatedFn<C>): BucketHandler<C>;
|
|
461
|
+
/** Handle S3 ObjectRemoved events (terminal — returns finalized handler) */
|
|
462
|
+
onObjectRemoved(fn: BucketObjectRemovedFn<C>): BucketHandler<C>;
|
|
463
|
+
/** Finalize as resource-only bucket (no Lambda) */
|
|
464
|
+
build(): BucketHandler<C>;
|
|
465
|
+
}
|
|
586
466
|
/**
|
|
587
467
|
* Define an S3 bucket with optional event handlers.
|
|
588
468
|
*
|
|
589
|
-
* Creates an S3 bucket. When event handlers are provided, also creates a Lambda
|
|
590
|
-
* function triggered by S3 event notifications.
|
|
591
|
-
*
|
|
592
469
|
* @example Bucket with event handler
|
|
593
470
|
* ```typescript
|
|
594
|
-
* export const uploads = defineBucket({
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
* const file = await bucket.get(event.key);
|
|
599
|
-
* console.log("New upload:", event.key, file?.body.length);
|
|
600
|
-
* }
|
|
601
|
-
* });
|
|
602
|
-
* ```
|
|
471
|
+
* export const uploads = defineBucket({ prefix: "images/", suffix: ".jpg" })
|
|
472
|
+
* .onObjectCreated(async ({ event, bucket }) => {
|
|
473
|
+
* console.log("New upload:", event.key);
|
|
474
|
+
* })
|
|
603
475
|
*
|
|
604
|
-
* @example Resource-only bucket (no Lambda)
|
|
605
|
-
* ```typescript
|
|
606
|
-
* export const assets = defineBucket({});
|
|
607
476
|
* ```
|
|
608
477
|
*
|
|
609
|
-
* @example
|
|
478
|
+
* @example Resource-only bucket (no Lambda)
|
|
610
479
|
* ```typescript
|
|
611
|
-
* export const
|
|
612
|
-
* basePath: "/process",
|
|
613
|
-
* deps: { uploads },
|
|
614
|
-
* post: async ({ req, deps }) => {
|
|
615
|
-
* await deps.uploads.put("output.jpg", buffer);
|
|
616
|
-
* return { status: 200, body: "OK" };
|
|
617
|
-
* },
|
|
618
|
-
* });
|
|
480
|
+
* export const assets = defineBucket().build()
|
|
619
481
|
* ```
|
|
620
482
|
*/
|
|
621
|
-
declare
|
|
483
|
+
declare function defineBucket(): BucketBuilder;
|
|
484
|
+
declare function defineBucket(options: BucketOptions & {
|
|
485
|
+
static: string[];
|
|
486
|
+
}): BucketBuilder<undefined, undefined, undefined, true>;
|
|
487
|
+
declare function defineBucket(options: BucketOptions): BucketBuilder;
|
|
622
488
|
|
|
623
489
|
/**
|
|
624
490
|
* Configuration options for defining a mailer (SES email identity)
|
|
@@ -703,7 +569,12 @@ type FifoQueueMessage<T = unknown> = {
|
|
|
703
569
|
*/
|
|
704
570
|
type FifoQueueConfig = {
|
|
705
571
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
706
|
-
lambda?:
|
|
572
|
+
lambda?: {
|
|
573
|
+
memory?: number;
|
|
574
|
+
timeout?: Duration;
|
|
575
|
+
logLevel?: LogLevel;
|
|
576
|
+
permissions?: Permission[];
|
|
577
|
+
};
|
|
707
578
|
/** Number of messages per Lambda invocation (1-10 for FIFO, default: 10) */
|
|
708
579
|
batchSize?: number;
|
|
709
580
|
/** Maximum time to gather messages before invoking (default: 0). Accepts `"5s"`, `"1m"`, etc. */
|
|
@@ -719,19 +590,16 @@ type FifoQueueConfig = {
|
|
|
719
590
|
/** Max number of receives before a message is sent to the dead-letter queue (default: 3) */
|
|
720
591
|
maxReceiveCount?: number;
|
|
721
592
|
};
|
|
722
|
-
/**
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
type SetupFactory$2<C, D, P, S extends string[] | undefined = undefined> = (args: ([D] extends [undefined] ? {} : {
|
|
593
|
+
/** Spread ctx into callback args (empty when no setup) */
|
|
594
|
+
type SpreadCtx$2<C> = [C] extends [undefined] ? {} : C & {};
|
|
595
|
+
/** Setup factory — receives deps/config/files based on what was declared */
|
|
596
|
+
type SetupArgs$2<D, P, HasFiles extends boolean> = ([D] extends [undefined] ? {} : {
|
|
727
597
|
deps: ResolveDeps<D>;
|
|
728
598
|
}) & ([P] extends [undefined] ? {} : {
|
|
729
599
|
config: ResolveConfig<P & {}>;
|
|
730
|
-
}) & (
|
|
600
|
+
}) & (HasFiles extends true ? {
|
|
731
601
|
files: StaticFiles;
|
|
732
|
-
}
|
|
733
|
-
/** Spread ctx into callback args (empty when no setup) */
|
|
734
|
-
type SpreadCtx$2<C> = [C] extends [undefined] ? {} : C & {};
|
|
602
|
+
} : {});
|
|
735
603
|
/**
|
|
736
604
|
* Per-message handler function.
|
|
737
605
|
* Called once per message in the batch. Failures are reported individually.
|
|
@@ -749,56 +617,6 @@ type FifoQueueBatchFn<T = unknown, C = undefined> = (args: {
|
|
|
749
617
|
} & SpreadCtx$2<C>) => Promise<void | {
|
|
750
618
|
failures: string[];
|
|
751
619
|
}>;
|
|
752
|
-
/** Base options shared by all defineFifoQueue variants */
|
|
753
|
-
type DefineFifoQueueBase<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = FifoQueueConfig & {
|
|
754
|
-
/**
|
|
755
|
-
* Decode/validate function for the message body.
|
|
756
|
-
* Called with the JSON-parsed body; should return typed data or throw on validation failure.
|
|
757
|
-
*/
|
|
758
|
-
schema?: (input: unknown) => T;
|
|
759
|
-
/**
|
|
760
|
-
* Error handler called when onMessage or onMessageBatch throws.
|
|
761
|
-
* If not provided, defaults to `console.error`.
|
|
762
|
-
*/
|
|
763
|
-
onError?: (args: {
|
|
764
|
-
error: unknown;
|
|
765
|
-
} & SpreadCtx$2<C>) => void;
|
|
766
|
-
/** Called after each invocation completes, right before Lambda freezes the process */
|
|
767
|
-
onAfterInvoke?: (args: SpreadCtx$2<C>) => void | Promise<void>;
|
|
768
|
-
/**
|
|
769
|
-
* Factory function to initialize shared state for the handler.
|
|
770
|
-
* Called once on cold start, result is cached and reused across invocations.
|
|
771
|
-
* When deps/params are declared, receives them as argument.
|
|
772
|
-
*/
|
|
773
|
-
setup?: SetupFactory$2<C, NoInfer<D>, NoInfer<P>, NoInfer<S>>;
|
|
774
|
-
/**
|
|
775
|
-
* Dependencies on other handlers (tables, queues, etc.).
|
|
776
|
-
* Typed clients are injected into the handler via the `deps` argument.
|
|
777
|
-
* Pass a function returning the deps object: `deps: () => ({ orders })`.
|
|
778
|
-
*/
|
|
779
|
-
deps?: () => D & {};
|
|
780
|
-
/**
|
|
781
|
-
* SSM Parameter Store parameters.
|
|
782
|
-
* Declare with `defineSecret()` helper. Values are fetched and cached at cold start.
|
|
783
|
-
*/
|
|
784
|
-
config?: ConfigFactory<P>;
|
|
785
|
-
/**
|
|
786
|
-
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
787
|
-
* Files are accessible at runtime via the `files` callback argument.
|
|
788
|
-
*/
|
|
789
|
-
static?: S;
|
|
790
|
-
};
|
|
791
|
-
/** Per-message processing */
|
|
792
|
-
type DefineFifoQueueWithOnMessage<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {
|
|
793
|
-
onMessage: FifoQueueMessageFn<T, C>;
|
|
794
|
-
onMessageBatch?: never;
|
|
795
|
-
};
|
|
796
|
-
/** Batch processing: all messages at once */
|
|
797
|
-
type DefineFifoQueueWithOnBatch<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {
|
|
798
|
-
onMessageBatch: FifoQueueBatchFn<T, C>;
|
|
799
|
-
onMessage?: never;
|
|
800
|
-
};
|
|
801
|
-
type DefineFifoQueueOptions<T = unknown, C = undefined, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnySecretRef> | undefined = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueWithOnMessage<T, C, D, P, S> | DefineFifoQueueWithOnBatch<T, C, D, P, S>;
|
|
802
620
|
/**
|
|
803
621
|
* Internal handler object created by defineFifoQueue
|
|
804
622
|
* @internal
|
|
@@ -808,7 +626,7 @@ type FifoQueueHandler<T = unknown, C = any> = {
|
|
|
808
626
|
readonly __spec: FifoQueueConfig;
|
|
809
627
|
readonly schema?: (input: unknown) => T;
|
|
810
628
|
readonly onError?: (...args: any[]) => any;
|
|
811
|
-
readonly
|
|
629
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
812
630
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
813
631
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
814
632
|
readonly config?: Record<string, unknown>;
|
|
@@ -816,37 +634,184 @@ type FifoQueueHandler<T = unknown, C = any> = {
|
|
|
816
634
|
readonly onMessage?: (...args: any[]) => any;
|
|
817
635
|
readonly onMessageBatch?: (...args: any[]) => any;
|
|
818
636
|
};
|
|
637
|
+
/** Options passed to `defineFifoQueue()` — static config */
|
|
638
|
+
type FifoQueueOptions<T> = {
|
|
639
|
+
/** Lambda memory in MB (default: 256) */
|
|
640
|
+
memory?: number;
|
|
641
|
+
/** Lambda timeout (default: 30s) */
|
|
642
|
+
timeout?: Duration;
|
|
643
|
+
/** Additional IAM permissions for the Lambda */
|
|
644
|
+
permissions?: Permission[];
|
|
645
|
+
/** Logging verbosity */
|
|
646
|
+
logLevel?: LogLevel;
|
|
647
|
+
/** Number of messages per Lambda invocation (1-10 for FIFO, default: 10) */
|
|
648
|
+
batchSize?: number;
|
|
649
|
+
/** Maximum time to gather messages before invoking (default: 0) */
|
|
650
|
+
batchWindow?: Duration;
|
|
651
|
+
/** Visibility timeout (default: max of timeout or 30s) */
|
|
652
|
+
visibilityTimeout?: Duration;
|
|
653
|
+
/** Message retention period (default: "4d") */
|
|
654
|
+
retentionPeriod?: Duration;
|
|
655
|
+
/** Delivery delay for all messages in the queue (default: 0) */
|
|
656
|
+
delay?: Duration;
|
|
657
|
+
/** Enable content-based deduplication (default: true) */
|
|
658
|
+
contentBasedDeduplication?: boolean;
|
|
659
|
+
/** Max number of receives before DLQ (default: 3) */
|
|
660
|
+
maxReceiveCount?: number;
|
|
661
|
+
/** Decode/validate function for the message body */
|
|
662
|
+
schema?: (input: unknown) => T;
|
|
663
|
+
/** Static file glob patterns to bundle into the Lambda ZIP */
|
|
664
|
+
static?: string[];
|
|
665
|
+
};
|
|
666
|
+
interface FifoQueueBuilder<T = unknown, D = undefined, P = undefined, C = undefined, HasFiles extends boolean = false> {
|
|
667
|
+
/** Declare handler dependencies */
|
|
668
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): FifoQueueBuilder<T, D2, P, C, HasFiles>;
|
|
669
|
+
/** Declare SSM secrets */
|
|
670
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): FifoQueueBuilder<T, D, P2, C, HasFiles>;
|
|
671
|
+
/** Initialize shared state on cold start. Receives deps, config, files. */
|
|
672
|
+
setup<C2>(fn: (args: SetupArgs$2<D, P, HasFiles>) => C2 | Promise<C2>): FifoQueueBuilder<T, D, P, C2, HasFiles>;
|
|
673
|
+
/** Handle errors thrown by message handlers */
|
|
674
|
+
onError(fn: (args: {
|
|
675
|
+
error: unknown;
|
|
676
|
+
} & SpreadCtx$2<C>) => void): FifoQueueBuilder<T, D, P, C, HasFiles>;
|
|
677
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
678
|
+
onCleanup(fn: (args: SpreadCtx$2<C>) => void | Promise<void>): FifoQueueBuilder<T, D, P, C, HasFiles>;
|
|
679
|
+
/** Per-message handler (terminal — returns finalized handler) */
|
|
680
|
+
onMessage(fn: FifoQueueMessageFn<T, C>): FifoQueueHandler<T, C>;
|
|
681
|
+
/** Batch handler (terminal — returns finalized handler) */
|
|
682
|
+
onMessageBatch(fn: FifoQueueBatchFn<T, C>): FifoQueueHandler<T, C>;
|
|
683
|
+
}
|
|
819
684
|
/**
|
|
820
|
-
* Define a FIFO SQS queue with a Lambda message handler
|
|
821
|
-
*
|
|
822
|
-
* Creates:
|
|
823
|
-
* - SQS FIFO queue (with `.fifo` suffix)
|
|
824
|
-
* - Lambda function triggered by the queue
|
|
825
|
-
* - Event source mapping with partial batch failure support
|
|
685
|
+
* Define a FIFO SQS queue with a Lambda message handler.
|
|
826
686
|
*
|
|
827
687
|
* @example Per-message processing
|
|
828
688
|
* ```typescript
|
|
829
|
-
*
|
|
830
|
-
*
|
|
831
|
-
* export const orderQueue = defineFifoQueue<OrderEvent>({
|
|
832
|
-
* onMessage: async ({ message }) => {
|
|
689
|
+
* export const orderQueue = defineFifoQueue<OrderEvent>()
|
|
690
|
+
* .onMessage(async ({ message }) => {
|
|
833
691
|
* console.log("Processing order:", message.body.orderId);
|
|
834
|
-
* }
|
|
835
|
-
*
|
|
692
|
+
* })
|
|
693
|
+
*
|
|
836
694
|
* ```
|
|
837
695
|
*
|
|
838
696
|
* @example Batch processing with schema
|
|
839
697
|
* ```typescript
|
|
840
|
-
* export const notifications = defineFifoQueue({
|
|
841
|
-
*
|
|
842
|
-
* batchSize: 5,
|
|
843
|
-
* onMessageBatch: async ({ messages }) => {
|
|
698
|
+
* export const notifications = defineFifoQueue({ batchSize: 5, schema: (i) => NotifSchema.parse(i) })
|
|
699
|
+
* .onMessageBatch(async ({ messages }) => {
|
|
844
700
|
* await sendAll(messages.map(m => m.body));
|
|
845
|
-
* }
|
|
846
|
-
*
|
|
701
|
+
* })
|
|
702
|
+
*
|
|
847
703
|
* ```
|
|
848
704
|
*/
|
|
849
|
-
declare
|
|
705
|
+
declare function defineFifoQueue<T = unknown>(): FifoQueueBuilder<T>;
|
|
706
|
+
declare function defineFifoQueue<T = unknown>(options: FifoQueueOptions<T> & {
|
|
707
|
+
static: string[];
|
|
708
|
+
}): FifoQueueBuilder<T, undefined, undefined, undefined, true>;
|
|
709
|
+
declare function defineFifoQueue<T = unknown>(options: FifoQueueOptions<T>): FifoQueueBuilder<T>;
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Sort key condition for TableClient.query()
|
|
713
|
+
*/
|
|
714
|
+
type SkCondition = string | {
|
|
715
|
+
begins_with: string;
|
|
716
|
+
} | {
|
|
717
|
+
gt: string;
|
|
718
|
+
} | {
|
|
719
|
+
gte: string;
|
|
720
|
+
} | {
|
|
721
|
+
lt: string;
|
|
722
|
+
} | {
|
|
723
|
+
lte: string;
|
|
724
|
+
} | {
|
|
725
|
+
between: [string, string];
|
|
726
|
+
};
|
|
727
|
+
/**
|
|
728
|
+
* Query parameters for TableClient.query()
|
|
729
|
+
*/
|
|
730
|
+
type QueryParams = {
|
|
731
|
+
/** Partition key value */
|
|
732
|
+
pk: string;
|
|
733
|
+
/** Optional sort key condition */
|
|
734
|
+
sk?: SkCondition;
|
|
735
|
+
/** Maximum number of items to return */
|
|
736
|
+
limit?: number;
|
|
737
|
+
/** Sort order (true = ascending, false = descending) */
|
|
738
|
+
scanIndexForward?: boolean;
|
|
739
|
+
};
|
|
740
|
+
/**
|
|
741
|
+
* Query parameters for TableClient.queryByTag() — cross-partition query via GSI.
|
|
742
|
+
* Uses the built-in `tag-pk-index` GSI (tag as partition key, pk as sort key).
|
|
743
|
+
*/
|
|
744
|
+
type QueryByTagParams = {
|
|
745
|
+
/** Tag value (GSI partition key) — the entity type discriminant */
|
|
746
|
+
tag: string;
|
|
747
|
+
/** Optional pk condition (GSI sort key) */
|
|
748
|
+
pk?: SkCondition;
|
|
749
|
+
/** Maximum number of items to return */
|
|
750
|
+
limit?: number;
|
|
751
|
+
/** Sort order (true = ascending, false = descending) */
|
|
752
|
+
scanIndexForward?: boolean;
|
|
753
|
+
};
|
|
754
|
+
/** Extract keys of T whose values are arrays */
|
|
755
|
+
type ArrayKeys<T> = {
|
|
756
|
+
[K in keyof T]: T[K] extends unknown[] ? K : never;
|
|
757
|
+
}[keyof T];
|
|
758
|
+
/** Extract keys of T whose values are numbers */
|
|
759
|
+
type NumberKeys<T> = {
|
|
760
|
+
[K in keyof T]: T[K] extends number ? K : never;
|
|
761
|
+
}[keyof T];
|
|
762
|
+
/**
|
|
763
|
+
* Update actions for TableClient.update()
|
|
764
|
+
*
|
|
765
|
+
* `set`, `append`, and `remove` target fields inside the `data` attribute.
|
|
766
|
+
* Effortless auto-prefixes `data.` in the DynamoDB expression.
|
|
767
|
+
*
|
|
768
|
+
* @typeParam T - Type of the domain data (the `data` attribute)
|
|
769
|
+
*/
|
|
770
|
+
type UpdateActions<T> = {
|
|
771
|
+
/** Set domain data fields (inside `data` attribute) */
|
|
772
|
+
set?: Partial<T>;
|
|
773
|
+
/** Atomically increment/decrement numeric fields inside `data` (use negative values to decrement) */
|
|
774
|
+
increment?: Pick<Partial<T>, NumberKeys<T>>;
|
|
775
|
+
/** Append elements to list fields inside `data` (creates the list if it doesn't exist) */
|
|
776
|
+
append?: Pick<Partial<T>, ArrayKeys<T>>;
|
|
777
|
+
/** Remove fields from `data` */
|
|
778
|
+
remove?: (keyof T)[];
|
|
779
|
+
/** Update the top-level `tag` attribute */
|
|
780
|
+
tag?: string;
|
|
781
|
+
/** Update TTL (set number or null to remove) */
|
|
782
|
+
ttl?: number | null;
|
|
783
|
+
};
|
|
784
|
+
/**
|
|
785
|
+
* Typed DynamoDB table client for single-table design.
|
|
786
|
+
*
|
|
787
|
+
* All items follow the `{ pk, sk, tag, data, ttl? }` structure.
|
|
788
|
+
* `T` is the domain data type stored in the `data` attribute.
|
|
789
|
+
*
|
|
790
|
+
* @typeParam T - Type of the domain data
|
|
791
|
+
*/
|
|
792
|
+
/**
|
|
793
|
+
* Options for `put()` operation.
|
|
794
|
+
*/
|
|
795
|
+
type PutOptions = {
|
|
796
|
+
/** When true, the put fails if an item with the same pk+sk already exists. */
|
|
797
|
+
ifNotExists?: boolean;
|
|
798
|
+
};
|
|
799
|
+
type TableClient<T = Record<string, unknown>> = {
|
|
800
|
+
/** Put an item. Tag is auto-extracted from `data[tagField]`. Use `ifNotExists` to prevent overwrites. */
|
|
801
|
+
put(item: PutInput<T>, options?: PutOptions): Promise<void>;
|
|
802
|
+
/** Get an item by pk + sk */
|
|
803
|
+
get(key: TableKey): Promise<TableItem<T> | undefined>;
|
|
804
|
+
/** Delete an item by pk + sk */
|
|
805
|
+
delete(key: TableKey): Promise<void>;
|
|
806
|
+
/** Update domain data fields without reading the full item */
|
|
807
|
+
update(key: TableKey, actions: UpdateActions<T>): Promise<void>;
|
|
808
|
+
/** Query by partition key with optional sort key condition */
|
|
809
|
+
query(params: QueryParams): Promise<TableItem<T>[]>;
|
|
810
|
+
/** Query by tag across all partitions via GSI (tag-pk-index). */
|
|
811
|
+
queryByTag(params: QueryByTagParams): Promise<TableItem<T>[]>;
|
|
812
|
+
/** The underlying DynamoDB table name */
|
|
813
|
+
tableName: string;
|
|
814
|
+
};
|
|
850
815
|
|
|
851
816
|
/**
|
|
852
817
|
* Options for sending an email via EmailClient.send()
|
|
@@ -924,7 +889,12 @@ type StreamView = "NEW_AND_OLD_IMAGES" | "NEW_IMAGE" | "OLD_IMAGE" | "KEYS_ONLY"
|
|
|
924
889
|
*/
|
|
925
890
|
type TableConfig = {
|
|
926
891
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
927
|
-
lambda?:
|
|
892
|
+
lambda?: {
|
|
893
|
+
memory?: number;
|
|
894
|
+
timeout?: Duration;
|
|
895
|
+
logLevel?: LogLevel;
|
|
896
|
+
permissions?: Permission[];
|
|
897
|
+
};
|
|
928
898
|
/** DynamoDB billing mode (default: "PAY_PER_REQUEST") */
|
|
929
899
|
billingMode?: "PAY_PER_REQUEST" | "PROVISIONED";
|
|
930
900
|
/** Stream view type - what data to include in stream records (default: "NEW_AND_OLD_IMAGES") */
|
|
@@ -968,20 +938,16 @@ type TableRecord<T = Record<string, unknown>> = {
|
|
|
968
938
|
/** Approximate timestamp when the modification occurred */
|
|
969
939
|
timestamp?: number;
|
|
970
940
|
};
|
|
971
|
-
/**
|
|
972
|
-
|
|
973
|
-
* Receives `table: TableClient<T>` (self-client for the handler's own table).
|
|
974
|
-
* Also receives `deps` and/or `config` when declared.
|
|
975
|
-
*/
|
|
976
|
-
type SetupFactory$1<C, T, D, P, S extends string[] | undefined = undefined> = (args: {
|
|
941
|
+
/** Setup factory — receives table/deps/config/files based on what was declared */
|
|
942
|
+
type SetupArgs$1<T, D, P, HasFiles extends boolean> = {
|
|
977
943
|
table: TableClient<T>;
|
|
978
944
|
} & ([D] extends [undefined] ? {} : {
|
|
979
945
|
deps: ResolveDeps<D>;
|
|
980
946
|
}) & ([P] extends [undefined] ? {} : {
|
|
981
947
|
config: ResolveConfig<P & {}>;
|
|
982
|
-
}) & (
|
|
948
|
+
}) & (HasFiles extends true ? {
|
|
983
949
|
files: StaticFiles;
|
|
984
|
-
}
|
|
950
|
+
} : {});
|
|
985
951
|
/** Spread ctx into callback args (empty when no setup) */
|
|
986
952
|
type SpreadCtx$1<C> = [C] extends [undefined] ? {} : C & {};
|
|
987
953
|
/**
|
|
@@ -1002,73 +968,10 @@ type TableBatchFn<T = Record<string, unknown>, C = undefined> = (args: {
|
|
|
1002
968
|
} & SpreadCtx$1<C>) => Promise<void | {
|
|
1003
969
|
failures: string[];
|
|
1004
970
|
}>;
|
|
1005
|
-
/**
|
|
1006
|
-
type DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = Omit<TableConfig, "tagField"> & {
|
|
1007
|
-
/** Name of the field in `data` that serves as the entity type discriminant (default: `"tag"`). */
|
|
1008
|
-
tagField?: Extract<keyof T, string>;
|
|
1009
|
-
/**
|
|
1010
|
-
* Decode/validate function for the `data` portion of stream record items.
|
|
1011
|
-
* Called with the unmarshalled `data` attribute; should return typed data or throw on validation failure.
|
|
1012
|
-
* When provided, T is inferred from the return type — no need to specify generic parameters.
|
|
1013
|
-
*/
|
|
1014
|
-
schema?: (input: unknown) => T;
|
|
1015
|
-
/**
|
|
1016
|
-
* Error handler called when onRecord/onRecordBatch throws.
|
|
1017
|
-
* If not provided, defaults to `console.error`.
|
|
1018
|
-
*/
|
|
1019
|
-
onError?: (args: {
|
|
1020
|
-
error: unknown;
|
|
1021
|
-
} & SpreadCtx$1<C>) => void;
|
|
1022
|
-
/** Called after each invocation completes, right before Lambda freezes the process */
|
|
1023
|
-
onAfterInvoke?: (args: SpreadCtx$1<C>) => void | Promise<void>;
|
|
1024
|
-
/**
|
|
1025
|
-
* Factory function to initialize shared state for callbacks.
|
|
1026
|
-
* Called once on cold start, result is cached and reused across invocations.
|
|
1027
|
-
* Receives `table` (self-client), plus `deps`/`config`/`files` when declared.
|
|
1028
|
-
*/
|
|
1029
|
-
setup?: SetupFactory$1<C, T, NoInfer<D>, NoInfer<P>, NoInfer<S>>;
|
|
1030
|
-
/**
|
|
1031
|
-
* Dependencies on other handlers (tables, queues, etc.).
|
|
1032
|
-
* Typed clients are injected into setup via the `deps` argument.
|
|
1033
|
-
* Pass a function returning the deps object: `deps: () => ({ orders })`.
|
|
1034
|
-
*/
|
|
1035
|
-
deps?: () => D & {};
|
|
1036
|
-
/**
|
|
1037
|
-
* SSM Parameter Store parameters.
|
|
1038
|
-
* Declare with `defineSecret()` helper. Values are fetched and cached at cold start.
|
|
1039
|
-
*/
|
|
1040
|
-
config?: ConfigFactory<P>;
|
|
1041
|
-
/**
|
|
1042
|
-
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
1043
|
-
* Files are accessible at runtime via the `files` argument in setup.
|
|
1044
|
-
*/
|
|
1045
|
-
static?: S;
|
|
1046
|
-
};
|
|
1047
|
-
/**
|
|
1048
|
-
* Options for defineTable.
|
|
1049
|
-
* `onRecord` and `onRecordBatch` are mutually exclusive. Both are optional (table-only mode).
|
|
1050
|
-
*/
|
|
1051
|
-
type DefineTableOptions<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & ({
|
|
1052
|
-
/**
|
|
1053
|
-
* Per-record stream handler. Called once per record in the batch.
|
|
1054
|
-
* Runtime handles partial batch failure reporting automatically.
|
|
1055
|
-
* Records are processed with configurable `concurrency` (default: 1 — sequential).
|
|
1056
|
-
*/
|
|
1057
|
-
onRecord?: TableRecordFn<T, C>;
|
|
1058
|
-
onRecordBatch?: never;
|
|
1059
|
-
} | {
|
|
1060
|
-
/**
|
|
1061
|
-
* Batch stream handler. Called once with all records in the batch.
|
|
1062
|
-
* Return `{ failures: string[] }` with sequence numbers for partial batch failure.
|
|
1063
|
-
*/
|
|
1064
|
-
onRecordBatch?: TableBatchFn<T, C>;
|
|
1065
|
-
onRecord?: never;
|
|
1066
|
-
} | {
|
|
1067
|
-
onRecord?: never;
|
|
1068
|
-
onRecordBatch?: never;
|
|
1069
|
-
});
|
|
971
|
+
/** Static config extracted by AST (no runtime callbacks) */
|
|
1070
972
|
/**
|
|
1071
|
-
*
|
|
973
|
+
* Handler object created by defineTable.
|
|
974
|
+
* Used by runtime wrappers and as type annotation for circular deps.
|
|
1072
975
|
* @internal
|
|
1073
976
|
*/
|
|
1074
977
|
type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
@@ -1076,7 +979,7 @@ type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
|
1076
979
|
readonly __spec: TableConfig;
|
|
1077
980
|
readonly schema?: (input: unknown) => T;
|
|
1078
981
|
readonly onError?: (...args: any[]) => any;
|
|
1079
|
-
readonly
|
|
982
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
1080
983
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
1081
984
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
1082
985
|
readonly config?: Record<string, unknown>;
|
|
@@ -1084,6 +987,55 @@ type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
|
1084
987
|
readonly onRecord?: (...args: any[]) => any;
|
|
1085
988
|
readonly onRecordBatch?: (...args: any[]) => any;
|
|
1086
989
|
};
|
|
990
|
+
/** Options passed to `defineTable()` — static config, no generics needed for inference */
|
|
991
|
+
type TableOptions<T> = {
|
|
992
|
+
/** Lambda memory in MB (default: 256) */
|
|
993
|
+
memory?: number;
|
|
994
|
+
/** Lambda timeout (default: 30s). Accepts seconds or duration string: `"30s"`, `"5m"` */
|
|
995
|
+
timeout?: Duration;
|
|
996
|
+
/** Additional IAM permissions for the Lambda */
|
|
997
|
+
permissions?: Permission[];
|
|
998
|
+
/** Logging verbosity */
|
|
999
|
+
logLevel?: LogLevel;
|
|
1000
|
+
/** DynamoDB billing mode (default: "PAY_PER_REQUEST") */
|
|
1001
|
+
billingMode?: "PAY_PER_REQUEST" | "PROVISIONED";
|
|
1002
|
+
/** Stream view type (default: "NEW_AND_OLD_IMAGES") */
|
|
1003
|
+
streamView?: StreamView;
|
|
1004
|
+
/** Number of records to process in each Lambda invocation (1-10000, default: 100) */
|
|
1005
|
+
batchSize?: number;
|
|
1006
|
+
/** Maximum time to gather records before invoking (default: "2s") */
|
|
1007
|
+
batchWindow?: Duration;
|
|
1008
|
+
/** Where to start reading the stream (default: "LATEST") */
|
|
1009
|
+
startingPosition?: "LATEST" | "TRIM_HORIZON";
|
|
1010
|
+
/** Number of records to process concurrently within a batch (default: 1) */
|
|
1011
|
+
concurrency?: number;
|
|
1012
|
+
/** Name of the field in `data` that serves as the entity type discriminant (default: "tag") */
|
|
1013
|
+
tagField?: Extract<keyof T, string>;
|
|
1014
|
+
/** Decode/validate function for the `data` portion of stream records */
|
|
1015
|
+
schema?: (input: unknown) => T;
|
|
1016
|
+
/** Static file glob patterns to bundle into the Lambda ZIP */
|
|
1017
|
+
static?: string[];
|
|
1018
|
+
};
|
|
1019
|
+
interface TableBuilder<T = Record<string, unknown>, D = undefined, P = undefined, C = undefined, HasFiles extends boolean = false> {
|
|
1020
|
+
/** Declare handler dependencies (tables, queues, buckets, mailers) */
|
|
1021
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): TableBuilder<T, D2, P, C, HasFiles>;
|
|
1022
|
+
/** Declare SSM secrets */
|
|
1023
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): TableBuilder<T, D, P2, C, HasFiles>;
|
|
1024
|
+
/** Initialize shared state on cold start. Receives table (self-client), deps, config, files. */
|
|
1025
|
+
setup<C2>(fn: (args: SetupArgs$1<T, D, P, HasFiles>) => C2 | Promise<C2>): TableBuilder<T, D, P, C2, HasFiles>;
|
|
1026
|
+
/** Handle errors thrown by onRecord/onRecordBatch */
|
|
1027
|
+
onError(fn: (args: {
|
|
1028
|
+
error: unknown;
|
|
1029
|
+
} & SpreadCtx$1<C>) => void): TableBuilder<T, D, P, C, HasFiles>;
|
|
1030
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
1031
|
+
onCleanup(fn: (args: SpreadCtx$1<C>) => void | Promise<void>): TableBuilder<T, D, P, C, HasFiles>;
|
|
1032
|
+
/** Per-record stream handler (terminal — returns finalized handler) */
|
|
1033
|
+
onRecord(fn: TableRecordFn<T, C>): TableHandler<T, C>;
|
|
1034
|
+
/** Batch stream handler (terminal — returns finalized handler) */
|
|
1035
|
+
onRecordBatch(fn: TableBatchFn<T, C>): TableHandler<T, C>;
|
|
1036
|
+
/** Finalize as resource-only table (no Lambda) */
|
|
1037
|
+
build(): TableHandler<T, C>;
|
|
1038
|
+
}
|
|
1087
1039
|
/**
|
|
1088
1040
|
* Define a DynamoDB table with optional stream handler (single-table design).
|
|
1089
1041
|
*
|
|
@@ -1092,32 +1044,30 @@ type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
|
1092
1044
|
*
|
|
1093
1045
|
* @example Table with stream handler
|
|
1094
1046
|
* ```typescript
|
|
1095
|
-
* export const orders = defineTable<OrderData>()
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
* setup: ({ table }) => ({ table }),
|
|
1099
|
-
* onRecord: async ({ record, batch, table }) => {
|
|
1047
|
+
* export const orders = defineTable<OrderData>({ batchSize: 10, concurrency: 5 })
|
|
1048
|
+
* .setup(({ table }) => ({ table }))
|
|
1049
|
+
* .onRecord(async ({ record, table }) => {
|
|
1100
1050
|
* if (record.eventName === "INSERT") {
|
|
1101
1051
|
* console.log("New order:", record.new?.data);
|
|
1102
1052
|
* }
|
|
1103
|
-
* }
|
|
1104
|
-
* });
|
|
1053
|
+
* })
|
|
1105
1054
|
* ```
|
|
1106
1055
|
*
|
|
1107
|
-
* @example Table
|
|
1056
|
+
* @example Table only (no Lambda)
|
|
1108
1057
|
* ```typescript
|
|
1109
|
-
* export const
|
|
1110
|
-
* schema: (input) => OrderSchema.parse(input),
|
|
1111
|
-
* onRecord: async ({ record }) => { ... }
|
|
1112
|
-
* });
|
|
1058
|
+
* export const users = defineTable<User>().build()
|
|
1113
1059
|
* ```
|
|
1114
1060
|
*
|
|
1115
|
-
* @example Table only
|
|
1061
|
+
* @example Table as dependency (resource-only, no Lambda)
|
|
1116
1062
|
* ```typescript
|
|
1117
|
-
* export const
|
|
1063
|
+
* export const sessions = defineTable<Session>().build()
|
|
1118
1064
|
* ```
|
|
1119
1065
|
*/
|
|
1120
|
-
declare
|
|
1066
|
+
declare function defineTable<T = Record<string, unknown>>(): TableBuilder<T>;
|
|
1067
|
+
declare function defineTable<T = Record<string, unknown>>(options: TableOptions<T> & {
|
|
1068
|
+
static: string[];
|
|
1069
|
+
}): TableBuilder<T, undefined, undefined, undefined, true>;
|
|
1070
|
+
declare function defineTable<T = Record<string, unknown>>(options: TableOptions<T>): TableBuilder<T>;
|
|
1121
1071
|
|
|
1122
1072
|
/**
|
|
1123
1073
|
* Configuration for deploying an SSR framework (Nuxt, Astro, etc.)
|
|
@@ -1330,7 +1280,11 @@ type ExtractAuth<C> = C extends {
|
|
|
1330
1280
|
auth: ApiAuthConfig<infer A>;
|
|
1331
1281
|
} ? A : undefined;
|
|
1332
1282
|
/** Property names reserved by the framework — cannot be used in setup return */
|
|
1333
|
-
type ReservedKeys = 'req' | 'input' | 'stream';
|
|
1283
|
+
type ReservedKeys = 'req' | 'input' | 'stream' | 'ok' | 'fail';
|
|
1284
|
+
/** Success response helper: `ok({ data })` → `{ status: 200, body: { data } }` */
|
|
1285
|
+
type OkHelper = (body?: unknown, status?: number) => HttpResponse;
|
|
1286
|
+
/** Error response helper: `fail("message")` → `{ status: 400, body: { error: "message" } }` */
|
|
1287
|
+
type FailHelper = (message: string, status?: number) => HttpResponse;
|
|
1334
1288
|
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
1335
1289
|
/** Parsed route definition stored at runtime */
|
|
1336
1290
|
type RouteEntry = {
|
|
@@ -1347,29 +1301,33 @@ type SpreadCtx<C> = ([C] extends [undefined] ? {} : Omit<C & {}, 'auth'>) & ([Ex
|
|
|
1347
1301
|
type RouteArgs<C, ST> = SpreadCtx<C> & {
|
|
1348
1302
|
req: HttpRequest;
|
|
1349
1303
|
input: unknown;
|
|
1304
|
+
ok: OkHelper;
|
|
1305
|
+
fail: FailHelper;
|
|
1350
1306
|
} & ([ST] extends [true] ? {
|
|
1351
1307
|
stream: ResponseStream;
|
|
1352
1308
|
} : {});
|
|
1353
|
-
/** Route
|
|
1354
|
-
type
|
|
1355
|
-
|
|
1356
|
-
|
|
1309
|
+
/** Route handler function */
|
|
1310
|
+
type RouteHandler<C, ST> = (args: RouteArgs<C, ST>) => Promise<HttpResponse | void> | HttpResponse | void;
|
|
1311
|
+
/** Route options (e.g. public) */
|
|
1312
|
+
type RouteOptions = {
|
|
1357
1313
|
public?: boolean;
|
|
1358
1314
|
};
|
|
1359
|
-
/**
|
|
1360
|
-
type
|
|
1361
|
-
[K in ReservedKeys]?: never;
|
|
1362
|
-
};
|
|
1363
|
-
/** Setup factory — receives deps/config/files/enableAuth when declared */
|
|
1364
|
-
type SetupFactory<C, D, P, S extends string[] | undefined = undefined> = (args: {
|
|
1315
|
+
/** Setup factory — receives deps/config/files/enableAuth based on what was declared */
|
|
1316
|
+
type SetupArgs<D, P, HasFiles extends boolean> = {
|
|
1365
1317
|
enableAuth: EnableAuth;
|
|
1318
|
+
ok: OkHelper;
|
|
1319
|
+
fail: FailHelper;
|
|
1366
1320
|
} & ([D] extends [undefined] ? {} : {
|
|
1367
1321
|
deps: ResolveDeps<D>;
|
|
1368
1322
|
}) & ([P] extends [undefined] ? {} : {
|
|
1369
1323
|
config: ResolveConfig<P & {}>;
|
|
1370
|
-
}) & (
|
|
1324
|
+
}) & (HasFiles extends true ? {
|
|
1371
1325
|
files: StaticFiles;
|
|
1372
|
-
}
|
|
1326
|
+
} : {});
|
|
1327
|
+
/** Validate that setup return type does not use reserved property names */
|
|
1328
|
+
type ValidateSetupReturn<C> = C & {
|
|
1329
|
+
[K in ReservedKeys]?: never;
|
|
1330
|
+
};
|
|
1373
1331
|
/** Static config extracted by AST (no runtime callbacks) */
|
|
1374
1332
|
type ApiConfig = {
|
|
1375
1333
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
@@ -1379,79 +1337,104 @@ type ApiConfig = {
|
|
|
1379
1337
|
/** Enable response streaming. When true, the Lambda Function URL uses RESPONSE_STREAM invoke mode. */
|
|
1380
1338
|
stream?: boolean;
|
|
1381
1339
|
};
|
|
1382
|
-
type DefineApiOptions<C = undefined, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnySecretRef> | undefined = undefined, S extends string[] | undefined = undefined, ST extends boolean | undefined = undefined> = {
|
|
1383
|
-
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
1384
|
-
lambda?: LambdaWithPermissions;
|
|
1385
|
-
/** Base path prefix for all routes (e.g., "/api") */
|
|
1386
|
-
basePath: `/${string}`;
|
|
1387
|
-
/** Enable response streaming. When true, routes receive a `stream` arg for SSE. */
|
|
1388
|
-
stream?: ST;
|
|
1389
|
-
/** Factory function to initialize shared state. Called once on cold start. */
|
|
1390
|
-
setup?: SetupFactory<C, NoInfer<D>, NoInfer<P>, NoInfer<S>>;
|
|
1391
|
-
/** Dependencies on other handlers (tables, queues, etc.): `deps: () => ({ users })` */
|
|
1392
|
-
deps?: () => D & {};
|
|
1393
|
-
/** SSM Parameter Store parameters. Receives `{ defineSecret }` helper. */
|
|
1394
|
-
config?: ConfigFactory<P>;
|
|
1395
|
-
/** Static file glob patterns to bundle into the Lambda ZIP */
|
|
1396
|
-
static?: S;
|
|
1397
|
-
/** Error handler called when a route throws */
|
|
1398
|
-
onError?: (args: {
|
|
1399
|
-
error: unknown;
|
|
1400
|
-
req: HttpRequest;
|
|
1401
|
-
} & SpreadCtx<C>) => HttpResponse;
|
|
1402
|
-
/** Called after each invocation completes */
|
|
1403
|
-
onAfterInvoke?: (args: SpreadCtx<C>) => void | Promise<void>;
|
|
1404
|
-
/** Route definitions — plain array of route objects */
|
|
1405
|
-
routes?: RouteDefinition<C, ST>[];
|
|
1406
|
-
};
|
|
1407
1340
|
/** Internal handler object created by defineApi */
|
|
1408
1341
|
type ApiHandler<C = undefined> = {
|
|
1409
1342
|
readonly __brand: "effortless-api";
|
|
1410
1343
|
readonly __spec: ApiConfig;
|
|
1411
1344
|
readonly onError?: (...args: any[]) => any;
|
|
1412
|
-
readonly
|
|
1345
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
1413
1346
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
1414
1347
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
1415
1348
|
readonly config?: Record<string, unknown>;
|
|
1416
1349
|
readonly static?: string[];
|
|
1417
1350
|
readonly routes?: RouteEntry[];
|
|
1418
1351
|
};
|
|
1352
|
+
/** Options passed to `defineApi()` */
|
|
1353
|
+
type ApiOptions = {
|
|
1354
|
+
/** Base path prefix for all routes (e.g., "/api") */
|
|
1355
|
+
basePath: `/${string}`;
|
|
1356
|
+
/** Lambda memory in MB (default: 256) */
|
|
1357
|
+
memory?: number;
|
|
1358
|
+
/** Lambda timeout (default: 30s). Accepts seconds or duration string: `"30s"`, `"5m"` */
|
|
1359
|
+
timeout?: Duration;
|
|
1360
|
+
/** Additional IAM permissions for the Lambda */
|
|
1361
|
+
permissions?: Permission[];
|
|
1362
|
+
/** Logging verbosity: "error" (errors only), "info" (+ execution summary), "debug" (+ input/output). Default: "info" */
|
|
1363
|
+
logLevel?: LogLevel;
|
|
1364
|
+
/** Enable response streaming. When true, routes receive a `stream` arg for SSE. */
|
|
1365
|
+
stream?: boolean;
|
|
1366
|
+
/** Static file glob patterns to bundle into the Lambda ZIP */
|
|
1367
|
+
static?: string[];
|
|
1368
|
+
};
|
|
1369
|
+
/**
|
|
1370
|
+
* Finalized API handler with route-adding methods.
|
|
1371
|
+
* Has `__brand` so CLI discovers it. Each `.get()/.post()` adds a route and returns self.
|
|
1372
|
+
*/
|
|
1373
|
+
interface ApiRoutes<C = undefined, ST extends boolean = false> extends ApiHandler<C> {
|
|
1374
|
+
get(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1375
|
+
post(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1376
|
+
put(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1377
|
+
patch(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1378
|
+
delete(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1379
|
+
}
|
|
1419
1380
|
/**
|
|
1420
|
-
*
|
|
1381
|
+
* Builder interface for defining API handlers.
|
|
1421
1382
|
*
|
|
1422
|
-
*
|
|
1423
|
-
*
|
|
1424
|
-
|
|
1383
|
+
* Each method sets exactly one generic, so inference happens one step at a time.
|
|
1384
|
+
* This prevents cascading type errors when one property has a mistake.
|
|
1385
|
+
*/
|
|
1386
|
+
interface ApiBuilder<D = undefined, P = undefined, C = undefined, ST extends boolean = false, HasFiles extends boolean = false> {
|
|
1387
|
+
/** Declare handler dependencies (tables, queues, buckets, mailers) */
|
|
1388
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): ApiBuilder<D2, P, C, ST, HasFiles>;
|
|
1389
|
+
/** Declare SSM secrets */
|
|
1390
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): ApiBuilder<D, P2, C, ST, HasFiles>;
|
|
1391
|
+
/** Initialize shared state on cold start. Receives deps/config/files based on what was declared. */
|
|
1392
|
+
setup<C2>(fn: (args: SetupArgs<D, P, HasFiles>) => ValidateSetupReturn<C2> | Promise<ValidateSetupReturn<C2>>): ApiBuilder<D, P, C2, ST, HasFiles>;
|
|
1393
|
+
/** Handle errors thrown by routes */
|
|
1394
|
+
onError(fn: (args: {
|
|
1395
|
+
error: unknown;
|
|
1396
|
+
req: HttpRequest;
|
|
1397
|
+
ok: OkHelper;
|
|
1398
|
+
fail: FailHelper;
|
|
1399
|
+
} & SpreadCtx<C>) => HttpResponse): ApiBuilder<D, P, C, ST, HasFiles>;
|
|
1400
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
1401
|
+
onCleanup(fn: (args: SpreadCtx<C>) => void | Promise<void>): ApiBuilder<D, P, C, ST, HasFiles>;
|
|
1402
|
+
/** Add a GET route (terminal — returns finalized handler with route methods) */
|
|
1403
|
+
get(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1404
|
+
/** Add a POST route (terminal) */
|
|
1405
|
+
post(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1406
|
+
/** Add a PUT route (terminal) */
|
|
1407
|
+
put(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1408
|
+
/** Add a PATCH route (terminal) */
|
|
1409
|
+
patch(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1410
|
+
/** Add a DELETE route (terminal) */
|
|
1411
|
+
delete(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Define an API with typed routes using a builder pattern.
|
|
1425
1415
|
*
|
|
1426
1416
|
* @example
|
|
1427
1417
|
* ```typescript
|
|
1428
|
-
*
|
|
1429
|
-
*
|
|
1430
|
-
*
|
|
1431
|
-
*
|
|
1418
|
+
* // Minimal
|
|
1419
|
+
* export default defineApi({ basePath: "/hello" })
|
|
1420
|
+
* .get("/", async ({ req, ok }) => ok({ message: "Hello!" }))
|
|
1421
|
+
*
|
|
1422
|
+
* // Full
|
|
1423
|
+
* export const api = defineApi({ basePath: "/api", timeout: "30s" })
|
|
1424
|
+
* .deps(() => ({ users }))
|
|
1425
|
+
* .config(({ defineSecret }) => ({ dbUrl: defineSecret() }))
|
|
1426
|
+
* .setup(async ({ deps, config, enableAuth }) => ({
|
|
1432
1427
|
* users: deps.users,
|
|
1433
|
-
* auth: {
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
1436
|
-
*
|
|
1437
|
-
*
|
|
1438
|
-
* return user[0] ? { userId: user[0].sk } : null;
|
|
1439
|
-
* },
|
|
1440
|
-
* },
|
|
1441
|
-
* },
|
|
1442
|
-
* }),
|
|
1443
|
-
* routes: [
|
|
1444
|
-
* {
|
|
1445
|
-
* path: "GET /me",
|
|
1446
|
-
* onRequest: async ({ users, auth }) => ({
|
|
1447
|
-
* status: 200,
|
|
1448
|
-
* body: { user: await users.get(auth.session.userId) },
|
|
1449
|
-
* }),
|
|
1450
|
-
* },
|
|
1451
|
-
* ],
|
|
1452
|
-
* })
|
|
1428
|
+
* auth: enableAuth<Session>({ secret: config.dbUrl }),
|
|
1429
|
+
* }))
|
|
1430
|
+
* .onError(({ error, fail }) => fail(String(error), 500))
|
|
1431
|
+
* .get("/me", async ({ users, auth, ok }) => ok(auth.session))
|
|
1432
|
+
* .post("/login", async ({ auth, ok }) => ok(await auth.createSession()), { public: true })
|
|
1453
1433
|
* ```
|
|
1454
1434
|
*/
|
|
1455
|
-
declare
|
|
1435
|
+
declare function defineApi(options: ApiOptions & {
|
|
1436
|
+
static: string[];
|
|
1437
|
+
}): ApiBuilder<undefined, undefined, undefined, false, true>;
|
|
1438
|
+
declare function defineApi<const O extends ApiOptions>(options: O): ApiBuilder<undefined, undefined, undefined, O["stream"] extends true ? true : false, O["static"] extends string[] ? true : false>;
|
|
1456
1439
|
|
|
1457
|
-
export { type AnyParamRef, type AnySecretRef, type ApiAuthConfig, type ApiConfig, type ApiHandler, type AppConfig, type AppHandler, type AuthHelpers, type BucketClient, type BucketConfig, type BucketEvent, type BucketHandler, type ConfigHelpers, type ContentType, type DefineSecretFn, type Duration, type EffortlessConfig, type EmailClient, type FifoQueueConfig, type FifoQueueHandler, type FifoQueueMessage, type GenerateSpec, type HttpMethod$1 as HttpMethod, type HttpRequest, type HttpResponse, type LambdaConfig, type LambdaWithPermissions, type LogLevel, type MailerConfig, type MailerHandler, type MiddlewareDeny, type MiddlewareHandler, type MiddlewareRedirect, type MiddlewareRequest, type MiddlewareResult, type ParamRef, type Permission, type PutInput, type PutOptions, type QueryByTagParams, type QueryParams, type QueueClient, type ResponseStream, type SecretRef, type SendEmailOptions, type SendMessageInput, type SkCondition, type StaticFiles, type StaticSiteConfig, type StaticSiteHandler, type StaticSiteSeo, type StreamView, type TableClient, type TableConfig, type TableHandler, type TableItem, type TableKey, type TableRecord, type UpdateActions, defineApi, defineApp, defineBucket, defineConfig, defineFifoQueue, defineMailer, defineSecret, defineStaticSite, defineTable, generateBase64, generateHex, generateUuid, param,
|
|
1440
|
+
export { type AnyParamRef, type AnySecretRef, type ApiAuthConfig, type ApiConfig, type ApiHandler, type ApiRoutes, type AppConfig, type AppHandler, type AuthHelpers, type BucketClient, type BucketConfig, type BucketEvent, type BucketHandler, type ConfigHelpers, type ContentType, type DefineSecretFn, type Duration, type EffortlessConfig, type EmailClient, type FifoQueueConfig, type FifoQueueHandler, type FifoQueueMessage, type GenerateSpec, type HttpMethod$1 as HttpMethod, type HttpRequest, type HttpResponse, type LambdaConfig, type LambdaWithPermissions, type LogLevel, type MailerConfig, type MailerHandler, type MiddlewareDeny, type MiddlewareHandler, type MiddlewareRedirect, type MiddlewareRequest, type MiddlewareResult, type ParamRef, type Permission, type PutInput, type PutOptions, type QueryByTagParams, type QueryParams, type QueueClient, type ResponseStream, type SecretRef, type SendEmailOptions, type SendMessageInput, type SkCondition, type StaticFiles, type StaticSiteConfig, type StaticSiteHandler, type StaticSiteSeo, type StreamView, type TableClient, type TableConfig, type TableHandler, type TableItem, type TableKey, type TableRecord, type UpdateActions, defineApi, defineApp, defineBucket, defineConfig, defineFifoQueue, defineMailer, defineSecret, defineStaticSite, defineTable, generateBase64, generateHex, generateUuid, param, secret, toSeconds, unsafeAs };
|