@karmaniverous/smoz 0.2.8 → 0.2.10
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/README.md +82 -81
- package/dist/cjs/index.js +20 -10
- package/dist/index.d.ts +43 -35
- package/dist/mjs/index.js +20 -10
- package/package.json +13 -6
- package/templates/default/.node-version +1 -0
- package/templates/default/.nvmrc +1 -0
- package/templates/default/app/config/app.config.ts +1 -2
- package/templates/default/package.json +52 -47
package/README.md
CHANGED
|
@@ -1,81 +1,82 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# SMOZ
|
|
4
|
-
|
|
5
|
-
[Serverless](https://www.serverless.com/) · [Middy](https://middy.js.org/) · [OpenAPI 3.1](https://spec.openapis.org/oas/latest.html) · [Zod](https://zod.dev/)
|
|
6
|
-
|
|
7
|
-
[](https://www.npmjs.com/package/@karmaniverous/smoz)
|
|
8
|
-

|
|
9
|
-
[](https://docs.karmanivero.us/smoz)
|
|
10
|
-
[](https://github.com/karmaniverous/smoz/tree/main/CHANGELOG.md)
|
|
11
|
-
[](https://github.com/karmaniverous/smoz/tree/main/LICENSE.md)
|
|
12
|
-
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
SMOZ is a small, pragmatic toolkit for authoring AWS Lambda handlers with [Middy] and [Zod], then aggregating Serverless functions and hand‑crafted OpenAPI 3.1 paths from a single, schema‑first application definition.
|
|
16
|
-
|
|
17
|
-
- Keep prod code testable and framework‑agnostic
|
|
18
|
-
- HTTP middleware with validation, shaping, errors, CORS, negotiation, and HEAD
|
|
19
|
-
- Non‑HTTP flows stay lean (no middleware overhead)
|
|
20
|
-
|
|
21
|
-
## Quick start (from zero)
|
|
22
|
-
|
|
23
|
-
From an empty directory:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npx @karmaniverous/smoz init -i
|
|
27
|
-
npx smoz dev -p 3000
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
- The first command scaffolds a new app and installs dependencies (including a local `smoz` bin).
|
|
31
|
-
- The second command starts the inline local backend and keeps registers + OpenAPI fresh.
|
|
32
|
-
- Open http://localhost:3000/openapi in your browser.
|
|
33
|
-
|
|
34
|
-
Prefer `serverless‑offline`?
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
npx smoz dev -l offline -p 3000
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Add your first endpoint (avoid clashing with the template’s hello):
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
npx smoz add rest/foo/get
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Quick links
|
|
47
|
-
|
|
48
|
-
- [Overview](https://docs.karmanivero.us/smoz/documents/Overview.html)
|
|
49
|
-
- [Why smoz?](https://docs.karmanivero.us/smoz/documents/Why_smoz_.html)
|
|
50
|
-
- [Getting started](https://docs.karmanivero.us/smoz/documents/Getting_started.html)
|
|
51
|
-
- [10-minute tour](https://docs.karmanivero.us/smoz/documents/10%E2%80%91minute_tour.html)
|
|
52
|
-
- [HTTP Middleware](https://docs.karmanivero.us/smoz/documents/HTTP_middleware.html)
|
|
53
|
-
- [Recipes](https://docs.karmanivero.us/smoz/documents/Recipes.html)
|
|
54
|
-
- [SQS function](https://docs.karmanivero.us/smoz/documents/Recipes.SQS_function.html)
|
|
55
|
-
- [
|
|
56
|
-
- [
|
|
57
|
-
- [
|
|
58
|
-
- [
|
|
59
|
-
- [
|
|
60
|
-
- [
|
|
61
|
-
- [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
- [
|
|
79
|
-
- [
|
|
80
|
-
- [
|
|
81
|
-
- [
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# SMOZ
|
|
4
|
+
|
|
5
|
+
[Serverless](https://www.serverless.com/) · [Middy](https://middy.js.org/) · [OpenAPI 3.1](https://spec.openapis.org/oas/latest.html) · [Zod](https://zod.dev/)
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@karmaniverous/smoz)
|
|
8
|
+

|
|
9
|
+
[](https://docs.karmanivero.us/smoz)
|
|
10
|
+
[](https://github.com/karmaniverous/smoz/tree/main/CHANGELOG.md)
|
|
11
|
+
[](https://github.com/karmaniverous/smoz/tree/main/LICENSE.md)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
SMOZ is a small, pragmatic toolkit for authoring AWS Lambda handlers with [Middy] and [Zod], then aggregating Serverless functions and hand‑crafted OpenAPI 3.1 paths from a single, schema‑first application definition.
|
|
16
|
+
|
|
17
|
+
- Keep prod code testable and framework‑agnostic
|
|
18
|
+
- HTTP middleware with validation, shaping, errors, CORS, negotiation, and HEAD
|
|
19
|
+
- Non‑HTTP flows stay lean (no middleware overhead)
|
|
20
|
+
|
|
21
|
+
## Quick start (from zero)
|
|
22
|
+
|
|
23
|
+
From an empty directory:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @karmaniverous/smoz init -i
|
|
27
|
+
npx smoz dev -p 3000
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- The first command scaffolds a new app and installs dependencies (including a local `smoz` bin).
|
|
31
|
+
- The second command starts the inline local backend and keeps registers + OpenAPI fresh.
|
|
32
|
+
- Open http://localhost:3000/openapi in your browser.
|
|
33
|
+
|
|
34
|
+
Prefer `serverless‑offline`?
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx smoz dev -l offline -p 3000
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Add your first endpoint (avoid clashing with the template’s hello):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx smoz add rest/foo/get
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick links
|
|
47
|
+
|
|
48
|
+
- [Overview](https://docs.karmanivero.us/smoz/documents/Overview.html)
|
|
49
|
+
- [Why smoz?](https://docs.karmanivero.us/smoz/documents/Why_smoz_.html)
|
|
50
|
+
- [Getting started](https://docs.karmanivero.us/smoz/documents/Getting_started.html)
|
|
51
|
+
- [10-minute tour](https://docs.karmanivero.us/smoz/documents/10%E2%80%91minute_tour.html)
|
|
52
|
+
- [HTTP Middleware](https://docs.karmanivero.us/smoz/documents/HTTP_middleware.html)
|
|
53
|
+
- [Recipes](https://docs.karmanivero.us/smoz/documents/Recipes.html)
|
|
54
|
+
- [SQS function](https://docs.karmanivero.us/smoz/documents/Recipes.SQS_function.html)
|
|
55
|
+
- [Step Functions function](https://docs.karmanivero.us/smoz/documents/Recipes.Step_function.html)
|
|
56
|
+
- [Contexts + Cognito authorizer](https://docs.karmanivero.us/smoz/documents/Recipes.Contexts_+_Cognito_authorizer.html) - [Custom middleware insertion](https://docs.karmanivero.us/smoz/documents/Recipes.Custom_middleware_insertion.html)
|
|
57
|
+
- [Per‑function env](<https://docs.karmanivero.us/smoz/documents/Recipes.Per%E2%80%91function_env_(fnEnvKeys).html>)
|
|
58
|
+
- [Observability](<https://docs.karmanivero.us/smoz/documents/Recipes.Observability_(requestId_header).html>)
|
|
59
|
+
- [Troubleshooting](https://docs.karmanivero.us/smoz/documents/Recipes.Troubleshooting.html)
|
|
60
|
+
- [Templates](https://docs.karmanivero.us/smoz/documents/Templates.html)
|
|
61
|
+
- [CLI](https://docs.karmanivero.us/smoz/documents/CLI.html)
|
|
62
|
+
- [Contributing](https://docs.karmanivero.us/smoz/documents/Contributing.html)
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm i @karmaniverous/smoz zod zod-openapi
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Dev tooling (recommended):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm i -D typescript typescript-eslint eslint prettier typedoc
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Docs and reference
|
|
77
|
+
|
|
78
|
+
- [Docs site](https://docs.karmanivero.us/smoz)
|
|
79
|
+
- [Changelog](https://github.com/karmaniverous/smoz/tree/main/CHANGELOG.md)
|
|
80
|
+
- [License](https://github.com/karmaniverous/smoz/tree/main/LICENSE.md)
|
|
81
|
+
- [Middy](https://middy.js.org/)
|
|
82
|
+
- [Zod](https://zod.dev/)
|
package/dist/cjs/index.js
CHANGED
|
@@ -30,12 +30,23 @@ const baseEventTypeMapSchema = zod.z.object({
|
|
|
30
30
|
firehose: zod.z.custom(),
|
|
31
31
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- Upstream AWS types mark this as deprecated; we retain the token for compatibility with existing apps.
|
|
32
32
|
'cognito-userpool': zod.z.custom(),
|
|
33
|
+
/**
|
|
34
|
+
* Step Functions → Lambda (Service Integration: Lambda Invoke)
|
|
35
|
+
*
|
|
36
|
+
* When Step Functions invokes Lambda via the AWS SDK integration
|
|
37
|
+
* (e.g., "arn:aws:states:::lambda:invoke"), the event received by the
|
|
38
|
+
* Lambda handler is an object that wraps the original input under a
|
|
39
|
+
* "Payload" key. The Payload is already parsed JSON.
|
|
40
|
+
*
|
|
41
|
+
* Notes:
|
|
42
|
+
* - We accept additional keys (e.g., StatusCode/ExecutedVersion in some
|
|
43
|
+
* patterns) via passthrough.
|
|
44
|
+
* - For the common “request/response” integration where Step Functions
|
|
45
|
+
* passes state directly, apps can still treat the event via their
|
|
46
|
+
* own app-local event map if needed.
|
|
47
|
+
*/
|
|
48
|
+
step: zod.z.object({ Payload: zod.z.unknown().optional() }).catchall(zod.z.unknown()),
|
|
33
49
|
});
|
|
34
|
-
// Notes:
|
|
35
|
-
// - This list intentionally includes widely used, generic AWS events.
|
|
36
|
-
// - Apps can extend the schema with custom or specialized tokens:
|
|
37
|
-
// const EventMap = baseEventTypeMapSchema.extend({ step: z.custom<MyStepEvent>() })
|
|
38
|
-
// - Only tokens listed in your App's httpEventTypeTokens are treated as HTTP by the runtime.
|
|
39
50
|
|
|
40
51
|
/**
|
|
41
52
|
* Stage artifacts factory.
|
|
@@ -1043,10 +1054,10 @@ const buildAllServerlessFunctions = (registry, serverless, buildFnEnv) => {
|
|
|
1043
1054
|
/**
|
|
1044
1055
|
* App (schema‑first)
|
|
1045
1056
|
*
|
|
1057
|
+
* Overloads on create() preserve strong inference when eventTypeMapSchema is omitted.
|
|
1046
1058
|
* Central orchestrator for a SMOZ application. You provide:
|
|
1047
1059
|
* - Global/stage parameter schemas and env exposure keys
|
|
1048
|
-
* - Serverless defaults (handler filename/export and context map)
|
|
1049
|
-
* - Event‑type map schema (extendable: e.g., add 'step')
|
|
1060
|
+
* - Serverless defaults (handler filename/export and context map) * - Event‑type map schema (extendable: e.g., add 'step')
|
|
1050
1061
|
*
|
|
1051
1062
|
* The instance:
|
|
1052
1063
|
* - Validates configuration
|
|
@@ -1130,6 +1141,7 @@ const buildAllServerlessFunctions = (registry, serverless, buildFnEnv) => {
|
|
|
1130
1141
|
* @param init - initialization object (schemas, serverless defaults, params/envKeys)
|
|
1131
1142
|
* @returns a new App instance
|
|
1132
1143
|
*/
|
|
1144
|
+
// Implementation (must come after overload signatures)
|
|
1133
1145
|
static create(init) {
|
|
1134
1146
|
return new App(init);
|
|
1135
1147
|
}
|
|
@@ -1137,9 +1149,7 @@ const buildAllServerlessFunctions = (registry, serverless, buildFnEnv) => {
|
|
|
1137
1149
|
* Register a function (HTTP or non‑HTTP).
|
|
1138
1150
|
*
|
|
1139
1151
|
* @typeParam EventType - A key from your eventTypeMapSchema (e.g., 'rest' | 'http' | 'sqs' | 'step')
|
|
1140
|
-
* @typeParam EventSchema - Optional Zod schema validated BEFORE the handler (refines event shape)
|
|
1141
|
-
* @typeParam ResponseSchema - Optional Zod schema validated AFTER the handler (refines response shape)
|
|
1142
|
-
* @param options - per‑function configuration (method/basePath/httpContexts for HTTP; serverless extras for non‑HTTP)
|
|
1152
|
+
* @typeParam EventSchema - Optional Zod schema validated BEFORE the handler (refines event shape) * @typeParam ResponseSchema - Optional Zod schema validated AFTER the handler (refines response shape) * @param options - per‑function configuration (method/basePath/httpContexts for HTTP; serverless extras for non‑HTTP)
|
|
1143
1153
|
* @returns a per‑function API: { handler(business), openapi(baseOperation), serverless(extras) }
|
|
1144
1154
|
*/
|
|
1145
1155
|
defineFunction(options) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ZodOpenApiOperationObject, ZodOpenApiPathItemObject, ZodOpenApiPathsObject } from 'zod-openapi';
|
|
2
2
|
import * as aws_lambda from 'aws-lambda';
|
|
3
|
-
import { APIGatewayProxyEvent,
|
|
3
|
+
import { APIGatewayProxyEvent, APIGatewayProxyEventV2, ALBEvent, SQSEvent, SNSEvent, S3Event, DynamoDBStreamEvent, KinesisStreamEvent, EventBridgeEvent, CloudWatchLogsEvent, SESEvent, CloudFrontRequestEvent, FirehoseTransformationEvent, CognitoUserPoolTriggerEvent, Context } from 'aws-lambda';
|
|
4
4
|
import { AWS } from '@serverless/typescript';
|
|
5
|
-
import { ZodObject, ZodRawShape
|
|
5
|
+
import { z, ZodObject, ZodRawShape } from 'zod';
|
|
6
6
|
import { MiddlewareObj } from '@middy/core';
|
|
7
7
|
import httpContentNegotiation from '@middy/http-content-negotiation';
|
|
8
8
|
import httpCors from '@middy/http-cors';
|
|
@@ -35,6 +35,39 @@ type MakeRequired<T extends object, U extends keyof T> = {
|
|
|
35
35
|
*/
|
|
36
36
|
type BaseOperation = MakeRequired<Omit<ZodOpenApiOperationObject, 'operationId'>, 'summary'>;
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* baseEventTypeMapSchema
|
|
40
|
+
* - Schema-first companion to BaseEventTypeMap.
|
|
41
|
+
* - Now includes a Step Functions event with an optional Payload wrapper.
|
|
42
|
+
* - Ensures z.infer<typeof baseEventTypeMapSchema> === BaseEventTypeMap.
|
|
43
|
+
*
|
|
44
|
+
* @remarks * Consumers typically extend this schema when creating an App to add
|
|
45
|
+
* project‑local event tokens (e.g., 'step').
|
|
46
|
+
* Only tokens listed in the app’s `httpEventTypeTokens` are treated as HTTP at runtime.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
declare const baseEventTypeMapSchema: z.ZodObject<{
|
|
50
|
+
rest: z.ZodCustom<APIGatewayProxyEvent, APIGatewayProxyEvent>;
|
|
51
|
+
http: z.ZodCustom<APIGatewayProxyEventV2, APIGatewayProxyEventV2>;
|
|
52
|
+
alb: z.ZodCustom<ALBEvent, ALBEvent>;
|
|
53
|
+
sqs: z.ZodCustom<SQSEvent, SQSEvent>;
|
|
54
|
+
sns: z.ZodCustom<SNSEvent, SNSEvent>;
|
|
55
|
+
s3: z.ZodCustom<S3Event, S3Event>;
|
|
56
|
+
dynamodb: z.ZodCustom<DynamoDBStreamEvent, DynamoDBStreamEvent>;
|
|
57
|
+
kinesis: z.ZodCustom<KinesisStreamEvent, KinesisStreamEvent>;
|
|
58
|
+
eventbridge: z.ZodCustom<EventBridgeEvent<string, unknown>, EventBridgeEvent<string, unknown>>;
|
|
59
|
+
'cloudwatch-logs': z.ZodCustom<CloudWatchLogsEvent, CloudWatchLogsEvent>;
|
|
60
|
+
ses: z.ZodCustom<SESEvent, SESEvent>;
|
|
61
|
+
cloudfront: z.ZodCustom<CloudFrontRequestEvent, CloudFrontRequestEvent>;
|
|
62
|
+
firehose: z.ZodCustom<FirehoseTransformationEvent, FirehoseTransformationEvent>;
|
|
63
|
+
'cognito-userpool': z.ZodCustom<CognitoUserPoolTriggerEvent, CognitoUserPoolTriggerEvent>;
|
|
64
|
+
step: z.ZodObject<{
|
|
65
|
+
Payload: z.ZodOptional<z.ZodUnknown>;
|
|
66
|
+
}, z.core.$catchall<z.ZodUnknown>>;
|
|
67
|
+
}, z.core.$strip>;
|
|
68
|
+
/** Canonical base event map type (schema‑first). Extend the schema in your App. */
|
|
69
|
+
type BaseEventTypeMap = z.infer<typeof baseEventTypeMapSchema>;
|
|
70
|
+
|
|
38
71
|
type Dict<T> = Record<string, T>;
|
|
39
72
|
type StagesFactoryInput<GlobalParams extends Record<string, unknown>, StageParams extends Record<string, unknown>> = {
|
|
40
73
|
globalParamsSchema: ZodObject<ZodRawShape>;
|
|
@@ -327,36 +360,6 @@ declare const buildSafeDefaults: (args: BuildSafeDefaultsArgs) => {
|
|
|
327
360
|
onError: M[];
|
|
328
361
|
};
|
|
329
362
|
|
|
330
|
-
/**
|
|
331
|
-
* baseEventTypeMapSchema
|
|
332
|
-
* - Schema-first companion to BaseEventTypeMap.
|
|
333
|
-
* - Ensures z.infer<typeof baseEventTypeMapSchema> === BaseEventTypeMap.
|
|
334
|
-
*
|
|
335
|
-
* @remarks
|
|
336
|
-
* Consumers typically extend this schema when creating an App to add
|
|
337
|
-
* project‑local event tokens (e.g., 'step').
|
|
338
|
-
* Only tokens listed in the app’s `httpEventTypeTokens` are treated as HTTP at runtime.
|
|
339
|
-
*/
|
|
340
|
-
|
|
341
|
-
declare const baseEventTypeMapSchema: z.ZodObject<{
|
|
342
|
-
rest: z.ZodCustom<APIGatewayProxyEvent, APIGatewayProxyEvent>;
|
|
343
|
-
http: z.ZodCustom<APIGatewayProxyEventV2, APIGatewayProxyEventV2>;
|
|
344
|
-
alb: z.ZodCustom<ALBEvent, ALBEvent>;
|
|
345
|
-
sqs: z.ZodCustom<SQSEvent, SQSEvent>;
|
|
346
|
-
sns: z.ZodCustom<SNSEvent, SNSEvent>;
|
|
347
|
-
s3: z.ZodCustom<S3Event, S3Event>;
|
|
348
|
-
dynamodb: z.ZodCustom<DynamoDBStreamEvent, DynamoDBStreamEvent>;
|
|
349
|
-
kinesis: z.ZodCustom<KinesisStreamEvent, KinesisStreamEvent>;
|
|
350
|
-
eventbridge: z.ZodCustom<EventBridgeEvent<string, unknown>, EventBridgeEvent<string, unknown>>;
|
|
351
|
-
'cloudwatch-logs': z.ZodCustom<CloudWatchLogsEvent, CloudWatchLogsEvent>;
|
|
352
|
-
ses: z.ZodCustom<SESEvent, SESEvent>;
|
|
353
|
-
cloudfront: z.ZodCustom<CloudFrontRequestEvent, CloudFrontRequestEvent>;
|
|
354
|
-
firehose: z.ZodCustom<FirehoseTransformationEvent, FirehoseTransformationEvent>;
|
|
355
|
-
'cognito-userpool': z.ZodCustom<CognitoUserPoolTriggerEvent, CognitoUserPoolTriggerEvent>;
|
|
356
|
-
}, z.core.$strip>;
|
|
357
|
-
/** Canonical base event map type (schema‑first). Extend the schema in your App. */
|
|
358
|
-
type BaseEventTypeMap = z.infer<typeof baseEventTypeMapSchema>;
|
|
359
|
-
|
|
360
363
|
/** HTTP methods supported from zod-openapi's PathItem shape (excluding helper 'id'). */
|
|
361
364
|
type MethodKey = keyof Omit<ZodOpenApiPathItemObject, 'id'>;
|
|
362
365
|
/**
|
|
@@ -462,13 +465,14 @@ interface AppInit<GlobalParamsSchema extends ZodObj, StageParamsSchema extends Z
|
|
|
462
465
|
* @returns a new App instance
|
|
463
466
|
*/
|
|
464
467
|
static create<GlobalParamsSchema extends ZodObj, StageParamsSchema extends ZodObj, EventTypeMapSchema extends ZodObj>(init: AppInit<GlobalParamsSchema, StageParamsSchema, EventTypeMapSchema>): App<GlobalParamsSchema, StageParamsSchema, EventTypeMapSchema>;
|
|
468
|
+
static create<GlobalParamsSchema extends ZodObj, StageParamsSchema extends ZodObj>(init: Omit<AppInit<GlobalParamsSchema, StageParamsSchema, typeof baseEventTypeMapSchema>, 'eventTypeMapSchema'> & {
|
|
469
|
+
eventTypeMapSchema?: undefined;
|
|
470
|
+
}): App<GlobalParamsSchema, StageParamsSchema, typeof baseEventTypeMapSchema>;
|
|
465
471
|
/**
|
|
466
472
|
* Register a function (HTTP or non‑HTTP).
|
|
467
473
|
*
|
|
468
474
|
* @typeParam EventType - A key from your eventTypeMapSchema (e.g., 'rest' | 'http' | 'sqs' | 'step')
|
|
469
|
-
* @typeParam EventSchema - Optional Zod schema validated BEFORE the handler (refines event shape)
|
|
470
|
-
* @typeParam ResponseSchema - Optional Zod schema validated AFTER the handler (refines response shape)
|
|
471
|
-
* @param options - per‑function configuration (method/basePath/httpContexts for HTTP; serverless extras for non‑HTTP)
|
|
475
|
+
* @typeParam EventSchema - Optional Zod schema validated BEFORE the handler (refines event shape) * @typeParam ResponseSchema - Optional Zod schema validated AFTER the handler (refines response shape) * @param options - per‑function configuration (method/basePath/httpContexts for HTTP; serverless extras for non‑HTTP)
|
|
472
476
|
* @returns a per‑function API: { handler(business), openapi(baseOperation), serverless(extras) }
|
|
473
477
|
*/
|
|
474
478
|
defineFunction<EventType extends Extract<keyof z.infer<EventTypeMapSchema>, string>, EventSchema extends z.ZodType | undefined, ResponseSchema extends z.ZodType | undefined>(options: {
|
|
@@ -499,6 +503,10 @@ interface AppInit<GlobalParamsSchema extends ZodObj, StageParamsSchema extends Z
|
|
|
499
503
|
cloudfront: aws_lambda.CloudFrontRequestEvent;
|
|
500
504
|
firehose: aws_lambda.FirehoseTransformationEvent;
|
|
501
505
|
'cognito-userpool': aws_lambda.CognitoUserPoolTriggerEvent;
|
|
506
|
+
step: {
|
|
507
|
+
[x: string]: unknown;
|
|
508
|
+
Payload?: unknown;
|
|
509
|
+
};
|
|
502
510
|
})[EventType]>) => (event: unknown, context: aws_lambda.Context) => Promise<ResponseSchema extends z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>> ? z.core.output<ResponseSchema> : unknown>;
|
|
503
511
|
openapi: (baseOperation: BaseOperation) => void;
|
|
504
512
|
serverless: (extras: unknown) => void;
|
package/dist/mjs/index.js
CHANGED
|
@@ -28,12 +28,23 @@ const baseEventTypeMapSchema = z.object({
|
|
|
28
28
|
firehose: z.custom(),
|
|
29
29
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- Upstream AWS types mark this as deprecated; we retain the token for compatibility with existing apps.
|
|
30
30
|
'cognito-userpool': z.custom(),
|
|
31
|
+
/**
|
|
32
|
+
* Step Functions → Lambda (Service Integration: Lambda Invoke)
|
|
33
|
+
*
|
|
34
|
+
* When Step Functions invokes Lambda via the AWS SDK integration
|
|
35
|
+
* (e.g., "arn:aws:states:::lambda:invoke"), the event received by the
|
|
36
|
+
* Lambda handler is an object that wraps the original input under a
|
|
37
|
+
* "Payload" key. The Payload is already parsed JSON.
|
|
38
|
+
*
|
|
39
|
+
* Notes:
|
|
40
|
+
* - We accept additional keys (e.g., StatusCode/ExecutedVersion in some
|
|
41
|
+
* patterns) via passthrough.
|
|
42
|
+
* - For the common “request/response” integration where Step Functions
|
|
43
|
+
* passes state directly, apps can still treat the event via their
|
|
44
|
+
* own app-local event map if needed.
|
|
45
|
+
*/
|
|
46
|
+
step: z.object({ Payload: z.unknown().optional() }).catchall(z.unknown()),
|
|
31
47
|
});
|
|
32
|
-
// Notes:
|
|
33
|
-
// - This list intentionally includes widely used, generic AWS events.
|
|
34
|
-
// - Apps can extend the schema with custom or specialized tokens:
|
|
35
|
-
// const EventMap = baseEventTypeMapSchema.extend({ step: z.custom<MyStepEvent>() })
|
|
36
|
-
// - Only tokens listed in your App's httpEventTypeTokens are treated as HTTP by the runtime.
|
|
37
48
|
|
|
38
49
|
/**
|
|
39
50
|
* Stage artifacts factory.
|
|
@@ -1041,10 +1052,10 @@ const buildAllServerlessFunctions = (registry, serverless, buildFnEnv) => {
|
|
|
1041
1052
|
/**
|
|
1042
1053
|
* App (schema‑first)
|
|
1043
1054
|
*
|
|
1055
|
+
* Overloads on create() preserve strong inference when eventTypeMapSchema is omitted.
|
|
1044
1056
|
* Central orchestrator for a SMOZ application. You provide:
|
|
1045
1057
|
* - Global/stage parameter schemas and env exposure keys
|
|
1046
|
-
* - Serverless defaults (handler filename/export and context map)
|
|
1047
|
-
* - Event‑type map schema (extendable: e.g., add 'step')
|
|
1058
|
+
* - Serverless defaults (handler filename/export and context map) * - Event‑type map schema (extendable: e.g., add 'step')
|
|
1048
1059
|
*
|
|
1049
1060
|
* The instance:
|
|
1050
1061
|
* - Validates configuration
|
|
@@ -1128,6 +1139,7 @@ const buildAllServerlessFunctions = (registry, serverless, buildFnEnv) => {
|
|
|
1128
1139
|
* @param init - initialization object (schemas, serverless defaults, params/envKeys)
|
|
1129
1140
|
* @returns a new App instance
|
|
1130
1141
|
*/
|
|
1142
|
+
// Implementation (must come after overload signatures)
|
|
1131
1143
|
static create(init) {
|
|
1132
1144
|
return new App(init);
|
|
1133
1145
|
}
|
|
@@ -1135,9 +1147,7 @@ const buildAllServerlessFunctions = (registry, serverless, buildFnEnv) => {
|
|
|
1135
1147
|
* Register a function (HTTP or non‑HTTP).
|
|
1136
1148
|
*
|
|
1137
1149
|
* @typeParam EventType - A key from your eventTypeMapSchema (e.g., 'rest' | 'http' | 'sqs' | 'step')
|
|
1138
|
-
* @typeParam EventSchema - Optional Zod schema validated BEFORE the handler (refines event shape)
|
|
1139
|
-
* @typeParam ResponseSchema - Optional Zod schema validated AFTER the handler (refines response shape)
|
|
1140
|
-
* @param options - per‑function configuration (method/basePath/httpContexts for HTTP; serverless extras for non‑HTTP)
|
|
1150
|
+
* @typeParam EventSchema - Optional Zod schema validated BEFORE the handler (refines event shape) * @typeParam ResponseSchema - Optional Zod schema validated AFTER the handler (refines response shape) * @param options - per‑function configuration (method/basePath/httpContexts for HTTP; serverless extras for non‑HTTP)
|
|
1141
1151
|
* @returns a per‑function API: { handler(business), openapi(baseOperation), serverless(extras) }
|
|
1142
1152
|
*/
|
|
1143
1153
|
defineFunction(options) {
|
package/package.json
CHANGED
|
@@ -39,38 +39,42 @@
|
|
|
39
39
|
"@types/aws-lambda": "^8.10.152",
|
|
40
40
|
"@types/fs-extra": "^11.0.4",
|
|
41
41
|
"@types/http-errors": "^2.0.5",
|
|
42
|
+
"@types/node": "^22",
|
|
42
43
|
"@types/serverless": "^3.12.27",
|
|
43
44
|
"@vitest/coverage-v8": "^3.2.4",
|
|
44
45
|
"auto-changelog": "^2.5.0",
|
|
45
|
-
"eslint": "^9.35.0",
|
|
46
46
|
"eslint-config-prettier": "^10.1.8",
|
|
47
47
|
"eslint-plugin-prettier": "^5.5.4",
|
|
48
48
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
49
|
+
"eslint": "^9.35.0",
|
|
49
50
|
"fs-extra": "^11.3.1",
|
|
50
51
|
"knip": "^5.63.1",
|
|
51
52
|
"lefthook": "^1.13.0",
|
|
52
53
|
"prettier": "^3.6.2",
|
|
53
54
|
"release-it": "^19.0.4",
|
|
54
55
|
"rimraf": "^6.0.1",
|
|
55
|
-
"rollup": "^4.50.1",
|
|
56
56
|
"rollup-plugin-dts": "^6.2.3",
|
|
57
|
-
"
|
|
57
|
+
"rollup": "^4.50.1",
|
|
58
58
|
"serverless-apigateway-log-retention": "^1.1.0",
|
|
59
59
|
"serverless-deployment-bucket": "^1.6.0",
|
|
60
60
|
"serverless-domain-manager": "^8.0.0",
|
|
61
61
|
"serverless-offline": "^14.4.0",
|
|
62
62
|
"serverless-plugin-common-excludes": "^4.0.0",
|
|
63
|
+
"serverless": "^4.18.2",
|
|
63
64
|
"tsx": "^4.20.5",
|
|
64
|
-
"typedoc": "^0.28.12",
|
|
65
65
|
"typedoc-plugin-mdn-links": "^5.0.9",
|
|
66
66
|
"typedoc-plugin-replace-text": "^4.2.0",
|
|
67
67
|
"typedoc-plugin-zod": "^1.4.2",
|
|
68
|
-
"
|
|
68
|
+
"typedoc": "^0.28.13",
|
|
69
69
|
"typescript-eslint": "^8.43.0",
|
|
70
|
+
"typescript": "^5.9.2",
|
|
70
71
|
"vite-tsconfig-paths": "^5.1.4",
|
|
71
72
|
"vitest": "^3.2.4",
|
|
72
73
|
"zod-openapi": "^5.4.1"
|
|
73
74
|
},
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=22.19.0 <23"
|
|
77
|
+
},
|
|
74
78
|
"exports": {
|
|
75
79
|
".": {
|
|
76
80
|
"import": {
|
|
@@ -181,5 +185,8 @@
|
|
|
181
185
|
"templates:lint": "eslint --fix -c templates/default/eslint.config.ts \"templates/default/**/*.{ts,tsx,js,jsx}\" \"templates/default/eslint.config.ts\""
|
|
182
186
|
},
|
|
183
187
|
"type": "module",
|
|
184
|
-
"version": "0.2.
|
|
188
|
+
"version": "0.2.10",
|
|
189
|
+
"volta": {
|
|
190
|
+
"node": "22.19.0"
|
|
191
|
+
}
|
|
185
192
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22.19.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22.19.0
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
|
|
4
|
-
import { App,
|
|
4
|
+
import { App, toPosixPath } from '@karmaniverous/smoz';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
7
7
|
// Derive the app root as the parent directory of app/config/
|
|
@@ -23,7 +23,6 @@ export const app = App.create({
|
|
|
23
23
|
DOMAIN_NAME: z.string(),
|
|
24
24
|
STAGE: z.string(),
|
|
25
25
|
}),
|
|
26
|
-
eventTypeMapSchema: baseEventTypeMapSchema,
|
|
27
26
|
serverless: {
|
|
28
27
|
httpContextEventMap: {
|
|
29
28
|
my: {}, // place a Cognito authorizer here if needed
|
|
@@ -1,47 +1,52 @@
|
|
|
1
|
-
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"@
|
|
14
|
-
"@types/
|
|
15
|
-
"
|
|
16
|
-
"eslint": "^
|
|
17
|
-
"eslint-
|
|
18
|
-
"eslint
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"serverless": "^
|
|
23
|
-
"serverless-
|
|
24
|
-
"serverless-
|
|
25
|
-
"serverless-
|
|
26
|
-
"serverless
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"typescript": "^5.9.2",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"scripts": {
|
|
36
|
-
"register": "smoz register",
|
|
37
|
-
"openapi": "smoz register && tsx app/config/openapi && prettier -w app/generated/openapi.json",
|
|
38
|
-
"package": "smoz register && serverless package",
|
|
39
|
-
"dev": "smoz dev",
|
|
40
|
-
"dev:offline": "smoz dev --local offline",
|
|
41
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
42
|
-
"lint": "eslint .",
|
|
43
|
-
"lint:fix": "eslint --fix .",
|
|
44
|
-
"test": "vitest run",
|
|
45
|
-
"docs": "typedoc"
|
|
46
|
-
}
|
|
47
|
-
|
|
1
|
+
{
|
|
2
|
+
"engines": {
|
|
3
|
+
"node": ">=22.19.0 <23"
|
|
4
|
+
},
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@middy/core": "^6.4.5",
|
|
7
|
+
"fs-extra": "^11.3.1",
|
|
8
|
+
"package-directory": "^8.1.0",
|
|
9
|
+
"zod": "^4.1.6"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@serverless/typescript": "^4.18.2",
|
|
13
|
+
"@types/fs-extra": "^11.0.4",
|
|
14
|
+
"@types/node": "^22",
|
|
15
|
+
"eslint-config-prettier": "^10.1.8",
|
|
16
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
17
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
18
|
+
"eslint": "^9.35.0",
|
|
19
|
+
"jiti": "^2.5.1",
|
|
20
|
+
"prettier": "^3.6.2",
|
|
21
|
+
"serverless-apigateway-log-retention": "^1.1.0",
|
|
22
|
+
"serverless-deployment-bucket": "^1.6.0",
|
|
23
|
+
"serverless-domain-manager": "^8.0.0",
|
|
24
|
+
"serverless-offline": "^14.4.0",
|
|
25
|
+
"serverless-plugin-common-excludes": "^4.0.0",
|
|
26
|
+
"serverless": "^4.18.2",
|
|
27
|
+
"tsx": "^4.20.5",
|
|
28
|
+
"typedoc": "^0.28.12",
|
|
29
|
+
"typescript-eslint": "^8.43.0",
|
|
30
|
+
"typescript": "^5.9.2",
|
|
31
|
+
"vitest": "^3.2.4",
|
|
32
|
+
"zod-openapi": "^5.4.1"
|
|
33
|
+
},
|
|
34
|
+
"name": "smoz-template-default",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"register": "smoz register",
|
|
37
|
+
"openapi": "smoz register && tsx app/config/openapi && prettier -w app/generated/openapi.json",
|
|
38
|
+
"package": "smoz register && serverless package",
|
|
39
|
+
"dev": "smoz dev",
|
|
40
|
+
"dev:offline": "smoz dev --local offline",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
42
|
+
"lint": "eslint .",
|
|
43
|
+
"lint:fix": "eslint --fix .",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"docs": "typedoc"
|
|
46
|
+
},
|
|
47
|
+
"type": "module",
|
|
48
|
+
"version": "0.0.0",
|
|
49
|
+
"volta": {
|
|
50
|
+
"node": "22.19.0"
|
|
51
|
+
}
|
|
52
|
+
}
|