effortless-aws 0.29.0 → 0.31.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 +537 -535
- package/dist/index.js +361 -87
- 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-cron.js +40 -0
- 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
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Configuration for an Effortless project.
|
|
3
3
|
*
|
|
4
|
-
* @
|
|
5
|
-
* ```typescript
|
|
6
|
-
* // effortless.config.ts
|
|
7
|
-
* import { defineConfig } from "effortless-aws";
|
|
8
|
-
*
|
|
9
|
-
* export default defineConfig({
|
|
10
|
-
* name: "my-service",
|
|
11
|
-
* region: "eu-central-1",
|
|
12
|
-
* handlers: "src",
|
|
13
|
-
* });
|
|
14
|
-
* ```
|
|
4
|
+
* @see {@link https://effortless-aws.website/configuration | Configuration guide}
|
|
15
5
|
*/
|
|
16
6
|
type EffortlessConfig = {
|
|
17
7
|
/**
|
|
@@ -78,21 +68,7 @@ type EffortlessConfig = {
|
|
|
78
68
|
runtime?: string;
|
|
79
69
|
};
|
|
80
70
|
};
|
|
81
|
-
/**
|
|
82
|
-
* Helper function for type-safe configuration.
|
|
83
|
-
* Returns the config object as-is, but provides TypeScript autocompletion.
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* ```typescript
|
|
87
|
-
* import { defineConfig } from "effortless-aws";
|
|
88
|
-
*
|
|
89
|
-
* export default defineConfig({
|
|
90
|
-
* name: "my-service",
|
|
91
|
-
* region: "eu-central-1",
|
|
92
|
-
* handlers: "src",
|
|
93
|
-
* });
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
71
|
+
/** Helper function for type-safe configuration with TypeScript autocompletion. */
|
|
96
72
|
declare const defineConfig: (config: EffortlessConfig) => EffortlessConfig;
|
|
97
73
|
|
|
98
74
|
/** Generator spec for auto-creating secrets at deploy time. */
|
|
@@ -136,6 +112,20 @@ type LambdaWithPermissions = LambdaConfig & {
|
|
|
136
112
|
/** Additional IAM permissions for the Lambda */
|
|
137
113
|
permissions?: Permission[];
|
|
138
114
|
};
|
|
115
|
+
/**
|
|
116
|
+
* Lambda configuration passed as argument to `.setup()`.
|
|
117
|
+
* Common across all handler types that create a Lambda function.
|
|
118
|
+
*/
|
|
119
|
+
type LambdaOptions = {
|
|
120
|
+
/** Lambda memory in MB (default: 256) */
|
|
121
|
+
memory?: number;
|
|
122
|
+
/** Lambda timeout (default: 30s). Accepts seconds or duration string: `"30s"`, `"5m"` */
|
|
123
|
+
timeout?: Duration;
|
|
124
|
+
/** Additional IAM permissions for the Lambda */
|
|
125
|
+
permissions?: Permission[];
|
|
126
|
+
/** Logging verbosity: "error" (errors only), "info" (+ execution summary), "debug" (+ input/output). Default: "info" */
|
|
127
|
+
logLevel?: LogLevel;
|
|
128
|
+
};
|
|
139
129
|
type AnySecretRef = SecretRef<any>;
|
|
140
130
|
/**
|
|
141
131
|
* Reference to an SSM Parameter Store secret.
|
|
@@ -236,127 +226,6 @@ type PutInput<T> = {
|
|
|
236
226
|
data: T;
|
|
237
227
|
ttl?: number;
|
|
238
228
|
};
|
|
239
|
-
/**
|
|
240
|
-
* Create a schema function that casts input to T without runtime validation.
|
|
241
|
-
* Use when you need T inference alongside other generics (deps, config).
|
|
242
|
-
* For handlers without deps/config, prefer `defineTable<Order>({...})`.
|
|
243
|
-
* For untrusted input, prefer a real parser (Zod, Effect Schema).
|
|
244
|
-
*
|
|
245
|
-
* @example
|
|
246
|
-
* ```typescript
|
|
247
|
-
* export const orders = defineTable({
|
|
248
|
-
* schema: unsafeAs<Order>(),
|
|
249
|
-
* deps: () => ({ notifications }),
|
|
250
|
-
* onRecord: async ({ record, deps }) => { ... }
|
|
251
|
-
* });
|
|
252
|
-
* ```
|
|
253
|
-
*/
|
|
254
|
-
declare function unsafeAs<T>(): (input: unknown) => T;
|
|
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
229
|
|
|
361
230
|
/** HTTP methods supported by Lambda Function URLs */
|
|
362
231
|
type HttpMethod$1 = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "ANY";
|
|
@@ -411,13 +280,6 @@ type HttpResponse = {
|
|
|
411
280
|
*/
|
|
412
281
|
binary?: boolean;
|
|
413
282
|
};
|
|
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
283
|
/** Stream helper injected into route args when `stream: true` is set on defineApi */
|
|
422
284
|
type ResponseStream = {
|
|
423
285
|
/** Write a raw string chunk to the response stream */
|
|
@@ -470,7 +332,12 @@ type BucketClient = {
|
|
|
470
332
|
*/
|
|
471
333
|
type BucketConfig = {
|
|
472
334
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
473
|
-
lambda?:
|
|
335
|
+
lambda?: {
|
|
336
|
+
memory?: number;
|
|
337
|
+
timeout?: Duration;
|
|
338
|
+
logLevel?: LogLevel;
|
|
339
|
+
permissions?: Permission[];
|
|
340
|
+
};
|
|
474
341
|
/** S3 key prefix filter for event notifications (e.g., "uploads/") */
|
|
475
342
|
prefix?: string;
|
|
476
343
|
/** S3 key suffix filter for event notifications (e.g., ".jpg") */
|
|
@@ -494,79 +361,29 @@ type BucketEvent = {
|
|
|
494
361
|
bucketName: string;
|
|
495
362
|
};
|
|
496
363
|
/** Spread ctx into callback args (empty when no setup) */
|
|
497
|
-
type SpreadCtx$
|
|
364
|
+
type SpreadCtx$4<C> = [C] extends [undefined] ? {} : C & {};
|
|
365
|
+
/** Setup factory — receives bucket/deps/config/files based on what was declared */
|
|
366
|
+
type SetupArgs$4<D, P, HasFiles extends boolean> = {
|
|
367
|
+
bucket: BucketClient;
|
|
368
|
+
} & ([D] extends [undefined] ? {} : {
|
|
369
|
+
deps: ResolveDeps<D>;
|
|
370
|
+
}) & ([P] extends [undefined] ? {} : {
|
|
371
|
+
config: ResolveConfig<P & {}>;
|
|
372
|
+
}) & (HasFiles extends true ? {
|
|
373
|
+
files: StaticFiles;
|
|
374
|
+
} : {});
|
|
498
375
|
/**
|
|
499
376
|
* Callback function type for S3 ObjectCreated events
|
|
500
377
|
*/
|
|
501
378
|
type BucketObjectCreatedFn<C = undefined> = (args: {
|
|
502
379
|
event: BucketEvent;
|
|
503
|
-
} & SpreadCtx$
|
|
380
|
+
} & SpreadCtx$4<C>) => Promise<void>;
|
|
504
381
|
/**
|
|
505
382
|
* Callback function type for S3 ObjectRemoved events
|
|
506
383
|
*/
|
|
507
384
|
type BucketObjectRemovedFn<C = undefined> = (args: {
|
|
508
385
|
event: BucketEvent;
|
|
509
|
-
} & SpreadCtx$
|
|
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>;
|
|
386
|
+
} & SpreadCtx$4<C>) => Promise<void>;
|
|
570
387
|
/**
|
|
571
388
|
* Internal handler object created by defineBucket
|
|
572
389
|
* @internal
|
|
@@ -575,7 +392,7 @@ type BucketHandler<C = any> = {
|
|
|
575
392
|
readonly __brand: "effortless-bucket";
|
|
576
393
|
readonly __spec: BucketConfig;
|
|
577
394
|
readonly onError?: (...args: any[]) => any;
|
|
578
|
-
readonly
|
|
395
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
579
396
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
580
397
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
581
398
|
readonly config?: Record<string, unknown>;
|
|
@@ -583,42 +400,54 @@ type BucketHandler<C = any> = {
|
|
|
583
400
|
readonly onObjectCreated?: (...args: any[]) => any;
|
|
584
401
|
readonly onObjectRemoved?: (...args: any[]) => any;
|
|
585
402
|
};
|
|
403
|
+
/** Options passed to `defineBucket()` — static config */
|
|
404
|
+
type BucketOptions = {
|
|
405
|
+
/** S3 key prefix filter for event notifications (e.g., "uploads/") */
|
|
406
|
+
prefix?: string;
|
|
407
|
+
/** S3 key suffix filter for event notifications (e.g., ".jpg") */
|
|
408
|
+
suffix?: string;
|
|
409
|
+
};
|
|
410
|
+
interface BucketBuilder<D = undefined, P = undefined, C = undefined, HasFiles extends boolean = false> {
|
|
411
|
+
/** Declare handler dependencies */
|
|
412
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): BucketBuilder<D2, P, C, HasFiles>;
|
|
413
|
+
/** Declare SSM secrets */
|
|
414
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): BucketBuilder<D, P2, C, HasFiles>;
|
|
415
|
+
/** Include static files in the Lambda ZIP */
|
|
416
|
+
include(glob: string): BucketBuilder<D, P, C, true>;
|
|
417
|
+
/** Initialize shared state on cold start with lambda options */
|
|
418
|
+
setup(lambda: LambdaOptions): BucketBuilder<D, P, C, HasFiles>;
|
|
419
|
+
/** Initialize shared state on cold start. Receives bucket (self-client), deps, config, files. */
|
|
420
|
+
setup<C2>(fn: (args: SetupArgs$4<D, P, HasFiles>) => C2 | Promise<C2>): BucketBuilder<D, P, C2, HasFiles>;
|
|
421
|
+
/** Initialize shared state on cold start with lambda options. Receives bucket (self-client), deps, config, files. */
|
|
422
|
+
setup<C2>(fn: (args: SetupArgs$4<D, P, HasFiles>) => C2 | Promise<C2>, lambda: LambdaOptions): BucketBuilder<D, P, C2, HasFiles>;
|
|
423
|
+
/** Handle errors thrown by callbacks */
|
|
424
|
+
onError(fn: (args: {
|
|
425
|
+
error: unknown;
|
|
426
|
+
} & SpreadCtx$4<C>) => void): BucketBuilder<D, P, C, HasFiles>;
|
|
427
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
428
|
+
onCleanup(fn: (args: SpreadCtx$4<C>) => void | Promise<void>): BucketBuilder<D, P, C, HasFiles>;
|
|
429
|
+
/** Handle S3 ObjectCreated events (terminal — returns finalized handler) */
|
|
430
|
+
onObjectCreated(fn: BucketObjectCreatedFn<C>): BucketHandler<C>;
|
|
431
|
+
/** Handle S3 ObjectRemoved events (terminal — returns finalized handler) */
|
|
432
|
+
onObjectRemoved(fn: BucketObjectRemovedFn<C>): BucketHandler<C>;
|
|
433
|
+
/** Finalize as resource-only bucket (no Lambda) */
|
|
434
|
+
build(): BucketHandler<C>;
|
|
435
|
+
}
|
|
586
436
|
/**
|
|
587
437
|
* Define an S3 bucket with optional event handlers.
|
|
588
438
|
*
|
|
589
|
-
*
|
|
590
|
-
* function triggered by S3 event notifications.
|
|
439
|
+
* @see {@link https://effortless-aws.website/use-cases/storage | Storage guide}
|
|
591
440
|
*
|
|
592
|
-
* @example
|
|
593
|
-
* ```typescript
|
|
594
|
-
* export const uploads = defineBucket({
|
|
595
|
-
* prefix: "images/",
|
|
596
|
-
* suffix: ".jpg",
|
|
597
|
-
* onObjectCreated: async ({ event, bucket }) => {
|
|
598
|
-
* const file = await bucket.get(event.key);
|
|
599
|
-
* console.log("New upload:", event.key, file?.body.length);
|
|
600
|
-
* }
|
|
601
|
-
* });
|
|
602
|
-
* ```
|
|
603
|
-
*
|
|
604
|
-
* @example Resource-only bucket (no Lambda)
|
|
605
|
-
* ```typescript
|
|
606
|
-
* export const assets = defineBucket({});
|
|
607
|
-
* ```
|
|
608
|
-
*
|
|
609
|
-
* @example As a dependency
|
|
441
|
+
* @example
|
|
610
442
|
* ```typescript
|
|
611
|
-
* export const
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
* await deps.uploads.put("output.jpg", buffer);
|
|
616
|
-
* return { status: 200, body: "OK" };
|
|
617
|
-
* },
|
|
618
|
-
* });
|
|
443
|
+
* export const uploads = defineBucket({ prefix: "images/", suffix: ".jpg" })
|
|
444
|
+
* .onObjectCreated(async ({ event, bucket }) => {
|
|
445
|
+
* console.log("New upload:", event.key);
|
|
446
|
+
* })
|
|
619
447
|
* ```
|
|
620
448
|
*/
|
|
621
|
-
declare
|
|
449
|
+
declare function defineBucket(): BucketBuilder;
|
|
450
|
+
declare function defineBucket(options: BucketOptions): BucketBuilder;
|
|
622
451
|
|
|
623
452
|
/**
|
|
624
453
|
* Configuration options for defining a mailer (SES email identity)
|
|
@@ -644,6 +473,8 @@ type MailerHandler = {
|
|
|
644
473
|
* On first deploy, DKIM DNS records are printed to the console.
|
|
645
474
|
* Add them to your DNS provider to verify the domain.
|
|
646
475
|
*
|
|
476
|
+
* @see {@link https://effortless-aws.website/use-cases/email | Email guide}
|
|
477
|
+
*
|
|
647
478
|
* @param options - Mailer configuration with the domain to send from
|
|
648
479
|
* @returns Handler object used by the deployment system and as a `deps` value
|
|
649
480
|
*
|
|
@@ -703,7 +534,12 @@ type FifoQueueMessage<T = unknown> = {
|
|
|
703
534
|
*/
|
|
704
535
|
type FifoQueueConfig = {
|
|
705
536
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
706
|
-
lambda?:
|
|
537
|
+
lambda?: {
|
|
538
|
+
memory?: number;
|
|
539
|
+
timeout?: Duration;
|
|
540
|
+
logLevel?: LogLevel;
|
|
541
|
+
permissions?: Permission[];
|
|
542
|
+
};
|
|
707
543
|
/** Number of messages per Lambda invocation (1-10 for FIFO, default: 10) */
|
|
708
544
|
batchSize?: number;
|
|
709
545
|
/** Maximum time to gather messages before invoking (default: 0). Accepts `"5s"`, `"1m"`, etc. */
|
|
@@ -719,26 +555,23 @@ type FifoQueueConfig = {
|
|
|
719
555
|
/** Max number of receives before a message is sent to the dead-letter queue (default: 3) */
|
|
720
556
|
maxReceiveCount?: number;
|
|
721
557
|
};
|
|
722
|
-
/**
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
type SetupFactory$2<C, D, P, S extends string[] | undefined = undefined> = (args: ([D] extends [undefined] ? {} : {
|
|
558
|
+
/** Spread ctx into callback args (empty when no setup) */
|
|
559
|
+
type SpreadCtx$3<C> = [C] extends [undefined] ? {} : C & {};
|
|
560
|
+
/** Setup factory — receives deps/config/files based on what was declared */
|
|
561
|
+
type SetupArgs$3<D, P, HasFiles extends boolean> = ([D] extends [undefined] ? {} : {
|
|
727
562
|
deps: ResolveDeps<D>;
|
|
728
563
|
}) & ([P] extends [undefined] ? {} : {
|
|
729
564
|
config: ResolveConfig<P & {}>;
|
|
730
|
-
}) & (
|
|
565
|
+
}) & (HasFiles extends true ? {
|
|
731
566
|
files: StaticFiles;
|
|
732
|
-
}
|
|
733
|
-
/** Spread ctx into callback args (empty when no setup) */
|
|
734
|
-
type SpreadCtx$2<C> = [C] extends [undefined] ? {} : C & {};
|
|
567
|
+
} : {});
|
|
735
568
|
/**
|
|
736
569
|
* Per-message handler function.
|
|
737
570
|
* Called once per message in the batch. Failures are reported individually.
|
|
738
571
|
*/
|
|
739
572
|
type FifoQueueMessageFn<T = unknown, C = undefined> = (args: {
|
|
740
573
|
message: FifoQueueMessage<T>;
|
|
741
|
-
} & SpreadCtx$
|
|
574
|
+
} & SpreadCtx$3<C>) => Promise<void>;
|
|
742
575
|
/**
|
|
743
576
|
* Batch handler function.
|
|
744
577
|
* Called once with all messages in the batch.
|
|
@@ -746,59 +579,9 @@ type FifoQueueMessageFn<T = unknown, C = undefined> = (args: {
|
|
|
746
579
|
*/
|
|
747
580
|
type FifoQueueBatchFn<T = unknown, C = undefined> = (args: {
|
|
748
581
|
messages: FifoQueueMessage<T>[];
|
|
749
|
-
} & SpreadCtx$
|
|
582
|
+
} & SpreadCtx$3<C>) => Promise<void | {
|
|
750
583
|
failures: string[];
|
|
751
584
|
}>;
|
|
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
585
|
/**
|
|
803
586
|
* Internal handler object created by defineFifoQueue
|
|
804
587
|
* @internal
|
|
@@ -808,7 +591,7 @@ type FifoQueueHandler<T = unknown, C = any> = {
|
|
|
808
591
|
readonly __spec: FifoQueueConfig;
|
|
809
592
|
readonly schema?: (input: unknown) => T;
|
|
810
593
|
readonly onError?: (...args: any[]) => any;
|
|
811
|
-
readonly
|
|
594
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
812
595
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
813
596
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
814
597
|
readonly config?: Record<string, unknown>;
|
|
@@ -816,37 +599,169 @@ type FifoQueueHandler<T = unknown, C = any> = {
|
|
|
816
599
|
readonly onMessage?: (...args: any[]) => any;
|
|
817
600
|
readonly onMessageBatch?: (...args: any[]) => any;
|
|
818
601
|
};
|
|
602
|
+
/** Options passed to `defineFifoQueue()` — static config */
|
|
603
|
+
type FifoQueueOptions<T> = {
|
|
604
|
+
/** Number of messages per Lambda invocation (1-10 for FIFO, default: 10) */
|
|
605
|
+
batchSize?: number;
|
|
606
|
+
/** Maximum time to gather messages before invoking (default: 0) */
|
|
607
|
+
batchWindow?: Duration;
|
|
608
|
+
/** Visibility timeout (default: max of timeout or 30s) */
|
|
609
|
+
visibilityTimeout?: Duration;
|
|
610
|
+
/** Message retention period (default: "4d") */
|
|
611
|
+
retentionPeriod?: Duration;
|
|
612
|
+
/** Delivery delay for all messages in the queue (default: 0) */
|
|
613
|
+
delay?: Duration;
|
|
614
|
+
/** Enable content-based deduplication (default: true) */
|
|
615
|
+
contentBasedDeduplication?: boolean;
|
|
616
|
+
/** Max number of receives before DLQ (default: 3) */
|
|
617
|
+
maxReceiveCount?: number;
|
|
618
|
+
/** Decode/validate function for the message body */
|
|
619
|
+
schema?: (input: unknown) => T;
|
|
620
|
+
};
|
|
621
|
+
interface FifoQueueBuilder<T = unknown, D = undefined, P = undefined, C = undefined, HasFiles extends boolean = false> {
|
|
622
|
+
/** Declare handler dependencies */
|
|
623
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): FifoQueueBuilder<T, D2, P, C, HasFiles>;
|
|
624
|
+
/** Declare SSM secrets */
|
|
625
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): FifoQueueBuilder<T, D, P2, C, HasFiles>;
|
|
626
|
+
/** Include static files in the Lambda bundle. Chainable — call multiple times. */
|
|
627
|
+
include(glob: string): FifoQueueBuilder<T, D, P, C, true>;
|
|
628
|
+
/** Configure Lambda settings only (memory, timeout, permissions, etc.) */
|
|
629
|
+
setup(lambda: LambdaOptions): FifoQueueBuilder<T, D, P, C, HasFiles>;
|
|
630
|
+
/** Initialize shared state on cold start. Receives deps, config, files. */
|
|
631
|
+
setup<C2>(fn: (args: SetupArgs$3<D, P, HasFiles>) => C2 | Promise<C2>): FifoQueueBuilder<T, D, P, C2, HasFiles>;
|
|
632
|
+
/** Initialize shared state on cold start + configure Lambda settings. */
|
|
633
|
+
setup<C2>(fn: (args: SetupArgs$3<D, P, HasFiles>) => C2 | Promise<C2>, lambda: LambdaOptions): FifoQueueBuilder<T, D, P, C2, HasFiles>;
|
|
634
|
+
/** Handle errors thrown by message handlers */
|
|
635
|
+
onError(fn: (args: {
|
|
636
|
+
error: unknown;
|
|
637
|
+
} & SpreadCtx$3<C>) => void): FifoQueueBuilder<T, D, P, C, HasFiles>;
|
|
638
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
639
|
+
onCleanup(fn: (args: SpreadCtx$3<C>) => void | Promise<void>): FifoQueueBuilder<T, D, P, C, HasFiles>;
|
|
640
|
+
/** Per-message handler (terminal — returns finalized handler) */
|
|
641
|
+
onMessage(fn: FifoQueueMessageFn<T, C>): FifoQueueHandler<T, C>;
|
|
642
|
+
/** Batch handler (terminal — returns finalized handler) */
|
|
643
|
+
onMessageBatch(fn: FifoQueueBatchFn<T, C>): FifoQueueHandler<T, C>;
|
|
644
|
+
}
|
|
819
645
|
/**
|
|
820
|
-
* Define a FIFO SQS queue with a Lambda message handler
|
|
646
|
+
* Define a FIFO SQS queue with a Lambda message handler.
|
|
821
647
|
*
|
|
822
|
-
*
|
|
823
|
-
* - SQS FIFO queue (with `.fifo` suffix)
|
|
824
|
-
* - Lambda function triggered by the queue
|
|
825
|
-
* - Event source mapping with partial batch failure support
|
|
648
|
+
* @see {@link https://effortless-aws.website/use-cases/queue | Queue guide}
|
|
826
649
|
*
|
|
827
|
-
* @example
|
|
828
|
-
* ```typescript
|
|
829
|
-
* type OrderEvent = { orderId: string; action: string };
|
|
830
|
-
*
|
|
831
|
-
* export const orderQueue = defineFifoQueue<OrderEvent>({
|
|
832
|
-
* onMessage: async ({ message }) => {
|
|
833
|
-
* console.log("Processing order:", message.body.orderId);
|
|
834
|
-
* }
|
|
835
|
-
* });
|
|
836
|
-
* ```
|
|
837
|
-
*
|
|
838
|
-
* @example Batch processing with schema
|
|
650
|
+
* @example
|
|
839
651
|
* ```typescript
|
|
840
|
-
* export const notifications = defineFifoQueue({
|
|
841
|
-
*
|
|
842
|
-
* batchSize: 5,
|
|
843
|
-
* onMessageBatch: async ({ messages }) => {
|
|
652
|
+
* export const notifications = defineFifoQueue({ batchSize: 5, schema: (i) => NotifSchema.parse(i) })
|
|
653
|
+
* .onMessageBatch(async ({ messages }) => {
|
|
844
654
|
* await sendAll(messages.map(m => m.body));
|
|
845
|
-
* }
|
|
846
|
-
* });
|
|
655
|
+
* })
|
|
847
656
|
* ```
|
|
848
657
|
*/
|
|
849
|
-
declare
|
|
658
|
+
declare function defineFifoQueue<T = unknown>(): FifoQueueBuilder<T>;
|
|
659
|
+
declare function defineFifoQueue<T = unknown>(options: FifoQueueOptions<T>): FifoQueueBuilder<T>;
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Sort key condition for TableClient.query()
|
|
663
|
+
*/
|
|
664
|
+
type SkCondition = string | {
|
|
665
|
+
begins_with: string;
|
|
666
|
+
} | {
|
|
667
|
+
gt: string;
|
|
668
|
+
} | {
|
|
669
|
+
gte: string;
|
|
670
|
+
} | {
|
|
671
|
+
lt: string;
|
|
672
|
+
} | {
|
|
673
|
+
lte: string;
|
|
674
|
+
} | {
|
|
675
|
+
between: [string, string];
|
|
676
|
+
};
|
|
677
|
+
/**
|
|
678
|
+
* Query parameters for TableClient.query()
|
|
679
|
+
*/
|
|
680
|
+
type QueryParams = {
|
|
681
|
+
/** Partition key value */
|
|
682
|
+
pk: string;
|
|
683
|
+
/** Optional sort key condition */
|
|
684
|
+
sk?: SkCondition;
|
|
685
|
+
/** Maximum number of items to return */
|
|
686
|
+
limit?: number;
|
|
687
|
+
/** Sort order (true = ascending, false = descending) */
|
|
688
|
+
scanIndexForward?: boolean;
|
|
689
|
+
};
|
|
690
|
+
/**
|
|
691
|
+
* Query parameters for TableClient.queryByTag() — cross-partition query via GSI.
|
|
692
|
+
* Uses the built-in `tag-pk-index` GSI (tag as partition key, pk as sort key).
|
|
693
|
+
*/
|
|
694
|
+
type QueryByTagParams = {
|
|
695
|
+
/** Tag value (GSI partition key) — the entity type discriminant */
|
|
696
|
+
tag: string;
|
|
697
|
+
/** Optional pk condition (GSI sort key) */
|
|
698
|
+
pk?: SkCondition;
|
|
699
|
+
/** Maximum number of items to return */
|
|
700
|
+
limit?: number;
|
|
701
|
+
/** Sort order (true = ascending, false = descending) */
|
|
702
|
+
scanIndexForward?: boolean;
|
|
703
|
+
};
|
|
704
|
+
/** Extract keys of T whose values are arrays */
|
|
705
|
+
type ArrayKeys<T> = {
|
|
706
|
+
[K in keyof T]: T[K] extends unknown[] ? K : never;
|
|
707
|
+
}[keyof T];
|
|
708
|
+
/** Extract keys of T whose values are numbers */
|
|
709
|
+
type NumberKeys<T> = {
|
|
710
|
+
[K in keyof T]: T[K] extends number ? K : never;
|
|
711
|
+
}[keyof T];
|
|
712
|
+
/**
|
|
713
|
+
* Update actions for TableClient.update()
|
|
714
|
+
*
|
|
715
|
+
* `set`, `append`, and `remove` target fields inside the `data` attribute.
|
|
716
|
+
* Effortless auto-prefixes `data.` in the DynamoDB expression.
|
|
717
|
+
*
|
|
718
|
+
* @typeParam T - Type of the domain data (the `data` attribute)
|
|
719
|
+
*/
|
|
720
|
+
type UpdateActions<T> = {
|
|
721
|
+
/** Set domain data fields (inside `data` attribute) */
|
|
722
|
+
set?: Partial<T>;
|
|
723
|
+
/** Atomically increment/decrement numeric fields inside `data` (use negative values to decrement) */
|
|
724
|
+
increment?: Pick<Partial<T>, NumberKeys<T>>;
|
|
725
|
+
/** Append elements to list fields inside `data` (creates the list if it doesn't exist) */
|
|
726
|
+
append?: Pick<Partial<T>, ArrayKeys<T>>;
|
|
727
|
+
/** Remove fields from `data` */
|
|
728
|
+
remove?: (keyof T)[];
|
|
729
|
+
/** Update the top-level `tag` attribute */
|
|
730
|
+
tag?: string;
|
|
731
|
+
/** Update TTL (set number or null to remove) */
|
|
732
|
+
ttl?: number | null;
|
|
733
|
+
};
|
|
734
|
+
/**
|
|
735
|
+
* Typed DynamoDB table client for single-table design.
|
|
736
|
+
*
|
|
737
|
+
* All items follow the `{ pk, sk, tag, data, ttl? }` structure.
|
|
738
|
+
* `T` is the domain data type stored in the `data` attribute.
|
|
739
|
+
*
|
|
740
|
+
* @typeParam T - Type of the domain data
|
|
741
|
+
*/
|
|
742
|
+
/**
|
|
743
|
+
* Options for `put()` operation.
|
|
744
|
+
*/
|
|
745
|
+
type PutOptions = {
|
|
746
|
+
/** When true, the put fails if an item with the same pk+sk already exists. */
|
|
747
|
+
ifNotExists?: boolean;
|
|
748
|
+
};
|
|
749
|
+
type TableClient<T = Record<string, unknown>> = {
|
|
750
|
+
/** Put an item. Tag is auto-extracted from `data[tagField]`. Use `ifNotExists` to prevent overwrites. */
|
|
751
|
+
put(item: PutInput<T>, options?: PutOptions): Promise<void>;
|
|
752
|
+
/** Get an item by pk + sk */
|
|
753
|
+
get(key: TableKey): Promise<TableItem<T> | undefined>;
|
|
754
|
+
/** Delete an item by pk + sk */
|
|
755
|
+
delete(key: TableKey): Promise<void>;
|
|
756
|
+
/** Update domain data fields without reading the full item */
|
|
757
|
+
update(key: TableKey, actions: UpdateActions<T>): Promise<void>;
|
|
758
|
+
/** Query by partition key with optional sort key condition */
|
|
759
|
+
query(params: QueryParams): Promise<TableItem<T>[]>;
|
|
760
|
+
/** Query by tag across all partitions via GSI (tag-pk-index). */
|
|
761
|
+
queryByTag(params: QueryByTagParams): Promise<TableItem<T>[]>;
|
|
762
|
+
/** The underlying DynamoDB table name */
|
|
763
|
+
tableName: string;
|
|
764
|
+
};
|
|
850
765
|
|
|
851
766
|
/**
|
|
852
767
|
* Options for sending an email via EmailClient.send()
|
|
@@ -924,7 +839,12 @@ type StreamView = "NEW_AND_OLD_IMAGES" | "NEW_IMAGE" | "OLD_IMAGE" | "KEYS_ONLY"
|
|
|
924
839
|
*/
|
|
925
840
|
type TableConfig = {
|
|
926
841
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
927
|
-
lambda?:
|
|
842
|
+
lambda?: {
|
|
843
|
+
memory?: number;
|
|
844
|
+
timeout?: Duration;
|
|
845
|
+
logLevel?: LogLevel;
|
|
846
|
+
permissions?: Permission[];
|
|
847
|
+
};
|
|
928
848
|
/** DynamoDB billing mode (default: "PAY_PER_REQUEST") */
|
|
929
849
|
billingMode?: "PAY_PER_REQUEST" | "PROVISIONED";
|
|
930
850
|
/** Stream view type - what data to include in stream records (default: "NEW_AND_OLD_IMAGES") */
|
|
@@ -968,22 +888,18 @@ type TableRecord<T = Record<string, unknown>> = {
|
|
|
968
888
|
/** Approximate timestamp when the modification occurred */
|
|
969
889
|
timestamp?: number;
|
|
970
890
|
};
|
|
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: {
|
|
891
|
+
/** Setup factory — receives table/deps/config/files based on what was declared */
|
|
892
|
+
type SetupArgs$2<T, D, P, HasFiles extends boolean> = {
|
|
977
893
|
table: TableClient<T>;
|
|
978
894
|
} & ([D] extends [undefined] ? {} : {
|
|
979
895
|
deps: ResolveDeps<D>;
|
|
980
896
|
}) & ([P] extends [undefined] ? {} : {
|
|
981
897
|
config: ResolveConfig<P & {}>;
|
|
982
|
-
}) & (
|
|
898
|
+
}) & (HasFiles extends true ? {
|
|
983
899
|
files: StaticFiles;
|
|
984
|
-
}
|
|
900
|
+
} : {});
|
|
985
901
|
/** Spread ctx into callback args (empty when no setup) */
|
|
986
|
-
type SpreadCtx$
|
|
902
|
+
type SpreadCtx$2<C> = [C] extends [undefined] ? {} : C & {};
|
|
987
903
|
/**
|
|
988
904
|
* Callback function type for processing a single DynamoDB stream record.
|
|
989
905
|
* Receives the current record and the full batch for context.
|
|
@@ -991,7 +907,7 @@ type SpreadCtx$1<C> = [C] extends [undefined] ? {} : C & {};
|
|
|
991
907
|
type TableRecordFn<T = Record<string, unknown>, C = undefined> = (args: {
|
|
992
908
|
record: TableRecord<T>;
|
|
993
909
|
batch: readonly TableRecord<T>[];
|
|
994
|
-
} & SpreadCtx$
|
|
910
|
+
} & SpreadCtx$2<C>) => Promise<void>;
|
|
995
911
|
/**
|
|
996
912
|
* Batch handler function for DynamoDB stream records.
|
|
997
913
|
* Called once with all records in the batch.
|
|
@@ -999,76 +915,13 @@ type TableRecordFn<T = Record<string, unknown>, C = undefined> = (args: {
|
|
|
999
915
|
*/
|
|
1000
916
|
type TableBatchFn<T = Record<string, unknown>, C = undefined> = (args: {
|
|
1001
917
|
records: readonly TableRecord<T>[];
|
|
1002
|
-
} & SpreadCtx$
|
|
918
|
+
} & SpreadCtx$2<C>) => Promise<void | {
|
|
1003
919
|
failures: string[];
|
|
1004
920
|
}>;
|
|
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
|
-
});
|
|
921
|
+
/** Static config extracted by AST (no runtime callbacks) */
|
|
1070
922
|
/**
|
|
1071
|
-
*
|
|
923
|
+
* Handler object created by defineTable.
|
|
924
|
+
* Used by runtime wrappers and as type annotation for circular deps.
|
|
1072
925
|
* @internal
|
|
1073
926
|
*/
|
|
1074
927
|
type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
@@ -1076,7 +929,7 @@ type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
|
1076
929
|
readonly __spec: TableConfig;
|
|
1077
930
|
readonly schema?: (input: unknown) => T;
|
|
1078
931
|
readonly onError?: (...args: any[]) => any;
|
|
1079
|
-
readonly
|
|
932
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
1080
933
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
1081
934
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
1082
935
|
readonly config?: Record<string, unknown>;
|
|
@@ -1084,40 +937,72 @@ type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
|
1084
937
|
readonly onRecord?: (...args: any[]) => any;
|
|
1085
938
|
readonly onRecordBatch?: (...args: any[]) => any;
|
|
1086
939
|
};
|
|
940
|
+
/** Options passed to `defineTable()` — resource config only, no Lambda settings */
|
|
941
|
+
type TableOptions<T> = {
|
|
942
|
+
/** DynamoDB billing mode (default: "PAY_PER_REQUEST") */
|
|
943
|
+
billingMode?: "PAY_PER_REQUEST" | "PROVISIONED";
|
|
944
|
+
/** Stream view type (default: "NEW_AND_OLD_IMAGES") */
|
|
945
|
+
streamView?: StreamView;
|
|
946
|
+
/** Number of records to process in each Lambda invocation (1-10000, default: 100) */
|
|
947
|
+
batchSize?: number;
|
|
948
|
+
/** Maximum time to gather records before invoking (default: "2s") */
|
|
949
|
+
batchWindow?: Duration;
|
|
950
|
+
/** Where to start reading the stream (default: "LATEST") */
|
|
951
|
+
startingPosition?: "LATEST" | "TRIM_HORIZON";
|
|
952
|
+
/** Number of records to process concurrently within a batch (default: 1) */
|
|
953
|
+
concurrency?: number;
|
|
954
|
+
/** Name of the field in `data` that serves as the entity type discriminant (default: "tag") */
|
|
955
|
+
tagField?: Extract<keyof T, string>;
|
|
956
|
+
/** Decode/validate function for the `data` portion of stream records */
|
|
957
|
+
schema?: (input: unknown) => T;
|
|
958
|
+
};
|
|
959
|
+
interface TableBuilder<T = Record<string, unknown>, D = undefined, P = undefined, C = undefined, HasFiles extends boolean = false> {
|
|
960
|
+
/** Declare handler dependencies (tables, queues, buckets, mailers) */
|
|
961
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): TableBuilder<T, D2, P, C, HasFiles>;
|
|
962
|
+
/** Declare SSM secrets */
|
|
963
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): TableBuilder<T, D, P2, C, HasFiles>;
|
|
964
|
+
/** Include static files in the Lambda bundle. Chainable — call multiple times. */
|
|
965
|
+
include(glob: string): TableBuilder<T, D, P, C, true>;
|
|
966
|
+
/** Configure Lambda settings only (memory, timeout, permissions, etc.) */
|
|
967
|
+
setup(lambda: LambdaOptions): TableBuilder<T, D, P, C, HasFiles>;
|
|
968
|
+
/** Initialize shared state on cold start. Receives table (self-client), deps, config, files. */
|
|
969
|
+
setup<C2>(fn: (args: SetupArgs$2<T, D, P, HasFiles>) => C2 | Promise<C2>): TableBuilder<T, D, P, C2, HasFiles>;
|
|
970
|
+
/** Initialize shared state on cold start + configure Lambda settings. */
|
|
971
|
+
setup<C2>(fn: (args: SetupArgs$2<T, D, P, HasFiles>) => C2 | Promise<C2>, lambda: LambdaOptions): TableBuilder<T, D, P, C2, HasFiles>;
|
|
972
|
+
/** Handle errors thrown by onRecord/onRecordBatch */
|
|
973
|
+
onError(fn: (args: {
|
|
974
|
+
error: unknown;
|
|
975
|
+
} & SpreadCtx$2<C>) => void): TableBuilder<T, D, P, C, HasFiles>;
|
|
976
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
977
|
+
onCleanup(fn: (args: SpreadCtx$2<C>) => void | Promise<void>): TableBuilder<T, D, P, C, HasFiles>;
|
|
978
|
+
/** Per-record stream handler (terminal — returns finalized handler) */
|
|
979
|
+
onRecord(fn: TableRecordFn<T, C>): TableHandler<T, C>;
|
|
980
|
+
/** Batch stream handler (terminal — returns finalized handler) */
|
|
981
|
+
onRecordBatch(fn: TableBatchFn<T, C>): TableHandler<T, C>;
|
|
982
|
+
/** Finalize as resource-only table (no Lambda) */
|
|
983
|
+
build(): TableHandler<T, C>;
|
|
984
|
+
}
|
|
1087
985
|
/**
|
|
1088
986
|
* Define a DynamoDB table with optional stream handler (single-table design).
|
|
1089
987
|
*
|
|
1090
988
|
* Creates a table with fixed key schema: `pk (S)` + `sk (S)`, plus `tag (S)`,
|
|
1091
989
|
* `data (M)`, and `ttl (N)` attributes. TTL is always enabled.
|
|
1092
990
|
*
|
|
1093
|
-
* @
|
|
991
|
+
* @see {@link https://effortless-aws.website/use-cases/database | Database guide}
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
1094
994
|
* ```typescript
|
|
1095
|
-
* export const orders = defineTable<OrderData>()
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
* setup: ({ table }) => ({ table }),
|
|
1099
|
-
* onRecord: async ({ record, batch, table }) => {
|
|
995
|
+
* export const orders = defineTable<OrderData>({ batchSize: 10, concurrency: 5 })
|
|
996
|
+
* .setup(({ table }) => ({ table }))
|
|
997
|
+
* .onRecord(async ({ record, table }) => {
|
|
1100
998
|
* if (record.eventName === "INSERT") {
|
|
1101
999
|
* console.log("New order:", record.new?.data);
|
|
1102
1000
|
* }
|
|
1103
|
-
* }
|
|
1104
|
-
* });
|
|
1105
|
-
* ```
|
|
1106
|
-
*
|
|
1107
|
-
* @example Table with runtime validation
|
|
1108
|
-
* ```typescript
|
|
1109
|
-
* export const orders = defineTable<OrderData>()({
|
|
1110
|
-
* schema: (input) => OrderSchema.parse(input),
|
|
1111
|
-
* onRecord: async ({ record }) => { ... }
|
|
1112
|
-
* });
|
|
1113
|
-
* ```
|
|
1114
|
-
*
|
|
1115
|
-
* @example Table only (no Lambda)
|
|
1116
|
-
* ```typescript
|
|
1117
|
-
* export const users = defineTable()({});
|
|
1001
|
+
* })
|
|
1118
1002
|
* ```
|
|
1119
1003
|
*/
|
|
1120
|
-
declare
|
|
1004
|
+
declare function defineTable<T = Record<string, unknown>>(): TableBuilder<T>;
|
|
1005
|
+
declare function defineTable<T = Record<string, unknown>>(options: TableOptions<T>): TableBuilder<T>;
|
|
1121
1006
|
|
|
1122
1007
|
/**
|
|
1123
1008
|
* Configuration for deploying an SSR framework (Nuxt, Astro, etc.)
|
|
@@ -1161,18 +1046,10 @@ type AppHandler = {
|
|
|
1161
1046
|
*
|
|
1162
1047
|
* For static-only sites (no SSR), use {@link defineStaticSite} instead.
|
|
1163
1048
|
*
|
|
1049
|
+
* @see {@link https://effortless-aws.website/use-cases/web-app | Web app guide}
|
|
1050
|
+
*
|
|
1164
1051
|
* @param options - App configuration: server directory, assets directory, optional build command
|
|
1165
1052
|
* @returns Handler object used by the deployment system
|
|
1166
|
-
*
|
|
1167
|
-
* @example Nuxt SSR
|
|
1168
|
-
* ```typescript
|
|
1169
|
-
* export const app = defineApp({
|
|
1170
|
-
* build: "nuxt build",
|
|
1171
|
-
* server: ".output/server",
|
|
1172
|
-
* assets: ".output/public",
|
|
1173
|
-
* lambda: { memory: 1024 },
|
|
1174
|
-
* });
|
|
1175
|
-
* ```
|
|
1176
1053
|
*/
|
|
1177
1054
|
declare const defineApp: () => (options: AppConfig) => AppHandler;
|
|
1178
1055
|
|
|
@@ -1249,26 +1126,10 @@ type StaticSiteHandler = {
|
|
|
1249
1126
|
/**
|
|
1250
1127
|
* Deploy a static site via S3 + CloudFront CDN.
|
|
1251
1128
|
*
|
|
1129
|
+
* @see {@link https://effortless-aws.website/use-cases/web-app | Web app guide}
|
|
1130
|
+
*
|
|
1252
1131
|
* @param options - Static site configuration: directory, optional SPA mode, build command
|
|
1253
1132
|
* @returns Handler object used by the deployment system
|
|
1254
|
-
*
|
|
1255
|
-
* @example Documentation site
|
|
1256
|
-
* ```typescript
|
|
1257
|
-
* export const docs = defineStaticSite({
|
|
1258
|
-
* dir: "dist",
|
|
1259
|
-
* build: "npx astro build",
|
|
1260
|
-
* });
|
|
1261
|
-
* ```
|
|
1262
|
-
*
|
|
1263
|
-
* @example SPA with client-side routing
|
|
1264
|
-
* ```typescript
|
|
1265
|
-
* export const app = defineStaticSite({
|
|
1266
|
-
* dir: "dist",
|
|
1267
|
-
* spa: true,
|
|
1268
|
-
* build: "npm run build",
|
|
1269
|
-
* });
|
|
1270
|
-
* ```
|
|
1271
|
-
*
|
|
1272
1133
|
*/
|
|
1273
1134
|
declare const defineStaticSite: () => (options: StaticSiteConfig) => StaticSiteHandler;
|
|
1274
1135
|
|
|
@@ -1330,7 +1191,11 @@ type ExtractAuth<C> = C extends {
|
|
|
1330
1191
|
auth: ApiAuthConfig<infer A>;
|
|
1331
1192
|
} ? A : undefined;
|
|
1332
1193
|
/** Property names reserved by the framework — cannot be used in setup return */
|
|
1333
|
-
type ReservedKeys = 'req' | 'input' | 'stream';
|
|
1194
|
+
type ReservedKeys = 'req' | 'input' | 'stream' | 'ok' | 'fail';
|
|
1195
|
+
/** Success response helper: `ok({ data })` → `{ status: 200, body: { data } }` */
|
|
1196
|
+
type OkHelper = (body?: unknown, status?: number) => HttpResponse;
|
|
1197
|
+
/** Error response helper: `fail("message")` → `{ status: 400, body: { error: "message" } }` */
|
|
1198
|
+
type FailHelper = (message: string, status?: number) => HttpResponse;
|
|
1334
1199
|
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
1335
1200
|
/** Parsed route definition stored at runtime */
|
|
1336
1201
|
type RouteEntry = {
|
|
@@ -1340,36 +1205,40 @@ type RouteEntry = {
|
|
|
1340
1205
|
public?: boolean;
|
|
1341
1206
|
};
|
|
1342
1207
|
/** Spread ctx into route args: Omit auth config, add AuthHelpers if present */
|
|
1343
|
-
type SpreadCtx<C> = ([C] extends [undefined] ? {} : Omit<C & {}, 'auth'>) & ([ExtractAuth<C>] extends [undefined] ? {} : {
|
|
1208
|
+
type SpreadCtx$1<C> = ([C] extends [undefined] ? {} : Omit<C & {}, 'auth'>) & ([ExtractAuth<C>] extends [undefined] ? {} : {
|
|
1344
1209
|
auth: AuthHelpers<ExtractAuth<C>>;
|
|
1345
1210
|
});
|
|
1346
1211
|
/** Callback args available inside each route — ctx is spread into args */
|
|
1347
|
-
type RouteArgs<C, ST> = SpreadCtx<C> & {
|
|
1212
|
+
type RouteArgs<C, ST> = SpreadCtx$1<C> & {
|
|
1348
1213
|
req: HttpRequest;
|
|
1349
1214
|
input: unknown;
|
|
1215
|
+
ok: OkHelper;
|
|
1216
|
+
fail: FailHelper;
|
|
1350
1217
|
} & ([ST] extends [true] ? {
|
|
1351
1218
|
stream: ResponseStream;
|
|
1352
1219
|
} : {});
|
|
1353
|
-
/** Route
|
|
1354
|
-
type
|
|
1355
|
-
|
|
1356
|
-
|
|
1220
|
+
/** Route handler function */
|
|
1221
|
+
type RouteHandler<C, ST> = (args: RouteArgs<C, ST>) => Promise<HttpResponse | void> | HttpResponse | void;
|
|
1222
|
+
/** Route options (e.g. public) */
|
|
1223
|
+
type RouteOptions = {
|
|
1357
1224
|
public?: boolean;
|
|
1358
1225
|
};
|
|
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: {
|
|
1226
|
+
/** Setup factory — receives deps/config/files/enableAuth based on what was declared */
|
|
1227
|
+
type SetupArgs$1<D, P, HasFiles extends boolean> = {
|
|
1365
1228
|
enableAuth: EnableAuth;
|
|
1229
|
+
ok: OkHelper;
|
|
1230
|
+
fail: FailHelper;
|
|
1366
1231
|
} & ([D] extends [undefined] ? {} : {
|
|
1367
1232
|
deps: ResolveDeps<D>;
|
|
1368
1233
|
}) & ([P] extends [undefined] ? {} : {
|
|
1369
1234
|
config: ResolveConfig<P & {}>;
|
|
1370
|
-
}) & (
|
|
1235
|
+
}) & (HasFiles extends true ? {
|
|
1371
1236
|
files: StaticFiles;
|
|
1372
|
-
}
|
|
1237
|
+
} : {});
|
|
1238
|
+
/** Validate that setup return type does not use reserved property names */
|
|
1239
|
+
type ValidateSetupReturn<C> = C & {
|
|
1240
|
+
[K in ReservedKeys]?: never;
|
|
1241
|
+
};
|
|
1373
1242
|
/** Static config extracted by AST (no runtime callbacks) */
|
|
1374
1243
|
type ApiConfig = {
|
|
1375
1244
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
@@ -1379,79 +1248,212 @@ type ApiConfig = {
|
|
|
1379
1248
|
/** Enable response streaming. When true, the Lambda Function URL uses RESPONSE_STREAM invoke mode. */
|
|
1380
1249
|
stream?: boolean;
|
|
1381
1250
|
};
|
|
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
1251
|
/** Internal handler object created by defineApi */
|
|
1408
1252
|
type ApiHandler<C = undefined> = {
|
|
1409
1253
|
readonly __brand: "effortless-api";
|
|
1410
1254
|
readonly __spec: ApiConfig;
|
|
1411
1255
|
readonly onError?: (...args: any[]) => any;
|
|
1412
|
-
readonly
|
|
1256
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
1413
1257
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
1414
1258
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
1415
1259
|
readonly config?: Record<string, unknown>;
|
|
1416
1260
|
readonly static?: string[];
|
|
1417
1261
|
readonly routes?: RouteEntry[];
|
|
1418
1262
|
};
|
|
1263
|
+
/** Options passed to `defineApi()` */
|
|
1264
|
+
type ApiOptions = {
|
|
1265
|
+
/** Base path prefix for all routes (e.g., "/api") */
|
|
1266
|
+
basePath: `/${string}`;
|
|
1267
|
+
/** Enable response streaming. When true, routes receive a `stream` arg for SSE. */
|
|
1268
|
+
stream?: boolean;
|
|
1269
|
+
};
|
|
1270
|
+
/**
|
|
1271
|
+
* Finalized API handler with route-adding methods.
|
|
1272
|
+
* Has `__brand` so CLI discovers it. Each `.get()/.post()` adds a route and returns self.
|
|
1273
|
+
*/
|
|
1274
|
+
interface ApiRoutes<C = undefined, ST extends boolean = false> extends ApiHandler<C> {
|
|
1275
|
+
get(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1276
|
+
post(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1277
|
+
put(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1278
|
+
patch(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1279
|
+
delete(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1280
|
+
}
|
|
1419
1281
|
/**
|
|
1420
|
-
*
|
|
1282
|
+
* Builder interface for defining API handlers.
|
|
1421
1283
|
*
|
|
1422
|
-
*
|
|
1423
|
-
*
|
|
1424
|
-
|
|
1284
|
+
* Each method sets exactly one generic, so inference happens one step at a time.
|
|
1285
|
+
* This prevents cascading type errors when one property has a mistake.
|
|
1286
|
+
*/
|
|
1287
|
+
interface ApiBuilder<D = undefined, P = undefined, C = undefined, ST extends boolean = false, HasFiles extends boolean = false> {
|
|
1288
|
+
/** Declare handler dependencies (tables, queues, buckets, mailers) */
|
|
1289
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): ApiBuilder<D2, P, C, ST, HasFiles>;
|
|
1290
|
+
/** Declare SSM secrets */
|
|
1291
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): ApiBuilder<D, P2, C, ST, HasFiles>;
|
|
1292
|
+
/** Include static files by glob pattern */
|
|
1293
|
+
include(glob: string): ApiBuilder<D, P, C, ST, true>;
|
|
1294
|
+
/** Configure Lambda settings only (no init function) */
|
|
1295
|
+
setup(lambda: LambdaOptions): ApiBuilder<D, P, C, ST, HasFiles>;
|
|
1296
|
+
/** Initialize shared state on cold start. Receives deps/config/files based on what was declared. */
|
|
1297
|
+
setup<C2>(fn: (args: SetupArgs$1<D, P, HasFiles>) => ValidateSetupReturn<C2> | Promise<ValidateSetupReturn<C2>>): ApiBuilder<D, P, C2, ST, HasFiles>;
|
|
1298
|
+
/** Initialize shared state on cold start with Lambda config. */
|
|
1299
|
+
setup<C2>(fn: (args: SetupArgs$1<D, P, HasFiles>) => ValidateSetupReturn<C2> | Promise<ValidateSetupReturn<C2>>, lambda: LambdaOptions): ApiBuilder<D, P, C2, ST, HasFiles>;
|
|
1300
|
+
/** Handle errors thrown by routes */
|
|
1301
|
+
onError(fn: (args: {
|
|
1302
|
+
error: unknown;
|
|
1303
|
+
req: HttpRequest;
|
|
1304
|
+
ok: OkHelper;
|
|
1305
|
+
fail: FailHelper;
|
|
1306
|
+
} & SpreadCtx$1<C>) => HttpResponse): ApiBuilder<D, P, C, ST, HasFiles>;
|
|
1307
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
1308
|
+
onCleanup(fn: (args: SpreadCtx$1<C>) => void | Promise<void>): ApiBuilder<D, P, C, ST, HasFiles>;
|
|
1309
|
+
/** Add a GET route (terminal — returns finalized handler with route methods) */
|
|
1310
|
+
get(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1311
|
+
/** Add a POST route (terminal) */
|
|
1312
|
+
post(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1313
|
+
/** Add a PUT route (terminal) */
|
|
1314
|
+
put(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1315
|
+
/** Add a PATCH route (terminal) */
|
|
1316
|
+
patch(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1317
|
+
/** Add a DELETE route (terminal) */
|
|
1318
|
+
delete(path: `/${string}`, handler: RouteHandler<C, ST>, options?: RouteOptions): ApiRoutes<C, ST>;
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Define an API with typed routes using a builder pattern.
|
|
1322
|
+
*
|
|
1323
|
+
* @see {@link https://effortless-aws.website/use-cases/http-api | HTTP API guide}
|
|
1425
1324
|
*
|
|
1426
1325
|
* @example
|
|
1427
1326
|
* ```typescript
|
|
1428
|
-
* export
|
|
1429
|
-
*
|
|
1430
|
-
*
|
|
1431
|
-
* setup
|
|
1327
|
+
* export const api = defineApi({ basePath: "/api", timeout: "30s" })
|
|
1328
|
+
* .deps(() => ({ users }))
|
|
1329
|
+
* .config(({ defineSecret }) => ({ dbUrl: defineSecret() }))
|
|
1330
|
+
* .setup(async ({ deps, config, enableAuth }) => ({
|
|
1432
1331
|
* users: deps.users,
|
|
1433
|
-
* auth: {
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
1436
|
-
*
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
*
|
|
1444
|
-
*
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1332
|
+
* auth: enableAuth<Session>({ secret: config.dbUrl }),
|
|
1333
|
+
* }))
|
|
1334
|
+
* .onError(({ error, fail }) => fail(String(error), 500))
|
|
1335
|
+
* .get("/me", async ({ users, auth, ok }) => ok(auth.session))
|
|
1336
|
+
* .post("/login", async ({ auth, ok }) => ok(await auth.createSession()), { public: true })
|
|
1337
|
+
* ```
|
|
1338
|
+
*/
|
|
1339
|
+
declare function defineApi<const O extends ApiOptions>(options: O): ApiBuilder<undefined, undefined, undefined, O["stream"] extends true ? true : false, false>;
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* All IANA time zones.
|
|
1343
|
+
* Generated from Intl.supportedValuesOf("timeZone") on Node.js 22.
|
|
1344
|
+
*/
|
|
1345
|
+
type Timezone = "UTC" | "Africa/Abidjan" | "Africa/Accra" | "Africa/Addis_Ababa" | "Africa/Algiers" | "Africa/Asmera" | "Africa/Bamako" | "Africa/Bangui" | "Africa/Banjul" | "Africa/Bissau" | "Africa/Blantyre" | "Africa/Brazzaville" | "Africa/Bujumbura" | "Africa/Cairo" | "Africa/Casablanca" | "Africa/Ceuta" | "Africa/Conakry" | "Africa/Dakar" | "Africa/Dar_es_Salaam" | "Africa/Djibouti" | "Africa/Douala" | "Africa/El_Aaiun" | "Africa/Freetown" | "Africa/Gaborone" | "Africa/Harare" | "Africa/Johannesburg" | "Africa/Juba" | "Africa/Kampala" | "Africa/Khartoum" | "Africa/Kigali" | "Africa/Kinshasa" | "Africa/Lagos" | "Africa/Libreville" | "Africa/Lome" | "Africa/Luanda" | "Africa/Lubumbashi" | "Africa/Lusaka" | "Africa/Malabo" | "Africa/Maputo" | "Africa/Maseru" | "Africa/Mbabane" | "Africa/Mogadishu" | "Africa/Monrovia" | "Africa/Nairobi" | "Africa/Ndjamena" | "Africa/Niamey" | "Africa/Nouakchott" | "Africa/Ouagadougou" | "Africa/Porto-Novo" | "Africa/Sao_Tome" | "Africa/Tripoli" | "Africa/Tunis" | "Africa/Windhoek" | "America/Adak" | "America/Anchorage" | "America/Anguilla" | "America/Antigua" | "America/Araguaina" | "America/Argentina/La_Rioja" | "America/Argentina/Rio_Gallegos" | "America/Argentina/Salta" | "America/Argentina/San_Juan" | "America/Argentina/San_Luis" | "America/Argentina/Tucuman" | "America/Argentina/Ushuaia" | "America/Aruba" | "America/Asuncion" | "America/Bahia" | "America/Bahia_Banderas" | "America/Barbados" | "America/Belem" | "America/Belize" | "America/Blanc-Sablon" | "America/Boa_Vista" | "America/Bogota" | "America/Boise" | "America/Buenos_Aires" | "America/Cambridge_Bay" | "America/Campo_Grande" | "America/Cancun" | "America/Caracas" | "America/Catamarca" | "America/Cayenne" | "America/Cayman" | "America/Chicago" | "America/Chihuahua" | "America/Ciudad_Juarez" | "America/Coral_Harbour" | "America/Cordoba" | "America/Costa_Rica" | "America/Coyhaique" | "America/Creston" | "America/Cuiaba" | "America/Curacao" | "America/Danmarkshavn" | "America/Dawson" | "America/Dawson_Creek" | "America/Denver" | "America/Detroit" | "America/Dominica" | "America/Edmonton" | "America/Eirunepe" | "America/El_Salvador" | "America/Fort_Nelson" | "America/Fortaleza" | "America/Glace_Bay" | "America/Godthab" | "America/Goose_Bay" | "America/Grand_Turk" | "America/Grenada" | "America/Guadeloupe" | "America/Guatemala" | "America/Guayaquil" | "America/Guyana" | "America/Halifax" | "America/Havana" | "America/Hermosillo" | "America/Indiana/Knox" | "America/Indiana/Marengo" | "America/Indiana/Petersburg" | "America/Indiana/Tell_City" | "America/Indiana/Vevay" | "America/Indiana/Vincennes" | "America/Indiana/Winamac" | "America/Indianapolis" | "America/Inuvik" | "America/Iqaluit" | "America/Jamaica" | "America/Jujuy" | "America/Juneau" | "America/Kentucky/Monticello" | "America/Kralendijk" | "America/La_Paz" | "America/Lima" | "America/Los_Angeles" | "America/Louisville" | "America/Lower_Princes" | "America/Maceio" | "America/Managua" | "America/Manaus" | "America/Marigot" | "America/Martinique" | "America/Matamoros" | "America/Mazatlan" | "America/Mendoza" | "America/Menominee" | "America/Merida" | "America/Metlakatla" | "America/Mexico_City" | "America/Miquelon" | "America/Moncton" | "America/Monterrey" | "America/Montevideo" | "America/Montserrat" | "America/Nassau" | "America/New_York" | "America/Nome" | "America/Noronha" | "America/North_Dakota/Beulah" | "America/North_Dakota/Center" | "America/North_Dakota/New_Salem" | "America/Ojinaga" | "America/Panama" | "America/Paramaribo" | "America/Phoenix" | "America/Port-au-Prince" | "America/Port_of_Spain" | "America/Porto_Velho" | "America/Puerto_Rico" | "America/Punta_Arenas" | "America/Rankin_Inlet" | "America/Recife" | "America/Regina" | "America/Resolute" | "America/Rio_Branco" | "America/Santarem" | "America/Santiago" | "America/Santo_Domingo" | "America/Sao_Paulo" | "America/Scoresbysund" | "America/Sitka" | "America/St_Barthelemy" | "America/St_Johns" | "America/St_Kitts" | "America/St_Lucia" | "America/St_Thomas" | "America/St_Vincent" | "America/Swift_Current" | "America/Tegucigalpa" | "America/Thule" | "America/Tijuana" | "America/Toronto" | "America/Tortola" | "America/Vancouver" | "America/Whitehorse" | "America/Winnipeg" | "America/Yakutat" | "Antarctica/Casey" | "Antarctica/Davis" | "Antarctica/DumontDUrville" | "Antarctica/Macquarie" | "Antarctica/Mawson" | "Antarctica/McMurdo" | "Antarctica/Palmer" | "Antarctica/Rothera" | "Antarctica/Syowa" | "Antarctica/Troll" | "Antarctica/Vostok" | "Arctic/Longyearbyen" | "Asia/Aden" | "Asia/Almaty" | "Asia/Amman" | "Asia/Anadyr" | "Asia/Aqtau" | "Asia/Aqtobe" | "Asia/Ashgabat" | "Asia/Atyrau" | "Asia/Baghdad" | "Asia/Bahrain" | "Asia/Baku" | "Asia/Bangkok" | "Asia/Barnaul" | "Asia/Beirut" | "Asia/Bishkek" | "Asia/Brunei" | "Asia/Calcutta" | "Asia/Chita" | "Asia/Colombo" | "Asia/Damascus" | "Asia/Dhaka" | "Asia/Dili" | "Asia/Dubai" | "Asia/Dushanbe" | "Asia/Famagusta" | "Asia/Gaza" | "Asia/Hebron" | "Asia/Hong_Kong" | "Asia/Hovd" | "Asia/Irkutsk" | "Asia/Jakarta" | "Asia/Jayapura" | "Asia/Jerusalem" | "Asia/Kabul" | "Asia/Kamchatka" | "Asia/Karachi" | "Asia/Katmandu" | "Asia/Khandyga" | "Asia/Krasnoyarsk" | "Asia/Kuala_Lumpur" | "Asia/Kuching" | "Asia/Kuwait" | "Asia/Macau" | "Asia/Magadan" | "Asia/Makassar" | "Asia/Manila" | "Asia/Muscat" | "Asia/Nicosia" | "Asia/Novokuznetsk" | "Asia/Novosibirsk" | "Asia/Omsk" | "Asia/Oral" | "Asia/Phnom_Penh" | "Asia/Pontianak" | "Asia/Pyongyang" | "Asia/Qatar" | "Asia/Qostanay" | "Asia/Qyzylorda" | "Asia/Rangoon" | "Asia/Riyadh" | "Asia/Saigon" | "Asia/Sakhalin" | "Asia/Samarkand" | "Asia/Seoul" | "Asia/Shanghai" | "Asia/Singapore" | "Asia/Srednekolymsk" | "Asia/Taipei" | "Asia/Tashkent" | "Asia/Tbilisi" | "Asia/Tehran" | "Asia/Thimphu" | "Asia/Tokyo" | "Asia/Tomsk" | "Asia/Ulaanbaatar" | "Asia/Urumqi" | "Asia/Ust-Nera" | "Asia/Vientiane" | "Asia/Vladivostok" | "Asia/Yakutsk" | "Asia/Yekaterinburg" | "Asia/Yerevan" | "Atlantic/Azores" | "Atlantic/Bermuda" | "Atlantic/Canary" | "Atlantic/Cape_Verde" | "Atlantic/Faeroe" | "Atlantic/Madeira" | "Atlantic/Reykjavik" | "Atlantic/South_Georgia" | "Atlantic/St_Helena" | "Atlantic/Stanley" | "Australia/Adelaide" | "Australia/Brisbane" | "Australia/Broken_Hill" | "Australia/Darwin" | "Australia/Eucla" | "Australia/Hobart" | "Australia/Lindeman" | "Australia/Lord_Howe" | "Australia/Melbourne" | "Australia/Perth" | "Australia/Sydney" | "Europe/Amsterdam" | "Europe/Andorra" | "Europe/Astrakhan" | "Europe/Athens" | "Europe/Belgrade" | "Europe/Berlin" | "Europe/Bratislava" | "Europe/Brussels" | "Europe/Bucharest" | "Europe/Budapest" | "Europe/Busingen" | "Europe/Chisinau" | "Europe/Copenhagen" | "Europe/Dublin" | "Europe/Gibraltar" | "Europe/Guernsey" | "Europe/Helsinki" | "Europe/Isle_of_Man" | "Europe/Istanbul" | "Europe/Jersey" | "Europe/Kaliningrad" | "Europe/Kiev" | "Europe/Kirov" | "Europe/Lisbon" | "Europe/Ljubljana" | "Europe/London" | "Europe/Luxembourg" | "Europe/Madrid" | "Europe/Malta" | "Europe/Mariehamn" | "Europe/Minsk" | "Europe/Monaco" | "Europe/Moscow" | "Europe/Oslo" | "Europe/Paris" | "Europe/Podgorica" | "Europe/Prague" | "Europe/Riga" | "Europe/Rome" | "Europe/Samara" | "Europe/San_Marino" | "Europe/Sarajevo" | "Europe/Saratov" | "Europe/Simferopol" | "Europe/Skopje" | "Europe/Sofia" | "Europe/Stockholm" | "Europe/Tallinn" | "Europe/Tirane" | "Europe/Ulyanovsk" | "Europe/Vaduz" | "Europe/Vatican" | "Europe/Vienna" | "Europe/Vilnius" | "Europe/Volgograd" | "Europe/Warsaw" | "Europe/Zagreb" | "Europe/Zurich" | "Indian/Antananarivo" | "Indian/Chagos" | "Indian/Christmas" | "Indian/Cocos" | "Indian/Comoro" | "Indian/Kerguelen" | "Indian/Mahe" | "Indian/Maldives" | "Indian/Mauritius" | "Indian/Mayotte" | "Indian/Reunion" | "Pacific/Apia" | "Pacific/Auckland" | "Pacific/Bougainville" | "Pacific/Chatham" | "Pacific/Easter" | "Pacific/Efate" | "Pacific/Enderbury" | "Pacific/Fakaofo" | "Pacific/Fiji" | "Pacific/Funafuti" | "Pacific/Galapagos" | "Pacific/Gambier" | "Pacific/Guadalcanal" | "Pacific/Guam" | "Pacific/Honolulu" | "Pacific/Kiritimati" | "Pacific/Kosrae" | "Pacific/Kwajalein" | "Pacific/Majuro" | "Pacific/Marquesas" | "Pacific/Midway" | "Pacific/Nauru" | "Pacific/Niue" | "Pacific/Norfolk" | "Pacific/Noumea" | "Pacific/Pago_Pago" | "Pacific/Palau" | "Pacific/Pitcairn" | "Pacific/Ponape" | "Pacific/Port_Moresby" | "Pacific/Rarotonga" | "Pacific/Saipan" | "Pacific/Tahiti" | "Pacific/Tarawa" | "Pacific/Tongatapu" | "Pacific/Truk" | "Pacific/Wake" | "Pacific/Wallis";
|
|
1346
|
+
|
|
1347
|
+
/** Singular/plural unit for rate expressions */
|
|
1348
|
+
type RateUnit = "minute" | "minutes" | "hour" | "hours" | "day" | "days";
|
|
1349
|
+
/**
|
|
1350
|
+
* Rate expression: `rate(1 hour)`, `rate(5 minutes)`, `rate(2 days)`
|
|
1351
|
+
*
|
|
1352
|
+
* Strictly typed — autocomplete and compile-time validation for unit.
|
|
1353
|
+
*/
|
|
1354
|
+
type RateExpression = `rate(${number} ${RateUnit})`;
|
|
1355
|
+
/**
|
|
1356
|
+
* Cron expression: `cron(min hour dom month dow year)`
|
|
1357
|
+
*
|
|
1358
|
+
* Not deeply typed (too combinatorial for TS), but the `cron(...)` wrapper is enforced.
|
|
1359
|
+
*
|
|
1360
|
+
* @example
|
|
1361
|
+
* ```
|
|
1362
|
+
* "cron(0 9 * * ? *)" // daily at 9:00 UTC
|
|
1363
|
+
* "cron(0 9 ? * MON-FRI *)" // weekdays at 9:00
|
|
1364
|
+
* "cron(0/15 * * * ? *)" // every 15 minutes
|
|
1365
|
+
* ```
|
|
1366
|
+
*/
|
|
1367
|
+
type CronExpression = `cron(${string})`;
|
|
1368
|
+
/**
|
|
1369
|
+
* EventBridge Scheduler schedule expression.
|
|
1370
|
+
*
|
|
1371
|
+
* - **Rate**: `"rate(5 minutes)"`, `"rate(1 hour)"`, `"rate(1 day)"` — strictly typed units
|
|
1372
|
+
* - **Cron**: `"cron(0 9 * * ? *)"` — 6 fields: min hour dom month dow year
|
|
1373
|
+
*/
|
|
1374
|
+
type ScheduleExpression = RateExpression | CronExpression;
|
|
1375
|
+
/** Static config extracted at deploy time */
|
|
1376
|
+
type CronConfig = {
|
|
1377
|
+
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
1378
|
+
lambda?: LambdaWithPermissions;
|
|
1379
|
+
/** EventBridge Scheduler schedule expression */
|
|
1380
|
+
schedule: ScheduleExpression;
|
|
1381
|
+
/** IANA timezone for the schedule (default: UTC) */
|
|
1382
|
+
timezone?: Timezone;
|
|
1383
|
+
};
|
|
1384
|
+
/** Setup factory — receives deps/config/files based on what was declared */
|
|
1385
|
+
type SetupArgs<D, P, HasFiles extends boolean> = ([D] extends [undefined] ? {} : {
|
|
1386
|
+
deps: ResolveDeps<D>;
|
|
1387
|
+
}) & ([P] extends [undefined] ? {} : {
|
|
1388
|
+
config: ResolveConfig<P & {}>;
|
|
1389
|
+
}) & (HasFiles extends true ? {
|
|
1390
|
+
files: StaticFiles;
|
|
1391
|
+
} : {});
|
|
1392
|
+
/** Spread ctx into callback args (empty when no setup) */
|
|
1393
|
+
type SpreadCtx<C> = [C] extends [undefined] ? {} : C & {};
|
|
1394
|
+
/** Callback function for cron tick */
|
|
1395
|
+
type CronTickFn<C = undefined> = (args: SpreadCtx<C>) => Promise<void> | void;
|
|
1396
|
+
/**
|
|
1397
|
+
* Handler object created by defineCron.
|
|
1398
|
+
* @internal
|
|
1399
|
+
*/
|
|
1400
|
+
type CronHandler<C = any> = {
|
|
1401
|
+
readonly __brand: "effortless-cron";
|
|
1402
|
+
readonly __spec: CronConfig;
|
|
1403
|
+
readonly onError?: (...args: any[]) => any;
|
|
1404
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
1405
|
+
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
1406
|
+
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
1407
|
+
readonly config?: Record<string, unknown>;
|
|
1408
|
+
readonly static?: string[];
|
|
1409
|
+
readonly onTick?: (...args: any[]) => any;
|
|
1410
|
+
};
|
|
1411
|
+
/** Options passed to `defineCron()` — resource config only */
|
|
1412
|
+
type CronOptions = {
|
|
1413
|
+
/** EventBridge Scheduler schedule expression: `"rate(5 minutes)"` or `"cron(0 9 * * ? *)"` */
|
|
1414
|
+
schedule: ScheduleExpression;
|
|
1415
|
+
/** IANA timezone for the schedule (default: UTC). Full autocomplete for all timezones. */
|
|
1416
|
+
timezone?: Timezone;
|
|
1417
|
+
};
|
|
1418
|
+
interface CronBuilder<D = undefined, P = undefined, C = undefined, HasFiles extends boolean = false> {
|
|
1419
|
+
/** Declare handler dependencies (tables, queues, buckets, mailers) */
|
|
1420
|
+
deps<D2 extends Record<string, AnyDepHandler>>(fn: () => D2): CronBuilder<D2, P, C, HasFiles>;
|
|
1421
|
+
/** Declare SSM secrets */
|
|
1422
|
+
config<P2 extends Record<string, AnySecretRef>>(fn: ConfigFactory<P2>): CronBuilder<D, P2, C, HasFiles>;
|
|
1423
|
+
/** Include static files in the Lambda bundle. Chainable — call multiple times. */
|
|
1424
|
+
include(glob: string): CronBuilder<D, P, C, true>;
|
|
1425
|
+
/** Configure Lambda settings only (memory, timeout, permissions, logLevel) */
|
|
1426
|
+
setup(lambda: LambdaOptions): CronBuilder<D, P, C, HasFiles>;
|
|
1427
|
+
/** Initialize shared state on cold start. Receives deps, config, files. */
|
|
1428
|
+
setup<C2>(fn: (args: SetupArgs<D, P, HasFiles>) => C2 | Promise<C2>): CronBuilder<D, P, C2, HasFiles>;
|
|
1429
|
+
/** Initialize shared state on cold start + configure Lambda settings. */
|
|
1430
|
+
setup<C2>(fn: (args: SetupArgs<D, P, HasFiles>) => C2 | Promise<C2>, lambda: LambdaOptions): CronBuilder<D, P, C2, HasFiles>;
|
|
1431
|
+
/** Handle errors thrown by onTick */
|
|
1432
|
+
onError(fn: (args: {
|
|
1433
|
+
error: unknown;
|
|
1434
|
+
} & SpreadCtx<C>) => void): CronBuilder<D, P, C, HasFiles>;
|
|
1435
|
+
/** Cleanup callback — runs after each invocation, before Lambda freezes */
|
|
1436
|
+
onCleanup(fn: (args: SpreadCtx<C>) => void | Promise<void>): CronBuilder<D, P, C, HasFiles>;
|
|
1437
|
+
/** Tick handler — called on each scheduled invocation (terminal) */
|
|
1438
|
+
onTick(fn: CronTickFn<C>): CronHandler<C>;
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Define a cron job — scheduled Lambda invocation via EventBridge Scheduler.
|
|
1442
|
+
*
|
|
1443
|
+
* @example
|
|
1444
|
+
* ```typescript
|
|
1445
|
+
* export const sync = defineCron({ schedule: "cron(0 9 * * ? *)" })
|
|
1446
|
+
* .deps(() => ({ orders }))
|
|
1447
|
+
* .config(({ defineSecret }) => ({ apiKey: defineSecret() }))
|
|
1448
|
+
* .include("templates/*.html")
|
|
1449
|
+
* .setup(async ({ deps, config, files }) => ({
|
|
1450
|
+
* db: deps.orders, key: config.apiKey, tpl: files,
|
|
1451
|
+
* }), { memory: 512 })
|
|
1452
|
+
* .onTick(async ({ db, key, tpl }) => {
|
|
1453
|
+
* const html = tpl.read("templates/report.html")
|
|
1454
|
+
* })
|
|
1453
1455
|
* ```
|
|
1454
1456
|
*/
|
|
1455
|
-
declare
|
|
1457
|
+
declare function defineCron(options: CronOptions): CronBuilder;
|
|
1456
1458
|
|
|
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,
|
|
1459
|
+
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 CronConfig, type CronHandler, 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 Timezone, type UpdateActions, defineApi, defineApp, defineBucket, defineConfig, defineCron, defineFifoQueue, defineMailer, defineSecret, defineStaticSite, defineTable, generateBase64, generateHex, generateUuid, param, secret, toSeconds };
|