effortless-aws 0.28.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/{chunk-EZG3NX42.js → chunk-ISJC6CHC.js} +24 -21
- package/dist/index.d.ts +595 -716
- package/dist/index.js +313 -129
- package/dist/index.js.map +1 -1
- package/dist/runtime/wrap-api.js +69 -95
- package/dist/runtime/wrap-bucket.js +10 -6
- package/dist/runtime/wrap-fifo-queue.js +18 -10
- package/dist/runtime/wrap-table-stream.js +45 -39
- package/package.json +6 -3
package/dist/index.d.ts
CHANGED
|
@@ -95,6 +95,8 @@ type EffortlessConfig = {
|
|
|
95
95
|
*/
|
|
96
96
|
declare const defineConfig: (config: EffortlessConfig) => EffortlessConfig;
|
|
97
97
|
|
|
98
|
+
/** Generator spec for auto-creating secrets at deploy time. */
|
|
99
|
+
type GenerateSpec = `hex:${number}` | `base64:${number}` | "uuid";
|
|
98
100
|
type AwsService = "dynamodb" | "s3" | "sqs" | "sns" | "ses" | "ssm" | "lambda" | "events" | "secretsmanager" | "cognito-idp" | "logs";
|
|
99
101
|
type Permission = `${AwsService}:${string}` | (string & {});
|
|
100
102
|
/**
|
|
@@ -143,7 +145,7 @@ type AnySecretRef = SecretRef<any>;
|
|
|
143
145
|
type SecretRef<T = string> = {
|
|
144
146
|
readonly __brand: "effortless-secret";
|
|
145
147
|
readonly key?: string;
|
|
146
|
-
readonly generate?:
|
|
148
|
+
readonly generate?: GenerateSpec;
|
|
147
149
|
readonly transform?: (raw: string) => T;
|
|
148
150
|
};
|
|
149
151
|
/**
|
|
@@ -155,76 +157,46 @@ type SecretRef<T = string> = {
|
|
|
155
157
|
type ResolveConfig<P> = {
|
|
156
158
|
[K in keyof P]: P[K] extends SecretRef<infer T> ? T : string;
|
|
157
159
|
};
|
|
158
|
-
/** Options for `
|
|
159
|
-
type
|
|
160
|
+
/** Options for `defineSecret()` without a transform. */
|
|
161
|
+
type DefineSecretOptions = {
|
|
160
162
|
/** Custom SSM key (default: derived from config property name in kebab-case) */
|
|
161
163
|
key?: string;
|
|
162
|
-
/** Generator
|
|
163
|
-
generate?:
|
|
164
|
+
/** Generator spec for auto-creating the secret at deploy time: `"hex:32"`, `"base64:32"`, `"uuid"` */
|
|
165
|
+
generate?: GenerateSpec;
|
|
164
166
|
};
|
|
165
|
-
/** Options for `
|
|
166
|
-
type
|
|
167
|
+
/** Options for `defineSecret()` with a transform. */
|
|
168
|
+
type DefineSecretOptionsWithTransform<T> = DefineSecretOptions & {
|
|
167
169
|
/** Transform the raw SSM string value into a typed value */
|
|
168
170
|
transform: (raw: string) => T;
|
|
169
171
|
};
|
|
170
|
-
/**
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
*
|
|
187
|
-
* @example Auto-generated secret
|
|
188
|
-
* ```typescript
|
|
189
|
-
* config: {
|
|
190
|
-
* authSecret: secret({ generate: generateHex(64) }),
|
|
191
|
-
* // → auto-creates SSM param if missing
|
|
192
|
-
* }
|
|
193
|
-
* ```
|
|
194
|
-
*
|
|
195
|
-
* @example With transform
|
|
196
|
-
* ```typescript
|
|
197
|
-
* config: {
|
|
198
|
-
* appConfig: secret({ transform: TOML.parse }),
|
|
199
|
-
* }
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
declare function secret(): SecretRef<string>;
|
|
203
|
-
declare function secret(options: SecretOptions): SecretRef<string>;
|
|
204
|
-
declare function secret<T>(options: SecretOptionsWithTransform<T>): SecretRef<T>;
|
|
205
|
-
/**
|
|
206
|
-
* Returns a generator that produces a random hex string.
|
|
207
|
-
* @param bytes - Number of random bytes (output will be 2x this length in hex chars)
|
|
208
|
-
*/
|
|
209
|
-
declare const generateHex: (bytes: number) => () => string;
|
|
210
|
-
/**
|
|
211
|
-
* Returns a generator that produces a random base64url string.
|
|
212
|
-
* @param bytes - Number of random bytes
|
|
213
|
-
*/
|
|
214
|
-
declare const generateBase64: (bytes: number) => () => string;
|
|
215
|
-
/**
|
|
216
|
-
* Returns a generator that produces a random UUID v4.
|
|
217
|
-
*/
|
|
218
|
-
declare const generateUuid: () => () => string;
|
|
172
|
+
/** The defineSecret helper function type, injected into config callbacks. */
|
|
173
|
+
type DefineSecretFn = {
|
|
174
|
+
(): SecretRef<string>;
|
|
175
|
+
(options: DefineSecretOptions): SecretRef<string>;
|
|
176
|
+
<T>(options: DefineSecretOptionsWithTransform<T>): SecretRef<T>;
|
|
177
|
+
};
|
|
178
|
+
/** Helpers injected into the `config` callback. */
|
|
179
|
+
type ConfigHelpers = {
|
|
180
|
+
defineSecret: DefineSecretFn;
|
|
181
|
+
};
|
|
182
|
+
/** Config factory: a function receiving helpers and returning a record of SecretRefs. */
|
|
183
|
+
type ConfigFactory<P> = (helpers: ConfigHelpers) => P;
|
|
184
|
+
/** The `defineSecret` implementation, passed to config callbacks. */
|
|
185
|
+
declare const defineSecret: DefineSecretFn;
|
|
186
|
+
/** @deprecated Use `defineSecret()` inside a config callback instead. */
|
|
187
|
+
declare const secret: DefineSecretFn;
|
|
219
188
|
/** @deprecated Use `SecretRef` instead */
|
|
220
189
|
type ParamRef<T = string> = SecretRef<T>;
|
|
221
190
|
/** @deprecated Use `AnySecretRef` instead */
|
|
222
191
|
type AnyParamRef = AnySecretRef;
|
|
223
|
-
/**
|
|
224
|
-
|
|
225
|
-
*/
|
|
226
|
-
declare
|
|
227
|
-
|
|
192
|
+
/** @deprecated Use `defineSecret()` instead. */
|
|
193
|
+
declare const param: <T = string>(key: string, transform?: (raw: string) => T) => SecretRef<T>;
|
|
194
|
+
/** @deprecated Use `defineSecret({ generate: "hex:N" })` instead. */
|
|
195
|
+
declare const generateHex: (bytes: number) => string;
|
|
196
|
+
/** @deprecated Use `defineSecret({ generate: "base64:N" })` instead. */
|
|
197
|
+
declare const generateBase64: (bytes: number) => string;
|
|
198
|
+
/** @deprecated Use `defineSecret({ generate: "uuid" })` instead. */
|
|
199
|
+
declare const generateUuid: () => string;
|
|
228
200
|
/**
|
|
229
201
|
* DynamoDB table key (always pk + sk strings in single-table design).
|
|
230
202
|
*/
|
|
@@ -281,113 +253,8 @@ type PutInput<T> = {
|
|
|
281
253
|
*/
|
|
282
254
|
declare function unsafeAs<T>(): (input: unknown) => T;
|
|
283
255
|
|
|
284
|
-
/**
|
|
285
|
-
* Sort key condition for TableClient.query()
|
|
286
|
-
*/
|
|
287
|
-
type SkCondition = string | {
|
|
288
|
-
begins_with: string;
|
|
289
|
-
} | {
|
|
290
|
-
gt: string;
|
|
291
|
-
} | {
|
|
292
|
-
gte: string;
|
|
293
|
-
} | {
|
|
294
|
-
lt: string;
|
|
295
|
-
} | {
|
|
296
|
-
lte: string;
|
|
297
|
-
} | {
|
|
298
|
-
between: [string, string];
|
|
299
|
-
};
|
|
300
|
-
/**
|
|
301
|
-
* Query parameters for TableClient.query()
|
|
302
|
-
*/
|
|
303
|
-
type QueryParams = {
|
|
304
|
-
/** Partition key value */
|
|
305
|
-
pk: string;
|
|
306
|
-
/** Optional sort key condition */
|
|
307
|
-
sk?: SkCondition;
|
|
308
|
-
/** Maximum number of items to return */
|
|
309
|
-
limit?: number;
|
|
310
|
-
/** Sort order (true = ascending, false = descending) */
|
|
311
|
-
scanIndexForward?: boolean;
|
|
312
|
-
};
|
|
313
|
-
/**
|
|
314
|
-
* Query parameters for TableClient.queryByTag() — cross-partition query via GSI.
|
|
315
|
-
* Uses the built-in `tag-pk-index` GSI (tag as partition key, pk as sort key).
|
|
316
|
-
*/
|
|
317
|
-
type QueryByTagParams = {
|
|
318
|
-
/** Tag value (GSI partition key) — the entity type discriminant */
|
|
319
|
-
tag: string;
|
|
320
|
-
/** Optional pk condition (GSI sort key) */
|
|
321
|
-
pk?: SkCondition;
|
|
322
|
-
/** Maximum number of items to return */
|
|
323
|
-
limit?: number;
|
|
324
|
-
/** Sort order (true = ascending, false = descending) */
|
|
325
|
-
scanIndexForward?: boolean;
|
|
326
|
-
};
|
|
327
|
-
/** Extract keys of T whose values are arrays */
|
|
328
|
-
type ArrayKeys<T> = {
|
|
329
|
-
[K in keyof T]: T[K] extends unknown[] ? K : never;
|
|
330
|
-
}[keyof T];
|
|
331
|
-
/** Extract keys of T whose values are numbers */
|
|
332
|
-
type NumberKeys<T> = {
|
|
333
|
-
[K in keyof T]: T[K] extends number ? K : never;
|
|
334
|
-
}[keyof T];
|
|
335
|
-
/**
|
|
336
|
-
* Update actions for TableClient.update()
|
|
337
|
-
*
|
|
338
|
-
* `set`, `append`, and `remove` target fields inside the `data` attribute.
|
|
339
|
-
* Effortless auto-prefixes `data.` in the DynamoDB expression.
|
|
340
|
-
*
|
|
341
|
-
* @typeParam T - Type of the domain data (the `data` attribute)
|
|
342
|
-
*/
|
|
343
|
-
type UpdateActions<T> = {
|
|
344
|
-
/** Set domain data fields (inside `data` attribute) */
|
|
345
|
-
set?: Partial<T>;
|
|
346
|
-
/** Atomically increment/decrement numeric fields inside `data` (use negative values to decrement) */
|
|
347
|
-
increment?: Pick<Partial<T>, NumberKeys<T>>;
|
|
348
|
-
/** Append elements to list fields inside `data` (creates the list if it doesn't exist) */
|
|
349
|
-
append?: Pick<Partial<T>, ArrayKeys<T>>;
|
|
350
|
-
/** Remove fields from `data` */
|
|
351
|
-
remove?: (keyof T)[];
|
|
352
|
-
/** Update the top-level `tag` attribute */
|
|
353
|
-
tag?: string;
|
|
354
|
-
/** Update TTL (set number or null to remove) */
|
|
355
|
-
ttl?: number | null;
|
|
356
|
-
};
|
|
357
|
-
/**
|
|
358
|
-
* Typed DynamoDB table client for single-table design.
|
|
359
|
-
*
|
|
360
|
-
* All items follow the `{ pk, sk, tag, data, ttl? }` structure.
|
|
361
|
-
* `T` is the domain data type stored in the `data` attribute.
|
|
362
|
-
*
|
|
363
|
-
* @typeParam T - Type of the domain data
|
|
364
|
-
*/
|
|
365
|
-
/**
|
|
366
|
-
* Options for `put()` operation.
|
|
367
|
-
*/
|
|
368
|
-
type PutOptions = {
|
|
369
|
-
/** When true, the put fails if an item with the same pk+sk already exists. */
|
|
370
|
-
ifNotExists?: boolean;
|
|
371
|
-
};
|
|
372
|
-
type TableClient<T = Record<string, unknown>> = {
|
|
373
|
-
/** Put an item. Tag is auto-extracted from `data[tagField]`. Use `ifNotExists` to prevent overwrites. */
|
|
374
|
-
put(item: PutInput<T>, options?: PutOptions): Promise<void>;
|
|
375
|
-
/** Get an item by pk + sk */
|
|
376
|
-
get(key: TableKey): Promise<TableItem<T> | undefined>;
|
|
377
|
-
/** Delete an item by pk + sk */
|
|
378
|
-
delete(key: TableKey): Promise<void>;
|
|
379
|
-
/** Update domain data fields without reading the full item */
|
|
380
|
-
update(key: TableKey, actions: UpdateActions<T>): Promise<void>;
|
|
381
|
-
/** Query by partition key with optional sort key condition */
|
|
382
|
-
query(params: QueryParams): Promise<TableItem<T>[]>;
|
|
383
|
-
/** Query by tag across all partitions via GSI (tag-pk-index). */
|
|
384
|
-
queryByTag(params: QueryByTagParams): Promise<TableItem<T>[]>;
|
|
385
|
-
/** The underlying DynamoDB table name */
|
|
386
|
-
tableName: string;
|
|
387
|
-
};
|
|
388
|
-
|
|
389
256
|
/** HTTP methods supported by Lambda Function URLs */
|
|
390
|
-
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "ANY";
|
|
257
|
+
type HttpMethod$1 = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "ANY";
|
|
391
258
|
/** Short content-type aliases for common response formats */
|
|
392
259
|
type ContentType = "json" | "html" | "text" | "css" | "js" | "xml" | "csv" | "svg";
|
|
393
260
|
/**
|
|
@@ -439,13 +306,6 @@ type HttpResponse = {
|
|
|
439
306
|
*/
|
|
440
307
|
binary?: boolean;
|
|
441
308
|
};
|
|
442
|
-
/** Response helpers for defineApi handlers */
|
|
443
|
-
declare const result: {
|
|
444
|
-
/** Return a JSON response */
|
|
445
|
-
json: (body: unknown, status?: number) => HttpResponse;
|
|
446
|
-
/** Return a binary response. Accepts a Buffer and converts to base64 automatically. */
|
|
447
|
-
binary: (body: Buffer, contentType: string, headers?: Record<string, string>) => HttpResponse;
|
|
448
|
-
};
|
|
449
309
|
/** Stream helper injected into route args when `stream: true` is set on defineApi */
|
|
450
310
|
type ResponseStream = {
|
|
451
311
|
/** Write a raw string chunk to the response stream */
|
|
@@ -493,27 +353,17 @@ type BucketClient = {
|
|
|
493
353
|
bucketName: string;
|
|
494
354
|
};
|
|
495
355
|
|
|
496
|
-
/**
|
|
497
|
-
* Common conditional args injected into handler callbacks.
|
|
498
|
-
* Resolves ctx, deps, config, and files based on whether each generic is defined.
|
|
499
|
-
* @internal
|
|
500
|
-
*/
|
|
501
|
-
type HandlerArgs<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = ([C] extends [undefined] ? {} : {
|
|
502
|
-
ctx: C;
|
|
503
|
-
}) & ([D] extends [undefined] ? {} : {
|
|
504
|
-
deps: ResolveDeps<D>;
|
|
505
|
-
}) & ([P] extends [undefined] ? {} : {
|
|
506
|
-
config: ResolveConfig<P>;
|
|
507
|
-
}) & ([S] extends [undefined] ? {} : {
|
|
508
|
-
files: StaticFiles;
|
|
509
|
-
});
|
|
510
|
-
|
|
511
356
|
/**
|
|
512
357
|
* Configuration options for defineBucket.
|
|
513
358
|
*/
|
|
514
359
|
type BucketConfig = {
|
|
515
360
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
516
|
-
lambda?:
|
|
361
|
+
lambda?: {
|
|
362
|
+
memory?: number;
|
|
363
|
+
timeout?: Duration;
|
|
364
|
+
logLevel?: LogLevel;
|
|
365
|
+
permissions?: Permission[];
|
|
366
|
+
};
|
|
517
367
|
/** S3 key prefix filter for event notifications (e.g., "uploads/") */
|
|
518
368
|
prefix?: string;
|
|
519
369
|
/** S3 key suffix filter for event notifications (e.g., ".jpg") */
|
|
@@ -536,80 +386,30 @@ type BucketEvent = {
|
|
|
536
386
|
/** S3 bucket name */
|
|
537
387
|
bucketName: string;
|
|
538
388
|
};
|
|
389
|
+
/** Spread ctx into callback args (empty when no setup) */
|
|
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
|
+
} : {});
|
|
539
401
|
/**
|
|
540
402
|
* Callback function type for S3 ObjectCreated events
|
|
541
403
|
*/
|
|
542
|
-
type BucketObjectCreatedFn<C = undefined
|
|
404
|
+
type BucketObjectCreatedFn<C = undefined> = (args: {
|
|
543
405
|
event: BucketEvent;
|
|
544
|
-
|
|
545
|
-
} & HandlerArgs<C, D, P, S>) => Promise<void>;
|
|
406
|
+
} & SpreadCtx$3<C>) => Promise<void>;
|
|
546
407
|
/**
|
|
547
408
|
* Callback function type for S3 ObjectRemoved events
|
|
548
409
|
*/
|
|
549
|
-
type BucketObjectRemovedFn<C = undefined
|
|
410
|
+
type BucketObjectRemovedFn<C = undefined> = (args: {
|
|
550
411
|
event: BucketEvent;
|
|
551
|
-
|
|
552
|
-
} & HandlerArgs<C, D, P, S>) => Promise<void>;
|
|
553
|
-
/**
|
|
554
|
-
* Setup factory type for bucket handlers.
|
|
555
|
-
* Always receives `bucket: BucketClient` (self-client for the handler's own bucket).
|
|
556
|
-
* Also receives `deps` and/or `config` when declared.
|
|
557
|
-
*/
|
|
558
|
-
type SetupFactory$3<C, D, P, S extends string[] | undefined = undefined> = (args: {
|
|
559
|
-
bucket: BucketClient;
|
|
560
|
-
} & ([D] extends [undefined] ? {} : {
|
|
561
|
-
deps: ResolveDeps<D>;
|
|
562
|
-
}) & ([P] extends [undefined] ? {} : {
|
|
563
|
-
config: ResolveConfig<P & {}>;
|
|
564
|
-
}) & ([S] extends [undefined] ? {} : {
|
|
565
|
-
files: StaticFiles;
|
|
566
|
-
})) => C | Promise<C>;
|
|
567
|
-
/** Base options shared by all defineBucket variants */
|
|
568
|
-
type DefineBucketBase<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = BucketConfig & {
|
|
569
|
-
/**
|
|
570
|
-
* Error handler called when onObjectCreated or onObjectRemoved throws.
|
|
571
|
-
* If not provided, defaults to `console.error`.
|
|
572
|
-
*/
|
|
573
|
-
onError?: (args: {
|
|
574
|
-
error: unknown;
|
|
575
|
-
} & HandlerArgs<C, D, P, S>) => void;
|
|
576
|
-
/** Called after each invocation completes, right before Lambda freezes the process */
|
|
577
|
-
onAfterInvoke?: (args: HandlerArgs<C, D, P, S>) => void | Promise<void>;
|
|
578
|
-
/**
|
|
579
|
-
* Factory function to initialize shared state for callbacks.
|
|
580
|
-
* Called once on cold start, result is cached and reused across invocations.
|
|
581
|
-
* Always receives `bucket: BucketClient` (self-client). When deps/config
|
|
582
|
-
* are declared, receives them as well.
|
|
583
|
-
*/
|
|
584
|
-
setup?: SetupFactory$3<C, D, P, S>;
|
|
585
|
-
/**
|
|
586
|
-
* Dependencies on other handlers (tables, buckets, etc.).
|
|
587
|
-
* Typed clients are injected into the handler via the `deps` argument.
|
|
588
|
-
* Pass a function returning the deps object: `deps: () => ({ uploads })`.
|
|
589
|
-
*/
|
|
590
|
-
deps?: () => D & {};
|
|
591
|
-
/**
|
|
592
|
-
* SSM Parameter Store parameters.
|
|
593
|
-
* Declare with `param()` helper. Values are fetched and cached at cold start.
|
|
594
|
-
*/
|
|
595
|
-
config?: P;
|
|
596
|
-
/**
|
|
597
|
-
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
598
|
-
* Files are accessible at runtime via the `files` callback argument.
|
|
599
|
-
*/
|
|
600
|
-
static?: S;
|
|
601
|
-
};
|
|
602
|
-
/** With event handlers (at least one callback) */
|
|
603
|
-
type DefineBucketWithHandlers<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {
|
|
604
|
-
onObjectCreated?: BucketObjectCreatedFn<C, D, P, S>;
|
|
605
|
-
onObjectRemoved?: BucketObjectRemovedFn<C, D, P, S>;
|
|
606
|
-
};
|
|
607
|
-
/** Resource-only: no Lambda, just creates the bucket */
|
|
608
|
-
type DefineBucketResourceOnly<C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineBucketBase<C, D, P, S> & {
|
|
609
|
-
onObjectCreated?: never;
|
|
610
|
-
onObjectRemoved?: never;
|
|
611
|
-
};
|
|
612
|
-
type DefineBucketOptions<C = undefined, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined, S extends string[] | undefined = undefined> = DefineBucketWithHandlers<C, D, P, S> | DefineBucketResourceOnly<C, D, P, S>;
|
|
412
|
+
} & SpreadCtx$3<C>) => Promise<void>;
|
|
613
413
|
/**
|
|
614
414
|
* Internal handler object created by defineBucket
|
|
615
415
|
* @internal
|
|
@@ -618,7 +418,7 @@ type BucketHandler<C = any> = {
|
|
|
618
418
|
readonly __brand: "effortless-bucket";
|
|
619
419
|
readonly __spec: BucketConfig;
|
|
620
420
|
readonly onError?: (...args: any[]) => any;
|
|
621
|
-
readonly
|
|
421
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
622
422
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
623
423
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
624
424
|
readonly config?: Record<string, unknown>;
|
|
@@ -626,42 +426,65 @@ type BucketHandler<C = any> = {
|
|
|
626
426
|
readonly onObjectCreated?: (...args: any[]) => any;
|
|
627
427
|
readonly onObjectRemoved?: (...args: any[]) => any;
|
|
628
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
|
+
}
|
|
629
466
|
/**
|
|
630
467
|
* Define an S3 bucket with optional event handlers.
|
|
631
468
|
*
|
|
632
|
-
* Creates an S3 bucket. When event handlers are provided, also creates a Lambda
|
|
633
|
-
* function triggered by S3 event notifications.
|
|
634
|
-
*
|
|
635
469
|
* @example Bucket with event handler
|
|
636
470
|
* ```typescript
|
|
637
|
-
* export const uploads = defineBucket({
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
* const file = await bucket.get(event.key);
|
|
642
|
-
* console.log("New upload:", event.key, file?.body.length);
|
|
643
|
-
* }
|
|
644
|
-
* });
|
|
645
|
-
* ```
|
|
471
|
+
* export const uploads = defineBucket({ prefix: "images/", suffix: ".jpg" })
|
|
472
|
+
* .onObjectCreated(async ({ event, bucket }) => {
|
|
473
|
+
* console.log("New upload:", event.key);
|
|
474
|
+
* })
|
|
646
475
|
*
|
|
647
|
-
* @example Resource-only bucket (no Lambda)
|
|
648
|
-
* ```typescript
|
|
649
|
-
* export const assets = defineBucket({});
|
|
650
476
|
* ```
|
|
651
477
|
*
|
|
652
|
-
* @example
|
|
478
|
+
* @example Resource-only bucket (no Lambda)
|
|
653
479
|
* ```typescript
|
|
654
|
-
* export const
|
|
655
|
-
* basePath: "/process",
|
|
656
|
-
* deps: { uploads },
|
|
657
|
-
* post: async ({ req, deps }) => {
|
|
658
|
-
* await deps.uploads.put("output.jpg", buffer);
|
|
659
|
-
* return { status: 200, body: "OK" };
|
|
660
|
-
* },
|
|
661
|
-
* });
|
|
480
|
+
* export const assets = defineBucket().build()
|
|
662
481
|
* ```
|
|
663
482
|
*/
|
|
664
|
-
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;
|
|
665
488
|
|
|
666
489
|
/**
|
|
667
490
|
* Configuration options for defining a mailer (SES email identity)
|
|
@@ -709,7 +532,7 @@ type MailerHandler = {
|
|
|
709
532
|
* });
|
|
710
533
|
* ```
|
|
711
534
|
*/
|
|
712
|
-
declare const defineMailer: (options: MailerConfig) => MailerHandler;
|
|
535
|
+
declare const defineMailer: () => (options: MailerConfig) => MailerHandler;
|
|
713
536
|
|
|
714
537
|
/**
|
|
715
538
|
* Parsed SQS FIFO message passed to the handler callbacks.
|
|
@@ -746,7 +569,12 @@ type FifoQueueMessage<T = unknown> = {
|
|
|
746
569
|
*/
|
|
747
570
|
type FifoQueueConfig = {
|
|
748
571
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
749
|
-
lambda?:
|
|
572
|
+
lambda?: {
|
|
573
|
+
memory?: number;
|
|
574
|
+
timeout?: Duration;
|
|
575
|
+
logLevel?: LogLevel;
|
|
576
|
+
permissions?: Permission[];
|
|
577
|
+
};
|
|
750
578
|
/** Number of messages per Lambda invocation (1-10 for FIFO, default: 10) */
|
|
751
579
|
batchSize?: number;
|
|
752
580
|
/** Maximum time to gather messages before invoking (default: 0). Accepts `"5s"`, `"1m"`, etc. */
|
|
@@ -762,81 +590,33 @@ type FifoQueueConfig = {
|
|
|
762
590
|
/** Max number of receives before a message is sent to the dead-letter queue (default: 3) */
|
|
763
591
|
maxReceiveCount?: number;
|
|
764
592
|
};
|
|
765
|
-
/**
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
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] ? {} : {
|
|
770
597
|
deps: ResolveDeps<D>;
|
|
771
598
|
}) & ([P] extends [undefined] ? {} : {
|
|
772
599
|
config: ResolveConfig<P & {}>;
|
|
773
|
-
}) & (
|
|
600
|
+
}) & (HasFiles extends true ? {
|
|
774
601
|
files: StaticFiles;
|
|
775
|
-
}
|
|
602
|
+
} : {});
|
|
776
603
|
/**
|
|
777
604
|
* Per-message handler function.
|
|
778
605
|
* Called once per message in the batch. Failures are reported individually.
|
|
779
606
|
*/
|
|
780
|
-
type FifoQueueMessageFn<T = unknown, C = undefined
|
|
607
|
+
type FifoQueueMessageFn<T = unknown, C = undefined> = (args: {
|
|
781
608
|
message: FifoQueueMessage<T>;
|
|
782
|
-
} &
|
|
609
|
+
} & SpreadCtx$2<C>) => Promise<void>;
|
|
783
610
|
/**
|
|
784
611
|
* Batch handler function.
|
|
785
612
|
* Called once with all messages in the batch.
|
|
613
|
+
* Return `{ failures: string[] }` (messageIds) for partial batch failure reporting.
|
|
786
614
|
*/
|
|
787
|
-
type FifoQueueBatchFn<T = unknown, C = undefined
|
|
615
|
+
type FifoQueueBatchFn<T = unknown, C = undefined> = (args: {
|
|
788
616
|
messages: FifoQueueMessage<T>[];
|
|
789
|
-
} &
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
/**
|
|
793
|
-
* Decode/validate function for the message body.
|
|
794
|
-
* Called with the JSON-parsed body; should return typed data or throw on validation failure.
|
|
795
|
-
*/
|
|
796
|
-
schema?: (input: unknown) => T;
|
|
797
|
-
/**
|
|
798
|
-
* Error handler called when onMessage or onBatch throws.
|
|
799
|
-
* If not provided, defaults to `console.error`.
|
|
800
|
-
*/
|
|
801
|
-
onError?: (args: {
|
|
802
|
-
error: unknown;
|
|
803
|
-
} & HandlerArgs<C, D, P, S>) => void;
|
|
804
|
-
/** Called after each invocation completes, right before Lambda freezes the process */
|
|
805
|
-
onAfterInvoke?: (args: HandlerArgs<C, D, P, S>) => void | Promise<void>;
|
|
806
|
-
/**
|
|
807
|
-
* Factory function to initialize shared state for the handler.
|
|
808
|
-
* Called once on cold start, result is cached and reused across invocations.
|
|
809
|
-
* When deps/params are declared, receives them as argument.
|
|
810
|
-
*/
|
|
811
|
-
setup?: SetupFactory$2<C, D, P, S>;
|
|
812
|
-
/**
|
|
813
|
-
* Dependencies on other handlers (tables, queues, etc.).
|
|
814
|
-
* Typed clients are injected into the handler via the `deps` argument.
|
|
815
|
-
* Pass a function returning the deps object: `deps: () => ({ orders })`.
|
|
816
|
-
*/
|
|
817
|
-
deps?: () => D & {};
|
|
818
|
-
/**
|
|
819
|
-
* SSM Parameter Store parameters.
|
|
820
|
-
* Declare with `param()` helper. Values are fetched and cached at cold start.
|
|
821
|
-
*/
|
|
822
|
-
config?: P;
|
|
823
|
-
/**
|
|
824
|
-
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
825
|
-
* Files are accessible at runtime via the `files` callback argument.
|
|
826
|
-
*/
|
|
827
|
-
static?: S;
|
|
828
|
-
};
|
|
829
|
-
/** Per-message processing */
|
|
830
|
-
type DefineFifoQueueWithOnMessage<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {
|
|
831
|
-
onMessage: FifoQueueMessageFn<T, C, D, P, S>;
|
|
832
|
-
onBatch?: never;
|
|
833
|
-
};
|
|
834
|
-
/** Batch processing: all messages at once */
|
|
835
|
-
type DefineFifoQueueWithOnBatch<T = unknown, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueBase<T, C, D, P, S> & {
|
|
836
|
-
onBatch: FifoQueueBatchFn<T, C, D, P, S>;
|
|
837
|
-
onMessage?: never;
|
|
838
|
-
};
|
|
839
|
-
type DefineFifoQueueOptions<T = unknown, C = undefined, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined, S extends string[] | undefined = undefined> = DefineFifoQueueWithOnMessage<T, C, D, P, S> | DefineFifoQueueWithOnBatch<T, C, D, P, S>;
|
|
617
|
+
} & SpreadCtx$2<C>) => Promise<void | {
|
|
618
|
+
failures: string[];
|
|
619
|
+
}>;
|
|
840
620
|
/**
|
|
841
621
|
* Internal handler object created by defineFifoQueue
|
|
842
622
|
* @internal
|
|
@@ -846,64 +626,211 @@ type FifoQueueHandler<T = unknown, C = any> = {
|
|
|
846
626
|
readonly __spec: FifoQueueConfig;
|
|
847
627
|
readonly schema?: (input: unknown) => T;
|
|
848
628
|
readonly onError?: (...args: any[]) => any;
|
|
849
|
-
readonly
|
|
629
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
850
630
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
851
631
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
852
632
|
readonly config?: Record<string, unknown>;
|
|
853
633
|
readonly static?: string[];
|
|
854
634
|
readonly onMessage?: (...args: any[]) => any;
|
|
855
|
-
readonly
|
|
635
|
+
readonly onMessageBatch?: (...args: any[]) => any;
|
|
856
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
|
+
}
|
|
857
684
|
/**
|
|
858
|
-
* Define a FIFO SQS queue with a Lambda message handler
|
|
859
|
-
*
|
|
860
|
-
* Creates:
|
|
861
|
-
* - SQS FIFO queue (with `.fifo` suffix)
|
|
862
|
-
* - Lambda function triggered by the queue
|
|
863
|
-
* - Event source mapping with partial batch failure support
|
|
685
|
+
* Define a FIFO SQS queue with a Lambda message handler.
|
|
864
686
|
*
|
|
865
687
|
* @example Per-message processing
|
|
866
688
|
* ```typescript
|
|
867
|
-
*
|
|
868
|
-
*
|
|
869
|
-
* export const orderQueue = defineFifoQueue<OrderEvent>({
|
|
870
|
-
* onMessage: async ({ message }) => {
|
|
689
|
+
* export const orderQueue = defineFifoQueue<OrderEvent>()
|
|
690
|
+
* .onMessage(async ({ message }) => {
|
|
871
691
|
* console.log("Processing order:", message.body.orderId);
|
|
872
|
-
* }
|
|
873
|
-
*
|
|
692
|
+
* })
|
|
693
|
+
*
|
|
874
694
|
* ```
|
|
875
695
|
*
|
|
876
696
|
* @example Batch processing with schema
|
|
877
697
|
* ```typescript
|
|
878
|
-
* export const notifications = defineFifoQueue({
|
|
879
|
-
*
|
|
880
|
-
* batchSize: 5,
|
|
881
|
-
* onBatch: async ({ messages }) => {
|
|
698
|
+
* export const notifications = defineFifoQueue({ batchSize: 5, schema: (i) => NotifSchema.parse(i) })
|
|
699
|
+
* .onMessageBatch(async ({ messages }) => {
|
|
882
700
|
* await sendAll(messages.map(m => m.body));
|
|
883
|
-
* }
|
|
884
|
-
*
|
|
701
|
+
* })
|
|
702
|
+
*
|
|
885
703
|
* ```
|
|
886
704
|
*/
|
|
887
|
-
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>;
|
|
888
710
|
|
|
889
711
|
/**
|
|
890
|
-
*
|
|
712
|
+
* Sort key condition for TableClient.query()
|
|
891
713
|
*/
|
|
892
|
-
type
|
|
893
|
-
|
|
894
|
-
from: string;
|
|
895
|
-
/** Recipient address(es) */
|
|
896
|
-
to: string | string[];
|
|
897
|
-
/** Email subject line */
|
|
898
|
-
subject: string;
|
|
899
|
-
};
|
|
900
|
-
type SendEmailOptions = SendEmailBase & ({
|
|
901
|
-
html: string;
|
|
902
|
-
text?: string;
|
|
714
|
+
type SkCondition = string | {
|
|
715
|
+
begins_with: string;
|
|
903
716
|
} | {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
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
|
+
};
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Options for sending an email via EmailClient.send()
|
|
818
|
+
*/
|
|
819
|
+
type SendEmailBase = {
|
|
820
|
+
/** Sender address (must be on a verified domain) */
|
|
821
|
+
from: string;
|
|
822
|
+
/** Recipient address(es) */
|
|
823
|
+
to: string | string[];
|
|
824
|
+
/** Email subject line */
|
|
825
|
+
subject: string;
|
|
826
|
+
};
|
|
827
|
+
type SendEmailOptions = SendEmailBase & ({
|
|
828
|
+
html: string;
|
|
829
|
+
text?: string;
|
|
830
|
+
} | {
|
|
831
|
+
html?: string;
|
|
832
|
+
text: string;
|
|
833
|
+
});
|
|
907
834
|
/**
|
|
908
835
|
* Typed SES email client injected via deps.
|
|
909
836
|
*
|
|
@@ -962,7 +889,12 @@ type StreamView = "NEW_AND_OLD_IMAGES" | "NEW_IMAGE" | "OLD_IMAGE" | "KEYS_ONLY"
|
|
|
962
889
|
*/
|
|
963
890
|
type TableConfig = {
|
|
964
891
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
965
|
-
lambda?:
|
|
892
|
+
lambda?: {
|
|
893
|
+
memory?: number;
|
|
894
|
+
timeout?: Duration;
|
|
895
|
+
logLevel?: LogLevel;
|
|
896
|
+
permissions?: Permission[];
|
|
897
|
+
};
|
|
966
898
|
/** DynamoDB billing mode (default: "PAY_PER_REQUEST") */
|
|
967
899
|
billingMode?: "PAY_PER_REQUEST" | "PROVISIONED";
|
|
968
900
|
/** Stream view type - what data to include in stream records (default: "NEW_AND_OLD_IMAGES") */
|
|
@@ -973,18 +905,12 @@ type TableConfig = {
|
|
|
973
905
|
batchWindow?: Duration;
|
|
974
906
|
/** Where to start reading the stream (default: "LATEST") */
|
|
975
907
|
startingPosition?: "LATEST" | "TRIM_HORIZON";
|
|
908
|
+
/** Number of records to process concurrently within a batch (default: 1 — sequential) */
|
|
909
|
+
concurrency?: number;
|
|
976
910
|
/**
|
|
977
911
|
* Name of the field in `data` that serves as the entity type discriminant.
|
|
978
912
|
* Effortless auto-copies `data[tagField]` to the top-level DynamoDB `tag` attribute on `put()`.
|
|
979
913
|
* Defaults to `"tag"`.
|
|
980
|
-
*
|
|
981
|
-
* @example
|
|
982
|
-
* ```typescript
|
|
983
|
-
* export const orders = defineTable<{ type: "order"; amount: number }>({
|
|
984
|
-
* tagField: "type",
|
|
985
|
-
* onRecord: async ({ record }) => { ... }
|
|
986
|
-
* });
|
|
987
|
-
* ```
|
|
988
914
|
*/
|
|
989
915
|
tagField?: string;
|
|
990
916
|
};
|
|
@@ -1012,118 +938,40 @@ type TableRecord<T = Record<string, unknown>> = {
|
|
|
1012
938
|
/** Approximate timestamp when the modification occurred */
|
|
1013
939
|
timestamp?: number;
|
|
1014
940
|
};
|
|
1015
|
-
/**
|
|
1016
|
-
|
|
1017
|
-
*
|
|
1018
|
-
* @typeParam T - Type of the domain data
|
|
1019
|
-
*/
|
|
1020
|
-
type FailedRecord<T = Record<string, unknown>> = {
|
|
1021
|
-
/** The record that failed to process */
|
|
1022
|
-
record: TableRecord<T>;
|
|
1023
|
-
/** The error that occurred */
|
|
1024
|
-
error: unknown;
|
|
1025
|
-
};
|
|
1026
|
-
/**
|
|
1027
|
-
* Setup factory type for table handlers.
|
|
1028
|
-
* Always receives `table: TableClient<T>` (self-client for the handler's own table).
|
|
1029
|
-
* Also receives `deps` and/or `config` when declared.
|
|
1030
|
-
*/
|
|
1031
|
-
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> = {
|
|
1032
943
|
table: TableClient<T>;
|
|
1033
944
|
} & ([D] extends [undefined] ? {} : {
|
|
1034
945
|
deps: ResolveDeps<D>;
|
|
1035
946
|
}) & ([P] extends [undefined] ? {} : {
|
|
1036
947
|
config: ResolveConfig<P & {}>;
|
|
1037
|
-
}) & (
|
|
948
|
+
}) & (HasFiles extends true ? {
|
|
1038
949
|
files: StaticFiles;
|
|
1039
|
-
}
|
|
950
|
+
} : {});
|
|
951
|
+
/** Spread ctx into callback args (empty when no setup) */
|
|
952
|
+
type SpreadCtx$1<C> = [C] extends [undefined] ? {} : C & {};
|
|
1040
953
|
/**
|
|
1041
|
-
* Callback function type for processing a single DynamoDB stream record
|
|
954
|
+
* Callback function type for processing a single DynamoDB stream record.
|
|
955
|
+
* Receives the current record and the full batch for context.
|
|
1042
956
|
*/
|
|
1043
|
-
type TableRecordFn<T = Record<string, unknown>, C = undefined
|
|
957
|
+
type TableRecordFn<T = Record<string, unknown>, C = undefined> = (args: {
|
|
1044
958
|
record: TableRecord<T>;
|
|
1045
|
-
|
|
1046
|
-
} &
|
|
1047
|
-
/**
|
|
1048
|
-
*
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
} &
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
*/
|
|
1058
|
-
type TableBatchFn<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = (args: {
|
|
1059
|
-
records: TableRecord<T>[];
|
|
1060
|
-
table: TableClient<T>;
|
|
1061
|
-
} & HandlerArgs<C, D, P, S>) => Promise<void>;
|
|
1062
|
-
/** Base options shared by all defineTable variants */
|
|
1063
|
-
type DefineTableBase<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = Omit<TableConfig, "tagField"> & {
|
|
1064
|
-
/** Name of the field in `data` that serves as the entity type discriminant (default: `"tag"`). */
|
|
1065
|
-
tagField?: Extract<keyof T, string>;
|
|
1066
|
-
/**
|
|
1067
|
-
* Decode/validate function for the `data` portion of stream record items.
|
|
1068
|
-
* Called with the unmarshalled `data` attribute; should return typed data or throw on validation failure.
|
|
1069
|
-
* When provided, T is inferred from the return type — no need to specify generic parameters.
|
|
1070
|
-
*/
|
|
1071
|
-
schema?: (input: unknown) => T;
|
|
1072
|
-
/**
|
|
1073
|
-
* Error handler called when onRecord, onBatch, or onBatchComplete throws.
|
|
1074
|
-
* Receives the error. If not provided, defaults to `console.error`.
|
|
1075
|
-
*/
|
|
1076
|
-
onError?: (args: {
|
|
1077
|
-
error: unknown;
|
|
1078
|
-
} & HandlerArgs<C, D, P, S>) => void;
|
|
1079
|
-
/** Called after each invocation completes, right before Lambda freezes the process */
|
|
1080
|
-
onAfterInvoke?: (args: HandlerArgs<C, D, P, S>) => void | Promise<void>;
|
|
1081
|
-
/**
|
|
1082
|
-
* Factory function to initialize shared state for callbacks.
|
|
1083
|
-
* Called once on cold start, result is cached and reused across invocations.
|
|
1084
|
-
* When deps/params are declared, receives them as argument.
|
|
1085
|
-
* Supports both sync and async return values.
|
|
1086
|
-
*/
|
|
1087
|
-
setup?: SetupFactory$1<C, T, D, P, S>;
|
|
1088
|
-
/**
|
|
1089
|
-
* Dependencies on other handlers (tables, queues, etc.).
|
|
1090
|
-
* Typed clients are injected into the handler via the `deps` argument.
|
|
1091
|
-
* Pass a function returning the deps object: `deps: () => ({ orders })`.
|
|
1092
|
-
*/
|
|
1093
|
-
deps?: () => D & {};
|
|
1094
|
-
/**
|
|
1095
|
-
* SSM Parameter Store parameters.
|
|
1096
|
-
* Declare with `param()` helper. Values are fetched and cached at cold start.
|
|
1097
|
-
* Typed values are injected into the handler via the `config` argument.
|
|
1098
|
-
*/
|
|
1099
|
-
config?: P;
|
|
1100
|
-
/**
|
|
1101
|
-
* Static file glob patterns to bundle into the Lambda ZIP.
|
|
1102
|
-
* Files are accessible at runtime via the `files` callback argument.
|
|
1103
|
-
*/
|
|
1104
|
-
static?: S;
|
|
1105
|
-
};
|
|
1106
|
-
/** Per-record processing: onRecord with optional onBatchComplete */
|
|
1107
|
-
type DefineTableWithOnRecord<T = Record<string, unknown>, C = undefined, R = void, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {
|
|
1108
|
-
onRecord: TableRecordFn<T, C, R, D, P, S>;
|
|
1109
|
-
onBatchComplete?: TableBatchCompleteFn<T, C, R, D, P, S>;
|
|
1110
|
-
onBatch?: never;
|
|
1111
|
-
};
|
|
1112
|
-
/** Batch processing: onBatch processes all records at once */
|
|
1113
|
-
type DefineTableWithOnBatch<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {
|
|
1114
|
-
onBatch: TableBatchFn<T, C, D, P, S>;
|
|
1115
|
-
onRecord?: never;
|
|
1116
|
-
onBatchComplete?: never;
|
|
1117
|
-
};
|
|
1118
|
-
/** Resource-only: no handler, just creates the table */
|
|
1119
|
-
type DefineTableResourceOnly<T = Record<string, unknown>, C = undefined, D = undefined, P = undefined, S extends string[] | undefined = undefined> = DefineTableBase<T, C, D, P, S> & {
|
|
1120
|
-
onRecord?: never;
|
|
1121
|
-
onBatch?: never;
|
|
1122
|
-
onBatchComplete?: never;
|
|
1123
|
-
};
|
|
1124
|
-
type DefineTableOptions<T = Record<string, unknown>, C = undefined, R = void, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined, S extends string[] | undefined = undefined> = DefineTableWithOnRecord<T, C, R, D, P, S> | DefineTableWithOnBatch<T, C, D, P, S> | DefineTableResourceOnly<T, C, D, P, S>;
|
|
959
|
+
batch: readonly TableRecord<T>[];
|
|
960
|
+
} & SpreadCtx$1<C>) => Promise<void>;
|
|
961
|
+
/**
|
|
962
|
+
* Batch handler function for DynamoDB stream records.
|
|
963
|
+
* Called once with all records in the batch.
|
|
964
|
+
* Return `{ failures: string[] }` (sequence numbers) for partial batch failure reporting.
|
|
965
|
+
*/
|
|
966
|
+
type TableBatchFn<T = Record<string, unknown>, C = undefined> = (args: {
|
|
967
|
+
records: readonly TableRecord<T>[];
|
|
968
|
+
} & SpreadCtx$1<C>) => Promise<void | {
|
|
969
|
+
failures: string[];
|
|
970
|
+
}>;
|
|
971
|
+
/** Static config extracted by AST (no runtime callbacks) */
|
|
1125
972
|
/**
|
|
1126
|
-
*
|
|
973
|
+
* Handler object created by defineTable.
|
|
974
|
+
* Used by runtime wrappers and as type annotation for circular deps.
|
|
1127
975
|
* @internal
|
|
1128
976
|
*/
|
|
1129
977
|
type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
@@ -1131,15 +979,63 @@ type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
|
1131
979
|
readonly __spec: TableConfig;
|
|
1132
980
|
readonly schema?: (input: unknown) => T;
|
|
1133
981
|
readonly onError?: (...args: any[]) => any;
|
|
1134
|
-
readonly
|
|
982
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
1135
983
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
1136
984
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
1137
985
|
readonly config?: Record<string, unknown>;
|
|
1138
986
|
readonly static?: string[];
|
|
1139
987
|
readonly onRecord?: (...args: any[]) => any;
|
|
1140
|
-
readonly
|
|
1141
|
-
readonly onBatch?: (...args: any[]) => any;
|
|
988
|
+
readonly onRecordBatch?: (...args: any[]) => any;
|
|
1142
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
|
+
}
|
|
1143
1039
|
/**
|
|
1144
1040
|
* Define a DynamoDB table with optional stream handler (single-table design).
|
|
1145
1041
|
*
|
|
@@ -1148,25 +1044,30 @@ type TableHandler<T = Record<string, unknown>, C = any> = {
|
|
|
1148
1044
|
*
|
|
1149
1045
|
* @example Table with stream handler
|
|
1150
1046
|
* ```typescript
|
|
1151
|
-
*
|
|
1152
|
-
*
|
|
1153
|
-
*
|
|
1154
|
-
* streamView: "NEW_AND_OLD_IMAGES",
|
|
1155
|
-
* batchSize: 10,
|
|
1156
|
-
* onRecord: async ({ record }) => {
|
|
1047
|
+
* export const orders = defineTable<OrderData>({ batchSize: 10, concurrency: 5 })
|
|
1048
|
+
* .setup(({ table }) => ({ table }))
|
|
1049
|
+
* .onRecord(async ({ record, table }) => {
|
|
1157
1050
|
* if (record.eventName === "INSERT") {
|
|
1158
|
-
* console.log("New order:", record.new?.data
|
|
1051
|
+
* console.log("New order:", record.new?.data);
|
|
1159
1052
|
* }
|
|
1160
|
-
* }
|
|
1161
|
-
* });
|
|
1053
|
+
* })
|
|
1162
1054
|
* ```
|
|
1163
1055
|
*
|
|
1164
1056
|
* @example Table only (no Lambda)
|
|
1165
1057
|
* ```typescript
|
|
1166
|
-
* export const users = defineTable(
|
|
1058
|
+
* export const users = defineTable<User>().build()
|
|
1059
|
+
* ```
|
|
1060
|
+
*
|
|
1061
|
+
* @example Table as dependency (resource-only, no Lambda)
|
|
1062
|
+
* ```typescript
|
|
1063
|
+
* export const sessions = defineTable<Session>().build()
|
|
1167
1064
|
* ```
|
|
1168
1065
|
*/
|
|
1169
|
-
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>;
|
|
1170
1071
|
|
|
1171
1072
|
/**
|
|
1172
1073
|
* Configuration for deploying an SSR framework (Nuxt, Astro, etc.)
|
|
@@ -1223,94 +1124,7 @@ type AppHandler = {
|
|
|
1223
1124
|
* });
|
|
1224
1125
|
* ```
|
|
1225
1126
|
*/
|
|
1226
|
-
declare const defineApp: (options: AppConfig) => AppHandler;
|
|
1227
|
-
|
|
1228
|
-
type AuthConfig<_T = undefined> = {
|
|
1229
|
-
/** Path to redirect unauthenticated users to (used by static sites). */
|
|
1230
|
-
loginPath: string;
|
|
1231
|
-
/** Paths that don't require authentication. Supports trailing `*` wildcard. */
|
|
1232
|
-
public?: string[];
|
|
1233
|
-
/** Default session lifetime (default: "7d"). Accepts seconds or duration string. */
|
|
1234
|
-
expiresIn?: Duration;
|
|
1235
|
-
};
|
|
1236
|
-
/**
|
|
1237
|
-
* Branded auth object returned by `defineAuth()`.
|
|
1238
|
-
* Pass to `defineApi({ auth })` and `defineStaticSite({ auth })`.
|
|
1239
|
-
*/
|
|
1240
|
-
type Auth<T = undefined> = AuthConfig<T> & {
|
|
1241
|
-
readonly __brand: "effortless-auth";
|
|
1242
|
-
/** @internal phantom type marker for session data */
|
|
1243
|
-
readonly __session?: T;
|
|
1244
|
-
};
|
|
1245
|
-
/** API token authentication strategy. Verifies tokens from HTTP headers (e.g. Authorization: Bearer). */
|
|
1246
|
-
type ApiTokenStrategy<T, D = undefined> = {
|
|
1247
|
-
/** HTTP header to read the token from. Default: "authorization" (strips "Bearer " prefix). */
|
|
1248
|
-
header?: string;
|
|
1249
|
-
/** Verify the token value and return session data, or null if invalid. */
|
|
1250
|
-
verify: [D] extends [undefined] ? (value: string) => T | null | Promise<T | null> : (value: string, ctx: {
|
|
1251
|
-
deps: D;
|
|
1252
|
-
}) => T | null | Promise<T | null>;
|
|
1253
|
-
/** Cache verified token results for this duration. Avoids calling verify on every request. */
|
|
1254
|
-
cacheTtl?: Duration;
|
|
1255
|
-
};
|
|
1256
|
-
/**
|
|
1257
|
-
* Define authentication for API handlers and static sites.
|
|
1258
|
-
*
|
|
1259
|
-
* Session-based auth uses HMAC-signed cookies (auto-managed by the framework).
|
|
1260
|
-
*
|
|
1261
|
-
* - Lambda@Edge middleware verifies cookie signatures for static sites
|
|
1262
|
-
* - API handler gets `auth.createSession()` / `auth.clearSession()` / `auth.session` helpers
|
|
1263
|
-
* - HMAC secret is auto-generated and stored in SSM Parameter Store
|
|
1264
|
-
*
|
|
1265
|
-
* @typeParam T - Session data type. When provided, `createSession(data)` requires typed payload
|
|
1266
|
-
* and `auth.session` is typed as `T` in handler args.
|
|
1267
|
-
*
|
|
1268
|
-
* @example
|
|
1269
|
-
* ```typescript
|
|
1270
|
-
* type Session = { userId: string; role: "admin" | "user" };
|
|
1271
|
-
*
|
|
1272
|
-
* const auth = defineAuth<Session>({
|
|
1273
|
-
* loginPath: '/login',
|
|
1274
|
-
* public: ['/login', '/api/login'],
|
|
1275
|
-
* expiresIn: '7d',
|
|
1276
|
-
* })
|
|
1277
|
-
*
|
|
1278
|
-
* export const api = defineApi({ auth, ... })
|
|
1279
|
-
* export const webapp = defineStaticSite({ auth, ... })
|
|
1280
|
-
* ```
|
|
1281
|
-
*/
|
|
1282
|
-
declare const defineAuth: <T = undefined>(options: AuthConfig<T>) => Auth<T>;
|
|
1283
|
-
/** Options for creating a session */
|
|
1284
|
-
type SessionOptions = {
|
|
1285
|
-
expiresIn?: Duration;
|
|
1286
|
-
};
|
|
1287
|
-
/** Session response with Set-Cookie header */
|
|
1288
|
-
type SessionResponse = {
|
|
1289
|
-
status: 200;
|
|
1290
|
-
body: {
|
|
1291
|
-
ok: true;
|
|
1292
|
-
};
|
|
1293
|
-
headers: Record<string, string>;
|
|
1294
|
-
};
|
|
1295
|
-
/**
|
|
1296
|
-
* Auth helpers injected into API handler callback args when `auth` is configured.
|
|
1297
|
-
* @typeParam T - Session data type (undefined = no custom data)
|
|
1298
|
-
*/
|
|
1299
|
-
type AuthHelpers<T = undefined> = {
|
|
1300
|
-
clearSession(): {
|
|
1301
|
-
status: 200;
|
|
1302
|
-
body: {
|
|
1303
|
-
ok: true;
|
|
1304
|
-
};
|
|
1305
|
-
headers: Record<string, string>;
|
|
1306
|
-
};
|
|
1307
|
-
/** The current session data (from cookie or API token). Undefined if no valid session. */
|
|
1308
|
-
session: T extends undefined ? undefined : T | undefined;
|
|
1309
|
-
} & ([T] extends [undefined] ? {
|
|
1310
|
-
createSession(options?: SessionOptions): SessionResponse;
|
|
1311
|
-
} : {
|
|
1312
|
-
createSession(data: T, options?: SessionOptions): SessionResponse;
|
|
1313
|
-
});
|
|
1127
|
+
declare const defineApp: () => (options: AppConfig) => AppHandler;
|
|
1314
1128
|
|
|
1315
1129
|
/** Any branded handler that deploys to API Gateway (HttpHandler, ApiHandler, etc.) */
|
|
1316
1130
|
type AnyRoutableHandler = {
|
|
@@ -1371,8 +1185,6 @@ type StaticSiteConfig = {
|
|
|
1371
1185
|
errorPage?: string;
|
|
1372
1186
|
/** Lambda@Edge middleware that runs before serving pages. Use for auth checks, redirects, etc. */
|
|
1373
1187
|
middleware?: MiddlewareHandler;
|
|
1374
|
-
/** Cookie-based authentication. Auto-generates Lambda@Edge middleware that verifies signed cookies. */
|
|
1375
|
-
auth?: Auth<any>;
|
|
1376
1188
|
/** SEO: auto-generate sitemap.xml and robots.txt at deploy time, optionally submit URLs to Google Indexing API */
|
|
1377
1189
|
seo?: StaticSiteSeo;
|
|
1378
1190
|
};
|
|
@@ -1407,48 +1219,115 @@ type StaticSiteHandler = {
|
|
|
1407
1219
|
* });
|
|
1408
1220
|
* ```
|
|
1409
1221
|
*
|
|
1410
|
-
* @example Protected site with middleware (Lambda@Edge)
|
|
1411
|
-
* ```typescript
|
|
1412
|
-
* export const admin = defineStaticSite({
|
|
1413
|
-
* dir: "admin/dist",
|
|
1414
|
-
* middleware: async (request) => {
|
|
1415
|
-
* if (!request.cookies.session) {
|
|
1416
|
-
* return { redirect: "/login" };
|
|
1417
|
-
* }
|
|
1418
|
-
* },
|
|
1419
|
-
* });
|
|
1420
|
-
* ```
|
|
1421
1222
|
*/
|
|
1422
|
-
declare const defineStaticSite: (options: StaticSiteConfig) => StaticSiteHandler;
|
|
1223
|
+
declare const defineStaticSite: () => (options: StaticSiteConfig) => StaticSiteHandler;
|
|
1423
1224
|
|
|
1424
|
-
/**
|
|
1425
|
-
type
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1225
|
+
/** Options for creating a session */
|
|
1226
|
+
type SessionOptions = {
|
|
1227
|
+
expiresIn?: Duration;
|
|
1228
|
+
};
|
|
1229
|
+
/** Session response with Set-Cookie header */
|
|
1230
|
+
type SessionResponse = {
|
|
1231
|
+
status: 200;
|
|
1232
|
+
body: {
|
|
1233
|
+
ok: true;
|
|
1234
|
+
};
|
|
1235
|
+
headers: Record<string, string>;
|
|
1236
|
+
};
|
|
1237
|
+
/**
|
|
1238
|
+
* Auth helpers injected into API handler callback args when `auth` is configured.
|
|
1239
|
+
* @typeParam T - Session data type (from `AuthOptions<T>`)
|
|
1240
|
+
*/
|
|
1241
|
+
type AuthHelpers<T = unknown> = {
|
|
1242
|
+
/** Create a signed session cookie with typed data. */
|
|
1243
|
+
createSession(data: T, options?: SessionOptions): SessionResponse;
|
|
1244
|
+
/** Clear the session cookie. */
|
|
1245
|
+
clearSession(): {
|
|
1246
|
+
status: 200;
|
|
1247
|
+
body: {
|
|
1248
|
+
ok: true;
|
|
1249
|
+
};
|
|
1250
|
+
headers: Record<string, string>;
|
|
1251
|
+
};
|
|
1252
|
+
/** The current session data (from cookie or API token). Undefined if no valid session. */
|
|
1253
|
+
session: T | undefined;
|
|
1254
|
+
};
|
|
1255
|
+
|
|
1256
|
+
/** Auth config options (user-facing) */
|
|
1257
|
+
type AuthOptions<A = unknown> = {
|
|
1258
|
+
/** HMAC secret for signing session cookies. Use `secret()` or `param()` in config. */
|
|
1259
|
+
secret: string;
|
|
1260
|
+
/** Default session lifetime (default: "7d"). */
|
|
1261
|
+
expiresIn?: Duration;
|
|
1262
|
+
/** Optional API token strategy for external clients. */
|
|
1263
|
+
apiToken?: {
|
|
1264
|
+
/** HTTP header to read the token from. Default: "authorization" (strips "Bearer " prefix). */
|
|
1265
|
+
header?: string;
|
|
1266
|
+
/** Verify the token value and return session data, or null if invalid. */
|
|
1267
|
+
verify: (value: string) => A | null | Promise<A | null>;
|
|
1268
|
+
/** Cache verified token results for this duration. */
|
|
1269
|
+
cacheTtl?: Duration;
|
|
1270
|
+
};
|
|
1271
|
+
};
|
|
1272
|
+
/** Branded auth config — created by `enableAuth<A>()` helper, carries session type A */
|
|
1273
|
+
type ApiAuthConfig<A = unknown> = AuthOptions<A> & {
|
|
1274
|
+
readonly __sessionType: A;
|
|
1275
|
+
};
|
|
1276
|
+
/** Type of the `enableAuth` helper injected into setup args */
|
|
1277
|
+
type EnableAuth = <A = unknown>(options: AuthOptions<A>) => ApiAuthConfig<A>;
|
|
1278
|
+
/** Extract session type A from ctx.auth if present */
|
|
1279
|
+
type ExtractAuth<C> = C extends {
|
|
1280
|
+
auth: ApiAuthConfig<infer A>;
|
|
1281
|
+
} ? A : undefined;
|
|
1282
|
+
/** Property names reserved by the framework — cannot be used in setup return */
|
|
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;
|
|
1288
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
1289
|
+
/** Parsed route definition stored at runtime */
|
|
1290
|
+
type RouteEntry = {
|
|
1291
|
+
method: HttpMethod;
|
|
1292
|
+
path: string;
|
|
1293
|
+
onRequest: (...args: any[]) => any;
|
|
1294
|
+
public?: boolean;
|
|
1295
|
+
};
|
|
1296
|
+
/** Spread ctx into route args: Omit auth config, add AuthHelpers if present */
|
|
1297
|
+
type SpreadCtx<C> = ([C] extends [undefined] ? {} : Omit<C & {}, 'auth'>) & ([ExtractAuth<C>] extends [undefined] ? {} : {
|
|
1298
|
+
auth: AuthHelpers<ExtractAuth<C>>;
|
|
1299
|
+
});
|
|
1300
|
+
/** Callback args available inside each route — ctx is spread into args */
|
|
1301
|
+
type RouteArgs<C, ST> = SpreadCtx<C> & {
|
|
1436
1302
|
req: HttpRequest;
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1303
|
+
input: unknown;
|
|
1304
|
+
ok: OkHelper;
|
|
1305
|
+
fail: FailHelper;
|
|
1306
|
+
} & ([ST] extends [true] ? {
|
|
1440
1307
|
stream: ResponseStream;
|
|
1441
|
-
} : {})
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
/**
|
|
1445
|
-
type
|
|
1308
|
+
} : {});
|
|
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 = {
|
|
1313
|
+
public?: boolean;
|
|
1314
|
+
};
|
|
1315
|
+
/** Setup factory — receives deps/config/files/enableAuth based on what was declared */
|
|
1316
|
+
type SetupArgs<D, P, HasFiles extends boolean> = {
|
|
1317
|
+
enableAuth: EnableAuth;
|
|
1318
|
+
ok: OkHelper;
|
|
1319
|
+
fail: FailHelper;
|
|
1320
|
+
} & ([D] extends [undefined] ? {} : {
|
|
1446
1321
|
deps: ResolveDeps<D>;
|
|
1447
1322
|
}) & ([P] extends [undefined] ? {} : {
|
|
1448
1323
|
config: ResolveConfig<P & {}>;
|
|
1449
|
-
}) & (
|
|
1324
|
+
}) & (HasFiles extends true ? {
|
|
1450
1325
|
files: StaticFiles;
|
|
1451
|
-
}
|
|
1326
|
+
} : {});
|
|
1327
|
+
/** Validate that setup return type does not use reserved property names */
|
|
1328
|
+
type ValidateSetupReturn<C> = C & {
|
|
1329
|
+
[K in ReservedKeys]?: never;
|
|
1330
|
+
};
|
|
1452
1331
|
/** Static config extracted by AST (no runtime callbacks) */
|
|
1453
1332
|
type ApiConfig = {
|
|
1454
1333
|
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
@@ -1458,104 +1337,104 @@ type ApiConfig = {
|
|
|
1458
1337
|
/** Enable response streaming. When true, the Lambda Function URL uses RESPONSE_STREAM invoke mode. */
|
|
1459
1338
|
stream?: boolean;
|
|
1460
1339
|
};
|
|
1461
|
-
/**
|
|
1462
|
-
* Options for defining a CQRS-style API endpoint.
|
|
1463
|
-
*
|
|
1464
|
-
* - `get` routes handle queries (path-based routing, no body)
|
|
1465
|
-
* - `post` handles commands (single entry point, discriminated union via `schema`)
|
|
1466
|
-
*/
|
|
1467
|
-
type DefineApiOptions<T = undefined, C = undefined, D extends Record<string, AnyDepHandler> | undefined = undefined, P extends Record<string, AnyParamRef> | undefined = undefined, S extends string[] | undefined = undefined, ST extends boolean | undefined = undefined, A extends Auth<any> | undefined = undefined> = {
|
|
1468
|
-
/** Lambda function settings (memory, timeout, permissions, etc.) */
|
|
1469
|
-
lambda?: LambdaWithPermissions;
|
|
1470
|
-
/** Base path prefix for all routes (e.g., "/api") */
|
|
1471
|
-
basePath: `/${string}`;
|
|
1472
|
-
/** Enable response streaming. When true, routes receive a `stream` arg for SSE. Routes can still return HttpResponse normally. */
|
|
1473
|
-
stream?: ST;
|
|
1474
|
-
/** Session-based authentication. Injects `auth` helpers (createSession/clearSession/session) into handler args. */
|
|
1475
|
-
auth?: A;
|
|
1476
|
-
/** API token authentication for external clients (Bearer tokens, API keys). Has access to deps. */
|
|
1477
|
-
apiToken?: ApiTokenStrategy<SessionOf<A>, [D] extends [undefined] ? undefined : ResolveDeps<D>>;
|
|
1478
|
-
/**
|
|
1479
|
-
* Factory function to initialize shared state.
|
|
1480
|
-
* Called once on cold start, result is cached and reused across invocations.
|
|
1481
|
-
*/
|
|
1482
|
-
setup?: SetupFactory<C, D, P, S>;
|
|
1483
|
-
/** Dependencies on other handlers (tables, queues, etc.): `deps: () => ({ users })` */
|
|
1484
|
-
deps?: () => D & {};
|
|
1485
|
-
/** SSM Parameter Store parameters */
|
|
1486
|
-
config?: P;
|
|
1487
|
-
/** Static file glob patterns to bundle into the Lambda ZIP */
|
|
1488
|
-
static?: S;
|
|
1489
|
-
/** Error handler called when schema validation or handler throws */
|
|
1490
|
-
onError?: (args: {
|
|
1491
|
-
error: unknown;
|
|
1492
|
-
req: HttpRequest;
|
|
1493
|
-
} & HandlerArgs<C, D, P, S>) => HttpResponse;
|
|
1494
|
-
/** Called after each invocation completes, right before Lambda freezes the process */
|
|
1495
|
-
onAfterInvoke?: (args: HandlerArgs<C, D, P, S>) => void | Promise<void>;
|
|
1496
|
-
/** GET routes — query handlers keyed by relative path (e.g., "/users/{id}") */
|
|
1497
|
-
get?: Record<`/${string}`, ApiGetHandlerFn<C, D, P, S, ST, A>>;
|
|
1498
|
-
/**
|
|
1499
|
-
* Schema for POST body validation. Use with discriminated unions:
|
|
1500
|
-
* ```typescript
|
|
1501
|
-
* schema: Action.parse,
|
|
1502
|
-
* post: async ({ data }) => { switch (data.action) { ... } }
|
|
1503
|
-
* ```
|
|
1504
|
-
*/
|
|
1505
|
-
schema?: (input: unknown) => T;
|
|
1506
|
-
/** POST handler — single entry point for commands */
|
|
1507
|
-
post?: ApiPostHandlerFn<T, C, D, P, S, ST, A>;
|
|
1508
|
-
};
|
|
1509
1340
|
/** Internal handler object created by defineApi */
|
|
1510
|
-
type ApiHandler<
|
|
1341
|
+
type ApiHandler<C = undefined> = {
|
|
1511
1342
|
readonly __brand: "effortless-api";
|
|
1512
1343
|
readonly __spec: ApiConfig;
|
|
1513
|
-
readonly schema?: (input: unknown) => T;
|
|
1514
1344
|
readonly onError?: (...args: any[]) => any;
|
|
1515
|
-
readonly
|
|
1345
|
+
readonly onCleanup?: (...args: any[]) => any;
|
|
1516
1346
|
readonly setup?: (...args: any[]) => C | Promise<C>;
|
|
1517
1347
|
readonly deps?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
1518
1348
|
readonly config?: Record<string, unknown>;
|
|
1519
1349
|
readonly static?: string[];
|
|
1520
|
-
readonly
|
|
1521
|
-
readonly apiToken?: ApiTokenStrategy<any, any>;
|
|
1522
|
-
readonly get?: Record<`/${string}`, (...args: any[]) => any>;
|
|
1523
|
-
readonly post?: (...args: any[]) => any;
|
|
1350
|
+
readonly routes?: RouteEntry[];
|
|
1524
1351
|
};
|
|
1525
|
-
/**
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
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
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Builder interface for defining API handlers.
|
|
1382
|
+
*
|
|
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.
|
|
1531
1415
|
*
|
|
1532
1416
|
* @example
|
|
1533
1417
|
* ```typescript
|
|
1534
|
-
*
|
|
1535
|
-
*
|
|
1536
|
-
*
|
|
1537
|
-
*
|
|
1538
|
-
*
|
|
1539
|
-
*
|
|
1540
|
-
*
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1546
|
-
*
|
|
1547
|
-
* }
|
|
1548
|
-
*
|
|
1549
|
-
* schema: Action.parse,
|
|
1550
|
-
* post: async ({ data, deps }) => {
|
|
1551
|
-
* switch (data.action) {
|
|
1552
|
-
* case "create": return { status: 201, body: await deps.users.put(data) }
|
|
1553
|
-
* case "delete": return { status: 200, body: await deps.users.delete(data.id) }
|
|
1554
|
-
* }
|
|
1555
|
-
* },
|
|
1556
|
-
* })
|
|
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 }) => ({
|
|
1427
|
+
* users: deps.users,
|
|
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 })
|
|
1557
1433
|
* ```
|
|
1558
1434
|
*/
|
|
1559
|
-
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>;
|
|
1560
1439
|
|
|
1561
|
-
export { type AnyParamRef, type AnySecretRef, type ApiConfig, type ApiHandler, type
|
|
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 };
|