@fnd-platform/api 1.0.0-alpha.1
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/LICENSE +21 -0
- package/README.md +204 -0
- package/lib/api-project.d.ts +99 -0
- package/lib/api-project.d.ts.map +1 -0
- package/lib/api-project.js +668 -0
- package/lib/api-project.js.map +1 -0
- package/lib/handlers/content.d.ts +52 -0
- package/lib/handlers/content.d.ts.map +1 -0
- package/lib/handlers/content.js +122 -0
- package/lib/handlers/content.js.map +1 -0
- package/lib/handlers/health.d.ts +43 -0
- package/lib/handlers/health.d.ts.map +1 -0
- package/lib/handlers/health.js +43 -0
- package/lib/handlers/health.js.map +1 -0
- package/lib/handlers/media.d.ts +86 -0
- package/lib/handlers/media.d.ts.map +1 -0
- package/lib/handlers/media.js +287 -0
- package/lib/handlers/media.js.map +1 -0
- package/lib/index.d.ts +22 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +50 -0
- package/lib/index.js.map +1 -0
- package/lib/lib/errors.d.ts +114 -0
- package/lib/lib/errors.d.ts.map +1 -0
- package/lib/lib/errors.js +154 -0
- package/lib/lib/errors.js.map +1 -0
- package/lib/lib/middleware.d.ts +33 -0
- package/lib/lib/middleware.d.ts.map +1 -0
- package/lib/lib/middleware.js +36 -0
- package/lib/lib/middleware.js.map +1 -0
- package/lib/lib/request.d.ts +90 -0
- package/lib/lib/request.d.ts.map +1 -0
- package/lib/lib/request.js +115 -0
- package/lib/lib/request.js.map +1 -0
- package/lib/lib/response.d.ts +131 -0
- package/lib/lib/response.d.ts.map +1 -0
- package/lib/lib/response.js +163 -0
- package/lib/lib/response.js.map +1 -0
- package/lib/middleware/auth.d.ts +57 -0
- package/lib/middleware/auth.d.ts.map +1 -0
- package/lib/middleware/auth.js +62 -0
- package/lib/middleware/auth.js.map +1 -0
- package/lib/middleware/cors.d.ts +51 -0
- package/lib/middleware/cors.d.ts.map +1 -0
- package/lib/middleware/cors.js +62 -0
- package/lib/middleware/cors.js.map +1 -0
- package/lib/middleware/error-handler.d.ts +38 -0
- package/lib/middleware/error-handler.d.ts.map +1 -0
- package/lib/middleware/error-handler.js +49 -0
- package/lib/middleware/error-handler.js.map +1 -0
- package/lib/middleware/index.d.ts +15 -0
- package/lib/middleware/index.d.ts.map +1 -0
- package/lib/middleware/index.js +49 -0
- package/lib/middleware/index.js.map +1 -0
- package/lib/middleware/logging.d.ts +48 -0
- package/lib/middleware/logging.d.ts.map +1 -0
- package/lib/middleware/logging.js +58 -0
- package/lib/middleware/logging.js.map +1 -0
- package/lib/middleware/validation.d.ts +41 -0
- package/lib/middleware/validation.d.ts.map +1 -0
- package/lib/middleware/validation.js +76 -0
- package/lib/middleware/validation.js.map +1 -0
- package/lib/options.d.ts +48 -0
- package/lib/options.d.ts.map +1 -0
- package/lib/options.js +3 -0
- package/lib/options.js.map +1 -0
- package/lib/types/api.d.ts +108 -0
- package/lib/types/api.d.ts.map +1 -0
- package/lib/types/api.js +11 -0
- package/lib/types/api.js.map +1 -0
- package/lib/types/middleware.d.ts +59 -0
- package/lib/types/middleware.d.ts.map +1 -0
- package/lib/types/middleware.js +11 -0
- package/lib/types/middleware.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware exports for @fnd-platform/api.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
8
|
+
exports.withLogging =
|
|
9
|
+
exports.withCors =
|
|
10
|
+
exports.withValidation =
|
|
11
|
+
exports.withAuth =
|
|
12
|
+
exports.withErrorHandler =
|
|
13
|
+
void 0;
|
|
14
|
+
var error_handler_1 = require('./error-handler');
|
|
15
|
+
Object.defineProperty(exports, 'withErrorHandler', {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () {
|
|
18
|
+
return error_handler_1.withErrorHandler;
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
var auth_1 = require('./auth');
|
|
22
|
+
Object.defineProperty(exports, 'withAuth', {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () {
|
|
25
|
+
return auth_1.withAuth;
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
var validation_1 = require('./validation');
|
|
29
|
+
Object.defineProperty(exports, 'withValidation', {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
get: function () {
|
|
32
|
+
return validation_1.withValidation;
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
var cors_1 = require('./cors');
|
|
36
|
+
Object.defineProperty(exports, 'withCors', {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return cors_1.withCors;
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
var logging_1 = require('./logging');
|
|
43
|
+
Object.defineProperty(exports, 'withLogging', {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return logging_1.withLogging;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,iDAAmD;AAA1C,iHAAA,gBAAgB,OAAA;AAGzB,+BAAkC;AAAzB,gGAAA,QAAQ,OAAA;AAGjB,2CAA8C;AAArC,4GAAA,cAAc,OAAA;AAEvB,+BAAkC;AAAzB,gGAAA,QAAQ,OAAA;AAGjB,qCAAwC;AAA/B,sGAAA,WAAW,OAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging middleware for Lambda handlers.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import type { Middleware } from '../types/middleware';
|
|
7
|
+
/**
|
|
8
|
+
* Logging configuration options.
|
|
9
|
+
*/
|
|
10
|
+
export interface LoggingOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Whether to log request metadata.
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
logRequest?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to log response metadata.
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
logResponse?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Paths to redact from logs (reserved for future use).
|
|
23
|
+
* @default []
|
|
24
|
+
*/
|
|
25
|
+
redactPaths?: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Middleware that logs request and response metadata.
|
|
29
|
+
*
|
|
30
|
+
* Logs are written to console in JSON format for CloudWatch integration.
|
|
31
|
+
*
|
|
32
|
+
* @param options - Logging configuration
|
|
33
|
+
* @returns Middleware that logs request/response data
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const handler = compose(
|
|
38
|
+
* withLogging({ logRequest: true, logResponse: true }),
|
|
39
|
+
* withErrorHandler()
|
|
40
|
+
* )(async (event) => {
|
|
41
|
+
* return success({ data: 'value' });
|
|
42
|
+
* });
|
|
43
|
+
* // Logs: {"type":"REQUEST","requestId":"...","method":"GET","path":"/users"}
|
|
44
|
+
* // Logs: {"type":"RESPONSE","requestId":"...","statusCode":200,"duration":45}
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function withLogging(options?: LoggingOptions): Middleware;
|
|
48
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/middleware/logging.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,UAAU,CAiCpE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Logging middleware for Lambda handlers.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
8
|
+
exports.withLogging = withLogging;
|
|
9
|
+
/**
|
|
10
|
+
* Middleware that logs request and response metadata.
|
|
11
|
+
*
|
|
12
|
+
* Logs are written to console in JSON format for CloudWatch integration.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Logging configuration
|
|
15
|
+
* @returns Middleware that logs request/response data
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const handler = compose(
|
|
20
|
+
* withLogging({ logRequest: true, logResponse: true }),
|
|
21
|
+
* withErrorHandler()
|
|
22
|
+
* )(async (event) => {
|
|
23
|
+
* return success({ data: 'value' });
|
|
24
|
+
* });
|
|
25
|
+
* // Logs: {"type":"REQUEST","requestId":"...","method":"GET","path":"/users"}
|
|
26
|
+
* // Logs: {"type":"RESPONSE","requestId":"...","statusCode":200,"duration":45}
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
function withLogging(options = {}) {
|
|
30
|
+
const { logRequest = true, logResponse = true } = options;
|
|
31
|
+
return (handler) => async (event, context) => {
|
|
32
|
+
const startTime = Date.now();
|
|
33
|
+
const requestId = context.awsRequestId;
|
|
34
|
+
if (logRequest) {
|
|
35
|
+
console.log(
|
|
36
|
+
JSON.stringify({
|
|
37
|
+
type: 'REQUEST',
|
|
38
|
+
requestId,
|
|
39
|
+
method: event.httpMethod,
|
|
40
|
+
path: event.path,
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
const response = await handler(event, context);
|
|
45
|
+
if (logResponse) {
|
|
46
|
+
console.log(
|
|
47
|
+
JSON.stringify({
|
|
48
|
+
type: 'RESPONSE',
|
|
49
|
+
requestId,
|
|
50
|
+
statusCode: response.statusCode,
|
|
51
|
+
duration: Date.now() - startTime,
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return response;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../../src/middleware/logging.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AA+CH,kCAiCC;AArDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,WAAW,CAAC,UAA0B,EAAE;IACtD,MAAM,EAAE,UAAU,GAAG,IAAI,EAAE,WAAW,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAE1D,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;QAEvC,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;gBACb,IAAI,EAAE,SAAS;gBACf,SAAS;gBACT,MAAM,EAAE,KAAK,CAAC,UAAU;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC,CACH,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAE/C,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;gBACb,IAAI,EAAE,UAAU;gBAChB,SAAS;gBACT,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;aACjC,CAAC,CACH,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request validation middleware for Lambda handlers.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import type { APIGatewayProxyEvent } from 'aws-lambda';
|
|
7
|
+
import type { ZodSchema } from 'zod';
|
|
8
|
+
import type { Middleware, ValidatedEvent } from '../types/middleware';
|
|
9
|
+
/**
|
|
10
|
+
* Middleware that validates request body against a Zod schema.
|
|
11
|
+
*
|
|
12
|
+
* Parses the JSON body and validates it against the provided schema.
|
|
13
|
+
* On success, adds the validated and typed body to `event.validatedBody`.
|
|
14
|
+
*
|
|
15
|
+
* @typeParam T - The type of the validated body (inferred from schema)
|
|
16
|
+
* @param schema - Zod schema to validate against
|
|
17
|
+
* @returns Middleware that validates the request body
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { z } from 'zod';
|
|
22
|
+
*
|
|
23
|
+
* const CreateUserSchema = z.object({
|
|
24
|
+
* name: z.string().min(1, 'Name is required'),
|
|
25
|
+
* email: z.string().email('Invalid email format'),
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* const handler = compose(
|
|
29
|
+
* withErrorHandler(),
|
|
30
|
+
* withValidation(CreateUserSchema)
|
|
31
|
+
* )(async (event) => {
|
|
32
|
+
* // event.validatedBody is typed as { name: string; email: string }
|
|
33
|
+
* const { name, email } = event.validatedBody;
|
|
34
|
+
* return success({ name, email });
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function withValidation<T>(
|
|
39
|
+
schema: ZodSchema<T>
|
|
40
|
+
): Middleware<APIGatewayProxyEvent, ValidatedEvent<T>>;
|
|
41
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/middleware/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,KAAK,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAkBtE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GACnB,UAAU,CAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CA0BrD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Request validation middleware for Lambda handlers.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
8
|
+
exports.withValidation = withValidation;
|
|
9
|
+
const response_1 = require('../lib/response');
|
|
10
|
+
/**
|
|
11
|
+
* Format Zod validation errors into a human-readable string.
|
|
12
|
+
*
|
|
13
|
+
* @param error - Zod validation error
|
|
14
|
+
* @returns Formatted error message
|
|
15
|
+
*/
|
|
16
|
+
function formatZodError(error) {
|
|
17
|
+
return error.errors
|
|
18
|
+
.map((e) => {
|
|
19
|
+
const path = e.path.length > 0 ? e.path.join('.') : 'body';
|
|
20
|
+
return `${path}: ${e.message}`;
|
|
21
|
+
})
|
|
22
|
+
.join(', ');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Middleware that validates request body against a Zod schema.
|
|
26
|
+
*
|
|
27
|
+
* Parses the JSON body and validates it against the provided schema.
|
|
28
|
+
* On success, adds the validated and typed body to `event.validatedBody`.
|
|
29
|
+
*
|
|
30
|
+
* @typeParam T - The type of the validated body (inferred from schema)
|
|
31
|
+
* @param schema - Zod schema to validate against
|
|
32
|
+
* @returns Middleware that validates the request body
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { z } from 'zod';
|
|
37
|
+
*
|
|
38
|
+
* const CreateUserSchema = z.object({
|
|
39
|
+
* name: z.string().min(1, 'Name is required'),
|
|
40
|
+
* email: z.string().email('Invalid email format'),
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* const handler = compose(
|
|
44
|
+
* withErrorHandler(),
|
|
45
|
+
* withValidation(CreateUserSchema)
|
|
46
|
+
* )(async (event) => {
|
|
47
|
+
* // event.validatedBody is typed as { name: string; email: string }
|
|
48
|
+
* const { name, email } = event.validatedBody;
|
|
49
|
+
* return success({ name, email });
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function withValidation(schema) {
|
|
54
|
+
return (handler) => async (event, context) => {
|
|
55
|
+
// Parse body
|
|
56
|
+
let body;
|
|
57
|
+
try {
|
|
58
|
+
body = event.body ? JSON.parse(event.body) : {};
|
|
59
|
+
} catch {
|
|
60
|
+
return (0, response_1.badRequest)('Invalid JSON in request body');
|
|
61
|
+
}
|
|
62
|
+
// Validate against schema
|
|
63
|
+
const result = schema.safeParse(body);
|
|
64
|
+
if (!result.success) {
|
|
65
|
+
const details = formatZodError(result.error);
|
|
66
|
+
return (0, response_1.badRequest)(`Validation failed: ${details}`);
|
|
67
|
+
}
|
|
68
|
+
// Add validated body to event
|
|
69
|
+
const validatedEvent = {
|
|
70
|
+
...event,
|
|
71
|
+
validatedBody: result.data,
|
|
72
|
+
};
|
|
73
|
+
return handler(validatedEvent, context);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/middleware/validation.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAmDH,wCA4BC;AA1ED,8CAA6C;AAE7C;;;;;GAKG;AACH,SAAS,cAAc,CAAC,KAAe;IACrC,OAAO,KAAK,CAAC,MAAM;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC3D,OAAO,GAAG,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;IACjC,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,SAAgB,cAAc,CAC5B,MAAoB;IAEpB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC3C,aAAa;QACb,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAA,qBAAU,EAAC,8BAA8B,CAAC,CAAC;QACpD,CAAC;QAED,0BAA0B;QAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAEtC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO,IAAA,qBAAU,EAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;QACrD,CAAC;QAED,8BAA8B;QAC9B,MAAM,cAAc,GAAsB;YACxC,GAAG,KAAK;YACR,aAAa,EAAE,MAAM,CAAC,IAAI;SAC3B,CAAC;QAEF,OAAO,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC,CAAC;AACJ,CAAC"}
|
package/lib/options.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FndMonorepoProject } from '@fnd-platform/core';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for FndApiProject.
|
|
4
|
+
*/
|
|
5
|
+
export interface FndApiProjectOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Parent monorepo project.
|
|
8
|
+
* The API project will be added as a subproject of this monorepo.
|
|
9
|
+
*/
|
|
10
|
+
readonly parent: FndMonorepoProject;
|
|
11
|
+
/**
|
|
12
|
+
* Package name for the API project.
|
|
13
|
+
* This will be prefixed with the parent project name to create the full
|
|
14
|
+
* package name (e.g., '@my-app/api').
|
|
15
|
+
*
|
|
16
|
+
* @example 'api'
|
|
17
|
+
*/
|
|
18
|
+
readonly name: string;
|
|
19
|
+
/**
|
|
20
|
+
* Output directory relative to monorepo root.
|
|
21
|
+
*
|
|
22
|
+
* @default 'packages/{name}'
|
|
23
|
+
*/
|
|
24
|
+
readonly outdir?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Enable DynamoDB integration.
|
|
27
|
+
* When true, adds AWS SDK DynamoDB dependencies and generates
|
|
28
|
+
* DynamoDB utility files.
|
|
29
|
+
*
|
|
30
|
+
* @default true
|
|
31
|
+
*/
|
|
32
|
+
readonly dynamodb?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Enable Cognito authentication integration.
|
|
35
|
+
* When true, includes authentication middleware and types.
|
|
36
|
+
*
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
readonly cognito?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Enable CORS headers in responses.
|
|
42
|
+
* When true, the response helpers will include CORS headers.
|
|
43
|
+
*
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
readonly cors?: boolean;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IAEpC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAE5B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB"}
|
package/lib/options.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type definitions for API handlers.
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe handler definitions and Cognito-authenticated
|
|
5
|
+
* event types for Lambda handlers.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
|
10
|
+
/**
|
|
11
|
+
* Standard Lambda handler type.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const handler: Handler = async (event, context) => {
|
|
16
|
+
* return success({ message: 'Hello' });
|
|
17
|
+
* };
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export type Handler = (
|
|
21
|
+
event: APIGatewayProxyEvent,
|
|
22
|
+
context: Context
|
|
23
|
+
) => Promise<APIGatewayProxyResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Cognito JWT claims structure.
|
|
26
|
+
*/
|
|
27
|
+
export interface CognitoClaims {
|
|
28
|
+
/** User's unique identifier (Cognito sub) */
|
|
29
|
+
sub: string;
|
|
30
|
+
/** User's email address */
|
|
31
|
+
email: string;
|
|
32
|
+
/** User's Cognito groups (roles) */
|
|
33
|
+
'cognito:groups'?: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* API Gateway event with Cognito authorizer claims.
|
|
37
|
+
*
|
|
38
|
+
* Use this type when your handler expects authenticated requests
|
|
39
|
+
* from API Gateway with a Cognito authorizer.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const handler: AuthenticatedHandler = async (event) => {
|
|
44
|
+
* const userId = event.requestContext.authorizer.claims.sub;
|
|
45
|
+
* const email = event.requestContext.authorizer.claims.email;
|
|
46
|
+
* // ...
|
|
47
|
+
* };
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export interface AuthenticatedEvent extends APIGatewayProxyEvent {
|
|
51
|
+
requestContext: APIGatewayProxyEvent['requestContext'] & {
|
|
52
|
+
authorizer: {
|
|
53
|
+
claims: CognitoClaims;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Lambda handler type for authenticated requests.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const getProfile: AuthenticatedHandler = async (event, context) => {
|
|
63
|
+
* const userId = event.requestContext.authorizer.claims.sub;
|
|
64
|
+
* return success({ userId });
|
|
65
|
+
* };
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export type AuthenticatedHandler = (
|
|
69
|
+
event: AuthenticatedEvent,
|
|
70
|
+
context: Context
|
|
71
|
+
) => Promise<APIGatewayProxyResult>;
|
|
72
|
+
/**
|
|
73
|
+
* Pagination parameters for list endpoints.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* interface ListUsersRequest extends PaginatedRequest {
|
|
78
|
+
* status?: 'active' | 'inactive';
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export interface PaginatedRequest {
|
|
83
|
+
/** Maximum number of items to return (default varies by endpoint) */
|
|
84
|
+
limit?: number;
|
|
85
|
+
/** Cursor for pagination (typically the last item's ID or encoded key) */
|
|
86
|
+
cursor?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Paginated response structure for list endpoints.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const response: PaginatedResponse<User> = {
|
|
94
|
+
* items: users,
|
|
95
|
+
* nextCursor: lastUser?.id,
|
|
96
|
+
* total: totalCount,
|
|
97
|
+
* };
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export interface PaginatedResponse<T> {
|
|
101
|
+
/** Array of items for the current page */
|
|
102
|
+
items: T[];
|
|
103
|
+
/** Cursor for the next page, undefined if no more pages */
|
|
104
|
+
nextCursor?: string;
|
|
105
|
+
/** Total count of items (optional, may be expensive to compute) */
|
|
106
|
+
total?: number;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEvF;;;;;;;;;GASG;AACH,MAAM,MAAM,OAAO,GAAG,CACpB,KAAK,EAAE,oBAAoB,EAC3B,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,cAAc,EAAE,oBAAoB,CAAC,gBAAgB,CAAC,GAAG;QACvD,UAAU,EAAE;YACV,MAAM,EAAE,aAAa,CAAC;SACvB,CAAC;KACH,CAAC;CACH;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEpC;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,0CAA0C;IAC1C,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
package/lib/types/api.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TypeScript type definitions for API handlers.
|
|
4
|
+
*
|
|
5
|
+
* Provides type-safe handler definitions and Cognito-authenticated
|
|
6
|
+
* event types for Lambda handlers.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware type definitions for Lambda handlers.
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe middleware composition for cross-cutting concerns
|
|
5
|
+
* like authentication, validation, error handling, and logging.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
|
10
|
+
/**
|
|
11
|
+
* Generic Lambda handler type.
|
|
12
|
+
*
|
|
13
|
+
* Allows handlers to receive transformed events (e.g., with validatedBody).
|
|
14
|
+
*
|
|
15
|
+
* @typeParam TEvent - The event type this handler receives
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const handler: MiddlewareHandler<ValidatedEvent<UserInput>> = async (event, context) => {
|
|
20
|
+
* const { name, email } = event.validatedBody;
|
|
21
|
+
* return success({ name, email });
|
|
22
|
+
* };
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export type MiddlewareHandler<TEvent = APIGatewayProxyEvent> = (
|
|
26
|
+
event: TEvent,
|
|
27
|
+
context: Context
|
|
28
|
+
) => Promise<APIGatewayProxyResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Middleware function type.
|
|
31
|
+
*
|
|
32
|
+
* Middleware wraps a handler, optionally transforming the event type.
|
|
33
|
+
* The transformation flows from TEventIn to TEventOut.
|
|
34
|
+
*
|
|
35
|
+
* @typeParam TEventIn - The event type this middleware receives
|
|
36
|
+
* @typeParam TEventOut - The event type passed to the inner handler
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Middleware that adds validatedBody to the event
|
|
41
|
+
* const withValidation: Middleware<APIGatewayProxyEvent, ValidatedEvent<T>> = ...
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export type Middleware<TEventIn = APIGatewayProxyEvent, TEventOut = TEventIn> = (
|
|
45
|
+
handler: MiddlewareHandler<TEventOut>
|
|
46
|
+
) => MiddlewareHandler<TEventIn>;
|
|
47
|
+
/**
|
|
48
|
+
* Event with validated request body.
|
|
49
|
+
*
|
|
50
|
+
* Used by withValidation middleware to provide type-safe access
|
|
51
|
+
* to the validated request body.
|
|
52
|
+
*
|
|
53
|
+
* @typeParam T - The validated body type (from Zod schema)
|
|
54
|
+
*/
|
|
55
|
+
export interface ValidatedEvent<T> extends APIGatewayProxyEvent {
|
|
56
|
+
/** The validated and typed request body */
|
|
57
|
+
validatedBody: T;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/types/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEvF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,iBAAiB,CAAC,MAAM,GAAG,oBAAoB,IAAI,CAC7D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEpC;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,UAAU,CAAC,QAAQ,GAAG,oBAAoB,EAAE,SAAS,GAAG,QAAQ,IAAI,CAC9E,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,KAClC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,oBAAoB;IAC7D,2CAA2C;IAC3C,aAAa,EAAE,CAAC,CAAC;CAClB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Middleware type definitions for Lambda handlers.
|
|
4
|
+
*
|
|
5
|
+
* Provides type-safe middleware composition for cross-cutting concerns
|
|
6
|
+
* like authentication, validation, error handling, and logging.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/types/middleware.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fnd-platform/api",
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
|
+
"description": "Projen project class for generating Lambda API packages in fnd-platform",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib/"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@aws-sdk/client-s3": "^3.500.0",
|
|
12
|
+
"@aws-sdk/s3-request-presigner": "^3.500.0",
|
|
13
|
+
"projen": "^0.91.0",
|
|
14
|
+
"zod": "^3.22.0",
|
|
15
|
+
"@fnd-platform/core": "1.0.0-alpha.1"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"projen": "^0.91.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/aws-lambda": "^8.10.159",
|
|
22
|
+
"@types/node": "^20.0.0",
|
|
23
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
24
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
25
|
+
"@vitest/coverage-v8": "^1.6.0",
|
|
26
|
+
"eslint": "^8.57.0",
|
|
27
|
+
"typescript": "^5.6.3",
|
|
28
|
+
"vitest": "^1.6.0"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"projen",
|
|
32
|
+
"lambda",
|
|
33
|
+
"api",
|
|
34
|
+
"aws",
|
|
35
|
+
"typescript",
|
|
36
|
+
"scaffolding"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/your-org/fnd-platform",
|
|
45
|
+
"directory": "packages/api"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"test:coverage": "vitest run --coverage",
|
|
52
|
+
"lint": "eslint src/ test/"
|
|
53
|
+
}
|
|
54
|
+
}
|