Skip to content

Commit

Permalink
feat: type Module providers, optimize gen paths
Browse files Browse the repository at this point in the history
  • Loading branch information
spirius committed Nov 9, 2024
1 parent bf5f2ed commit 6f2fdec
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 39 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@cloudventure/sdf",
"description": "Serverless Development Framework",
"version": "0.2.11",
"version": "0.2.12",
"author": "Vahe Sahakyan <[email protected]>",
"license": "MIT",
"packageManager": "[email protected]",
Expand Down
8 changes: 5 additions & 3 deletions src/bundler/Bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export interface BundlerContainerImageConfig {

export type BundlerConfig<
Variables extends TerraformHclModuleConfig["variables"] = TerraformHclModuleConfig["variables"],
Providers extends Record<string, TerraformProvider> = Record<string, TerraformProvider>,
> = ((BundlerConfigTypeScript | BundlerConfigCustom) &
(BundlerConfigDirect | BundlerConfigS3 | BundlerConfigContainer | BundlerConfigNone)) & {
/** the language of the bundler */
Expand All @@ -111,7 +112,7 @@ export type BundlerConfig<

/** external variables */
variables?: Variables
providers?: Array<TerraformProvider>
providers?: Providers
}

export type BundleManifest = Omit<BundlerConfig, "variables" | "providers"> & {
Expand All @@ -121,7 +122,8 @@ export type BundleManifest = Omit<BundlerConfig, "variables" | "providers"> & {

export class Bundler<
Variables extends TerraformHclModuleConfig["variables"] = TerraformHclModuleConfig["variables"],
> extends Module<Variables> {
Providers extends Record<string, TerraformProvider> = Record<string, TerraformProvider>,
> extends Module<Variables, Providers> {
private app: App
private stack: TerraformStack

Expand All @@ -133,7 +135,7 @@ export class Bundler<

private config: BundlerConfig<Variables>

constructor(scope: Construct, id: string, { variables, providers, ...config }: BundlerConfig<Variables>) {
constructor(scope: Construct, id: string, { variables, providers, ...config }: BundlerConfig<Variables, Providers>) {
super(scope, id, { variables, providers }, (self: Construct) => {
self.node.setContext(Bundler.name, self)
self.node.setContext(self.constructor.name, self)
Expand Down
4 changes: 2 additions & 2 deletions src/bundler/language/BundlerLanguageTypeScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class BundlerLanguageTypeScript extends Construct implements BundlerLangu

/** The path of the HTTP API directory */
private httpApiDir(httpApi: HttpApi): string {
return join(this.genDir, httpApi.prefix)
return join(this.genDir, httpApi.id)
}

/** The path of the OpenAPI document */
Expand Down Expand Up @@ -121,7 +121,7 @@ export class BundlerLanguageTypeScript extends Construct implements BundlerLangu

/** The path of the entry points directory */
private httpApiEntryPointsDir(httpApi: HttpApi): string {
return join(this.genDir, ".entrypoints", httpApi.prefix)
return join(this.genDir, ".entrypoints", httpApi.id)
}

private httpApiEntryPointPath(httpApi: HttpApi, operationId: string): string {
Expand Down
31 changes: 23 additions & 8 deletions src/core/Module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,28 @@ import { Construct } from "constructs"

import { App } from "./App"

export interface ModuleConfig<Variables extends TerraformHclModuleConfig["variables"]> {
export interface ModuleConfig<
Variables extends TerraformHclModuleConfig["variables"],
Providers extends Record<string, TerraformProvider>,
> {
variables?: Variables
providers?: Array<TerraformProvider>
providers?: Providers
}

export class Module<
Variables extends TerraformHclModuleConfig["variables"] = TerraformHclModuleConfig["variables"],
Providers extends Record<string, TerraformProvider> = Record<string, TerraformProvider>,
SetContext extends (scope: Construct) => void = (scope: Construct) => void,
> extends TerraformStack {
public readonly variables: { [key in keyof Variables]: Variables[key] } = {} as any
public readonly providers: { [key in keyof Providers]: Providers[key] } = {} as any

public readonly module: TerraformHclModule

constructor(
scope: Construct,
public readonly id: string,
{ variables = {}, providers = [] }: ModuleConfig<Variables>,
{ variables = {}, providers = {} as Providers }: ModuleConfig<Variables, Providers>,
setContext?: SetContext,
) {
super(App.getAppFromContext(scope), id)
Expand All @@ -42,19 +47,29 @@ export class Module<
source: `../${id}`,
skipAssetCreationFromLocalModules: true,
variables,
providers,
providers: Object.entries(providers).map(([, provider]) =>
provider.alias
? {
moduleAlias: provider.alias,
provider,
}
: provider,
),
})

this.variables = Object.entries(variables || {}).reduce(
(acc, [key]) => ({ [key]: new TerraformVariable(this, key, {}).value, ...acc }),
this.variables,
)

providers.forEach(provider => {
this.providers = Object.entries(providers).reduce((acc, [key, provider]) => {
const ProviderClass: { new (...args: any[]): typeof provider } = provider.constructor as any
const key = provider.node.id
new ProviderClass(this, key)
})
const id = provider.node.id
return {
...acc,
[key]: new ProviderClass(this, id, { alias: provider.alias }),
}
}, this.providers)
}

output(name: string): IResolvable {
Expand Down
2 changes: 1 addition & 1 deletion src/http-api/core/DocumentSchemaAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export class DocumentSchemaAdapter {
const schema = {
type: "object",
additionalProperties: {
oneOf: [{ type: "string" }, { type: "number" }, { type: "boolean" }],
anyOf: [{ type: "string" }, { type: "number" }, { type: "boolean" }],
},
properties: {},
required: [] as Array<string>,
Expand Down
12 changes: 6 additions & 6 deletions src/http-api/core/HttpApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe(HttpApi.name, () => {
bundle: "direct",
path: rootDir,
prefix: "src",
providers: [aws, archive],
providers: { aws, archive },
variables: {
inputvar: local.expression,
},
Expand Down Expand Up @@ -241,7 +241,7 @@ describe(HttpApi.name, () => {
bundle: "direct",
path: rootDir,
prefix: join("src", bundlerName),
providers: [aws, archive],
providers: { aws, archive },
})

new HttpApi(bundler, "api", {
Expand Down Expand Up @@ -320,7 +320,7 @@ describe(HttpApi.name, () => {
bundle: "direct",
path: rootDir,
prefix: join("src", bundlerName),
providers: [aws, archive],
providers: { aws, archive },
})

const authorizer = new HttpApiLambdaAuthorizer(bundler, "my-auth", {
Expand Down Expand Up @@ -368,7 +368,7 @@ describe(HttpApi.name, () => {
bundle: "direct",
path: rootDir,
prefix: join("src", bundlerName),
providers: [aws, archive],
providers: { aws, archive },
})

expect(
Expand Down Expand Up @@ -403,7 +403,7 @@ describe(HttpApi.name, () => {
bundle: "direct",
path: rootDir,
prefix: join("src", bundlerName),
providers: [aws, archive],
providers: { aws, archive },
})

expect(
Expand Down Expand Up @@ -438,7 +438,7 @@ describe(HttpApi.name, () => {
bundle: "direct",
path: rootDir,
prefix: join("src", bundlerName),
providers: [aws, archive],
providers: { aws, archive },
})

expect(
Expand Down
2 changes: 1 addition & 1 deletion src/http-api/core/HttpApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class HttpApi extends Construct {

constructor(
scope: Construct,
private id: string,
public readonly id: string,
public readonly config: HttpApiConfig,
) {
super(scope, id)
Expand Down
2 changes: 1 addition & 1 deletion src/http-api/runtime/client/HttpApiClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe(HttpApiClient.name, () => {
bundle: "none",
path: rootDir,
prefix: "src",
providers: [aws, archive],
providers: { aws, archive },
})

new HttpApi(bundler, "api", {
Expand Down
1 change: 1 addition & 0 deletions src/http-api/runtime/errors/HttpError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export abstract class HttpError extends Error {
public code: string,
public message: string,
public details?: unknown,
public internal?: unknown,
) {
super(`[${code}]: ${message}`)
}
Expand Down
2 changes: 1 addition & 1 deletion src/http-api/runtime/server/HttpApiServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe("HttpApiServer", () => {
bundle: "direct",
path: rootDir,
prefix: "src",
providers: [aws, archive],
providers: { aws, archive },
})

new HttpApi(bundler, "api", {
Expand Down
32 changes: 18 additions & 14 deletions src/http-api/runtime/server/HttpApiServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { APIGatewayProxyEventV2WithRequestContext, APIGatewayProxyStructuredResu
import { HttpHeaders } from "../../common/HttpHeaders"
import { Operation } from "../../openapi/Operation"
import { AwsHttpEventCodec } from "../codec/AwsHttpEventCodec"
import { Codec, CodecInput, CodecOutput } from "../codec/Codec"
import { Codec, CodecInput } from "../codec/Codec"
import { HeaderEncoder } from "../codec/HeaderEncoder"
import { MediaContainer, MediaContainerCodecs } from "../codec/MediaContainerCodec"
import { ApiResponse, DefaultMediaType } from "../common/ApiResponse"
Expand Down Expand Up @@ -47,7 +47,7 @@ export type ConstructServerRequest<Request extends GeneratedRequestShape> = {
mediaType: infer MediaType extends string
body: infer Body
}
? { mediaType: MediaType; body: PreserveBodyType<Body, CodecOutputType<MediaType>> }
? { mediaType: MediaType; body: PreserveBodyType<Body, CodecInputType<MediaType>> }
: Record<string, never>)

type ConditionalExtend<T, U> = T extends U ? T : unknown
Expand All @@ -60,10 +60,6 @@ export type ConstructResponseBody<

type MediaCodecs = typeof MediaContainerCodecs

export type CodecOutputType<K extends string> = CodecOutput<
MediaCodecs[K extends keyof MediaCodecs ? K : DefaultMediaType]
>

export type CodecInputType<K extends string> = CodecInput<
MediaCodecs[K extends keyof MediaCodecs ? K : DefaultMediaType]
>
Expand Down Expand Up @@ -171,7 +167,9 @@ export class HttpApiServer<OpType extends HttpApiServerOperation> {
return request
}

private async invokeHandler(event: APIGatewayProxyEventV2WithRequestContext<unknown>): Promise<ApiResponse> {
private async invokeHandler(
event: APIGatewayProxyEventV2WithRequestContext<unknown>,
): Promise<{ response: ApiResponse; error?: unknown }> {
try {
let request = await this.createRequest(event)

Expand All @@ -185,15 +183,21 @@ export class HttpApiServer<OpType extends HttpApiServerOperation> {
throw new InternalServerError("INTERNAL_SERVER_ERROR", "handler must return an ApiResponse")
}

return response
return { response }
} catch (error) {
if (error instanceof ApiResponse) {
return error
return { response: error }
} else if (error instanceof HttpError) {
return ApiResponse.fromError(error)
return {
response: ApiResponse.fromError(error),
error,
}
} else {
console.error(error)
return ApiResponse.fromError(new InternalServerError("INTERNAL_SERVER_ERROR", "internal server error"))
return {
response: ApiResponse.fromError(new InternalServerError("INTERNAL_SERVER_ERROR", "internal server error")),
error,
}
}
}
}
Expand All @@ -202,13 +206,13 @@ export class HttpApiServer<OpType extends HttpApiServerOperation> {
return async (
event: APIGatewayProxyEventV2WithRequestContext<unknown>,
): Promise<APIGatewayProxyStructuredResultV2> => {
let response = await this.invokeHandler(event)
const result = await this.invokeHandler(event)

if (this.middleware?.response) {
response = await this.middleware.response(response, this.operation)
result.response = await this.middleware.response(result.response, this.operation, result.error)
}

return this.codec.encode(response)
return this.codec.encode(result.response)
}
}
}
2 changes: 1 addition & 1 deletion src/http-api/runtime/server/Middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { HttpApiServerRequestShape } from "./HttpApiServer"

export interface Middleware {
request?: (request: HttpApiServerRequestShape, operation: Operation) => Promise<HttpApiServerRequestShape>
response?: (response: ApiResponse, operation: Operation) => Promise<ApiResponse>
response?: (response: ApiResponse, operation: Operation, error?: unknown) => Promise<ApiResponse>
}

0 comments on commit 6f2fdec

Please sign in to comment.