From 9cf2273788d64ba03820c5932eaba83c293c80e0 Mon Sep 17 00:00:00 2001 From: Thada Wangthammang Date: Wed, 17 Apr 2024 23:23:59 +0700 Subject: [PATCH 1/6] feat(examples): add azure-functions inversify class examples --- .../azure-functions-with-context/README.md | 1 + .../azure-functions-with-context/host.json | 15 +++++++++++ .../local.settings.json | 9 +++++++ .../azure-functions-with-context/package.json | 27 +++++++++++++++++++ .../src/container.ts | 6 +++++ .../src/functions/hello.ts | 0 .../azure-functions-with-context/src/main.ts | 10 +++++++ .../src/nammatham.ts | 7 +++++ .../src/services/data.service.ts | 9 +++++++ .../tsconfig.json | 13 +++++++++ .../src/controllers/home.controller.ts | 18 +++++++++++++ .../src/main.ts | 9 ++++--- 12 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 examples/azure-functions-with-context/README.md create mode 100644 examples/azure-functions-with-context/host.json create mode 100644 examples/azure-functions-with-context/local.settings.json create mode 100644 examples/azure-functions-with-context/package.json create mode 100644 examples/azure-functions-with-context/src/container.ts rename examples/{azure-functions-with-inversify => azure-functions-with-context}/src/functions/hello.ts (100%) create mode 100644 examples/azure-functions-with-context/src/main.ts create mode 100644 examples/azure-functions-with-context/src/nammatham.ts create mode 100644 examples/azure-functions-with-context/src/services/data.service.ts create mode 100644 examples/azure-functions-with-context/tsconfig.json create mode 100644 examples/azure-functions-with-inversify/src/controllers/home.controller.ts diff --git a/examples/azure-functions-with-context/README.md b/examples/azure-functions-with-context/README.md new file mode 100644 index 00000000..0aec29f0 --- /dev/null +++ b/examples/azure-functions-with-context/README.md @@ -0,0 +1 @@ +# @examples/azure-functions diff --git a/examples/azure-functions-with-context/host.json b/examples/azure-functions-with-context/host.json new file mode 100644 index 00000000..852b7b7a --- /dev/null +++ b/examples/azure-functions-with-context/host.json @@ -0,0 +1,15 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + } + } + }, + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[3.15.0, 4.0.0)" + } +} \ No newline at end of file diff --git a/examples/azure-functions-with-context/local.settings.json b/examples/azure-functions-with-context/local.settings.json new file mode 100644 index 00000000..6199cf10 --- /dev/null +++ b/examples/azure-functions-with-context/local.settings.json @@ -0,0 +1,9 @@ +{ + "IsEncrypted": false, + "Values": { + "FUNCTIONS_WORKER_RUNTIME": "node", + "AzureWebJobsFeatureFlags": "EnableWorkerIndexing", + "AzureWebJobsStorage": "UseDevelopmentStorage=true" + }, + "ConnectionStrings": {} +} \ No newline at end of file diff --git a/examples/azure-functions-with-context/package.json b/examples/azure-functions-with-context/package.json new file mode 100644 index 00000000..e5039cdf --- /dev/null +++ b/examples/azure-functions-with-context/package.json @@ -0,0 +1,27 @@ +{ + "name": "@examples/azure-functions-with-inversify", + "version": "1.0.0", + "description": "", + "main": "dist/src/main.js", + "scripts": { + "build": "tsc", + "lint": "tsc --noEmit", + "start": "tsc && func start", + "dev": "cross-env NODE_ENV=development tsx watch src/main.ts" + }, + "author": "Thada Wangthammang", + "license": "MIT", + "dependencies": { + "@azure/functions": "^4.1.0", + "@di-extra/inversify": "^0.2.0", + "nammatham": "2.0.0-alpha.13", + "inversify": "^6.0.2", + "reflect-metadata": "^0.2.1" + }, + "devDependencies": { + "cross-env": "^7.0.3", + "npm-run-all": "^4.1.5", + "tsx": "^4.7.0", + "typescript": "^5.0.2" + } +} \ No newline at end of file diff --git a/examples/azure-functions-with-context/src/container.ts b/examples/azure-functions-with-context/src/container.ts new file mode 100644 index 00000000..5ac6234e --- /dev/null +++ b/examples/azure-functions-with-context/src/container.ts @@ -0,0 +1,6 @@ +import { Container } from 'inversify'; +import { DataService } from './services/data.service'; + +export const container = new Container(); +container.bind(DataService).toSelf(); + diff --git a/examples/azure-functions-with-inversify/src/functions/hello.ts b/examples/azure-functions-with-context/src/functions/hello.ts similarity index 100% rename from examples/azure-functions-with-inversify/src/functions/hello.ts rename to examples/azure-functions-with-context/src/functions/hello.ts diff --git a/examples/azure-functions-with-context/src/main.ts b/examples/azure-functions-with-context/src/main.ts new file mode 100644 index 00000000..a116f49b --- /dev/null +++ b/examples/azure-functions-with-context/src/main.ts @@ -0,0 +1,10 @@ +import 'reflect-metadata'; +import { expressPlugin } from 'nammatham'; +import hello from './functions/hello'; +import { app } from './nammatham'; + +app.addFunctions(hello); + +const dev =process.env.NODE_ENV === 'development'; +app.register(expressPlugin({ dev })); +app.start(); diff --git a/examples/azure-functions-with-context/src/nammatham.ts b/examples/azure-functions-with-context/src/nammatham.ts new file mode 100644 index 00000000..f321be24 --- /dev/null +++ b/examples/azure-functions-with-context/src/nammatham.ts @@ -0,0 +1,7 @@ +import { initNammatham } from 'nammatham'; + +const n = initNammatham.create(); +n.func; +// ^? +export const func = n.func; +export const app = n.app; diff --git a/examples/azure-functions-with-context/src/services/data.service.ts b/examples/azure-functions-with-context/src/services/data.service.ts new file mode 100644 index 00000000..ed289e29 --- /dev/null +++ b/examples/azure-functions-with-context/src/services/data.service.ts @@ -0,0 +1,9 @@ +import { injectable } from 'inversify'; + +@injectable() +export class DataService { + + public getData() { + return `Data from DataService`; + } +} \ No newline at end of file diff --git a/examples/azure-functions-with-context/tsconfig.json b/examples/azure-functions-with-context/tsconfig.json new file mode 100644 index 00000000..f970fa21 --- /dev/null +++ b/examples/azure-functions-with-context/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "dist", + "rootDir": ".", + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "experimentalDecorators": true, + }, + "exclude": ["node_modules", "**/*.test.ts"] +} \ No newline at end of file diff --git a/examples/azure-functions-with-inversify/src/controllers/home.controller.ts b/examples/azure-functions-with-inversify/src/controllers/home.controller.ts new file mode 100644 index 00000000..ddd6371c --- /dev/null +++ b/examples/azure-functions-with-inversify/src/controllers/home.controller.ts @@ -0,0 +1,18 @@ +import { func } from '../nammatham'; +import { DataService } from '../services/data.service'; + +export class HomeController { + constructor(public dataService: DataService) {} + + hello = func + .httpGet('hello', { + route: 'hello-world', + }) + .handler(async c => { + c.context.log('HTTP trigger function processed a request.'); + + return c.json({ + data: 'hello world' + this.dataService.getData(), + }); + }); +} diff --git a/examples/azure-functions-with-inversify/src/main.ts b/examples/azure-functions-with-inversify/src/main.ts index a116f49b..7421374b 100644 --- a/examples/azure-functions-with-inversify/src/main.ts +++ b/examples/azure-functions-with-inversify/src/main.ts @@ -1,10 +1,13 @@ import 'reflect-metadata'; import { expressPlugin } from 'nammatham'; -import hello from './functions/hello'; +import { HomeController } from './controllers/home.controller'; import { app } from './nammatham'; +import { container } from './container'; +import { DataService } from './services/data.service'; -app.addFunctions(hello); +const homeController = new HomeController(container.get(DataService)); +app.addFunctions(homeController.hello); -const dev =process.env.NODE_ENV === 'development'; +const dev = process.env.NODE_ENV === 'development'; app.register(expressPlugin({ dev })); app.start(); From 7d570290701b7de6c1a3ce68349aca4b0860fc49 Mon Sep 17 00:00:00 2001 From: Thada Wangthammang Date: Wed, 17 Apr 2024 23:46:03 +0700 Subject: [PATCH 2/6] feat(examples): add poc for inversify plugin --- .../src/controllers/home.controller.ts | 3 ++- .../src/main.ts | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/examples/azure-functions-with-inversify/src/controllers/home.controller.ts b/examples/azure-functions-with-inversify/src/controllers/home.controller.ts index ddd6371c..92df1fe4 100644 --- a/examples/azure-functions-with-inversify/src/controllers/home.controller.ts +++ b/examples/azure-functions-with-inversify/src/controllers/home.controller.ts @@ -1,8 +1,9 @@ +import { inject } from 'inversify'; import { func } from '../nammatham'; import { DataService } from '../services/data.service'; export class HomeController { - constructor(public dataService: DataService) {} + constructor(@inject(DataService) public dataService: DataService) {} hello = func .httpGet('hello', { diff --git a/examples/azure-functions-with-inversify/src/main.ts b/examples/azure-functions-with-inversify/src/main.ts index 7421374b..e0cd5c7b 100644 --- a/examples/azure-functions-with-inversify/src/main.ts +++ b/examples/azure-functions-with-inversify/src/main.ts @@ -1,12 +1,25 @@ import 'reflect-metadata'; -import { expressPlugin } from 'nammatham'; +import { BaseHandlerResolver, expressPlugin, NammathamApp } from 'nammatham'; import { HomeController } from './controllers/home.controller'; import { app } from './nammatham'; import { container } from './container'; -import { DataService } from './services/data.service'; +import { Container, interfaces } from 'inversify'; -const homeController = new HomeController(container.get(DataService)); -app.addFunctions(homeController.hello); +// Uncomment this line to use inversify plugin +// import { inverisfyPlugin } from '@nammatham/inversify'; + +// Mock inversify plugin +declare function inverisfyPlugin(options: { + container: Container; + controllers: interfaces.ServiceIdentifier[]; +}): (app: NammathamApp, handlerResolver: BaseHandlerResolver) => void; + +// Manually register controllers +// const homeController = new HomeController(container.get(DataService)); +// app.addFunctions(homeController.hello); + +// Automatically register controllers +app.register(inverisfyPlugin({ container, controllers: [HomeController] })); const dev = process.env.NODE_ENV === 'development'; app.register(expressPlugin({ dev })); From e3b0949d2cd02be65267b78d0230c4cc8dcc5f3c Mon Sep 17 00:00:00 2001 From: Thada Wangthammang Date: Wed, 17 Apr 2024 23:50:39 +0700 Subject: [PATCH 3/6] fix(examples): fix pnpm lockfile --- pnpm-lock.yaml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fd969aa7..c2c24191 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -132,6 +132,37 @@ importers: specifier: ^5.0.2 version: 5.3.3 + examples/azure-functions-with-context: + dependencies: + '@azure/functions': + specifier: ^4.1.0 + version: 4.1.0 + '@di-extra/inversify': + specifier: ^0.2.0 + version: 0.2.0 + inversify: + specifier: ^6.0.2 + version: 6.0.2 + nammatham: + specifier: 2.0.0-alpha.13 + version: link:../../packages/main + reflect-metadata: + specifier: ^0.2.1 + version: 0.2.1 + devDependencies: + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + npm-run-all: + specifier: ^4.1.5 + version: 4.1.5 + tsx: + specifier: ^4.7.0 + version: 4.7.0 + typescript: + specifier: ^5.0.2 + version: 5.3.3 + examples/azure-functions-with-inversify: dependencies: '@azure/functions': From d0413bf8e54a8fa97f2f6dc97d27535af47d21d8 Mon Sep 17 00:00:00 2001 From: Thada Wangthammang Date: Thu, 18 Apr 2024 17:43:18 +0700 Subject: [PATCH 4/6] feat: init inversify plugin --- .../package.json | 3 +- .../src/main.ts | 15 +- package.json | 8 +- packages/inversify/README.md | 148 ++++++++++++++++++ packages/inversify/package.json | 33 ++++ packages/inversify/src/main.ts | 1 + packages/inversify/src/plugin.ts | 14 ++ pnpm-lock.yaml | 12 ++ 8 files changed, 218 insertions(+), 16 deletions(-) create mode 100644 packages/inversify/README.md create mode 100644 packages/inversify/package.json create mode 100644 packages/inversify/src/main.ts create mode 100644 packages/inversify/src/plugin.ts diff --git a/examples/azure-functions-with-inversify/package.json b/examples/azure-functions-with-inversify/package.json index e5039cdf..f0aa19bb 100644 --- a/examples/azure-functions-with-inversify/package.json +++ b/examples/azure-functions-with-inversify/package.json @@ -14,8 +14,9 @@ "dependencies": { "@azure/functions": "^4.1.0", "@di-extra/inversify": "^0.2.0", - "nammatham": "2.0.0-alpha.13", + "@nammatham/inversify": "2.0.0-alpha.13", "inversify": "^6.0.2", + "nammatham": "2.0.0-alpha.13", "reflect-metadata": "^0.2.1" }, "devDependencies": { diff --git a/examples/azure-functions-with-inversify/src/main.ts b/examples/azure-functions-with-inversify/src/main.ts index e0cd5c7b..4002fdb4 100644 --- a/examples/azure-functions-with-inversify/src/main.ts +++ b/examples/azure-functions-with-inversify/src/main.ts @@ -1,25 +1,18 @@ import 'reflect-metadata'; -import { BaseHandlerResolver, expressPlugin, NammathamApp } from 'nammatham'; +import { expressPlugin } from 'nammatham'; import { HomeController } from './controllers/home.controller'; import { app } from './nammatham'; import { container } from './container'; -import { Container, interfaces } from 'inversify'; -// Uncomment this line to use inversify plugin -// import { inverisfyPlugin } from '@nammatham/inversify'; - -// Mock inversify plugin -declare function inverisfyPlugin(options: { - container: Container; - controllers: interfaces.ServiceIdentifier[]; -}): (app: NammathamApp, handlerResolver: BaseHandlerResolver) => void; +// Import the inversify plugin +import { inverisfyPlugin } from '@nammatham/inversify'; // Manually register controllers // const homeController = new HomeController(container.get(DataService)); // app.addFunctions(homeController.hello); // Automatically register controllers -app.register(inverisfyPlugin({ container, controllers: [HomeController] })); +app.register(inverisfyPlugin({ container, services: [HomeController] })); const dev = process.env.NODE_ENV === 'development'; app.register(expressPlugin({ dev })); diff --git a/package.json b/package.json index de3652fe..6c265915 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,14 @@ "scripts": { "test": "vitest", "test:coverage": "vitest run --coverage", - "dev": "nx run @nammatham/core:build && nx run-many -t dev --projects nammatham @nammatham/* --parallel=5", + "dev": "nx run @nammatham/core:build && nx run-many -t dev --projects nammatham @nammatham/* --parallel=10", "pre-local": "tsx ./scripts/pre-local.ts", "post-local": "tsx ./scripts/post-local.ts", "release": "run-s build releaseOnly", "releaseOnly": "tsx ./scripts/release.ts", - "format": "nx run-many -t format --projects=@nammatham/* --parallel=5", - "lint": "nx run-many -t lint --projects=@nammatham/* --parallel=5", - "lint:fix": "nx run-many -t lint:fix --projects=@nammatham/* --parallel=5", + "format": "nx run-many -t format --projects=@nammatham/* --parallel=10", + "lint": "nx run-many -t lint --projects=@nammatham/* --parallel=10", + "lint:fix": "nx run-many -t lint:fix --projects=@nammatham/* --parallel=10", "build": "nx run-many -t build --parallel=10", "azurite": "pnpx azurite --silent --location ./.azurite --debug ./.azurite/debug.log" }, diff --git a/packages/inversify/README.md b/packages/inversify/README.md new file mode 100644 index 00000000..2ffe6a22 --- /dev/null +++ b/packages/inversify/README.md @@ -0,0 +1,148 @@ +

+ Nammatham Logo +

+ +

+Type-safe Serverless Library for Azure Functions and friends +

+ +

NPM Version (with dist tag) + npm download

+ + +> 🚧 Alpha Stage: Internal Use Only 🚧 +> +> Please note that Nammatham v2 is currently in its Alpha stage and is intended for internal use only. As we actively develop and refine the platform, be aware that the API may undergo frequent changes. [Tracking v2 Roadmap](https://github.com/thaitype/nammatham/issues?q=is%3Aissue+is%3Aopen+label%3Av2-blocker) +> +> Note: [Nammatham v1](https://www.npmjs.com/package/nammatham) is currently in maintenance mode. no new features are actively being developed + +You're reading v2 docs + + +| Version | Status | Azure Functions
Node.js Lib | Branch | Build Status | +| ------- | ----------- | ----------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| v1.x | Maintenance | v3.x | [v1.x][v1.x] | [![Build & Test](https://github.com/thaitype/nammatham/actions/workflows/test.yml/badge.svg?branch=v1.x)](https://github.com/thaitype/nammatham/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/thaitype/nammatham/branch/v1.x/graph/badge.svg?token=Y7ZMDKFPAN)](https://codecov.io/gh/thaitype/nammatham) | +| v2.x | Alpha | v4.x | [main][main] | [![Build & Test](https://github.com/thaitype/nammatham/actions/workflows/test.yml/badge.svg?branch=main.unittest)](https://github.com/thaitype/nammatham/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/thaitype/nammatham/branch/main/graph/badge.svg?token=Y7ZMDKFPAN)](https://codecov.io/gh/thaitype/nammatham) | + +[v1.x]: https://github.com/thaitype/nammatham/tree/v1.x +[main]: https://github.com/thaitype/nammatham/tree/main + +## Description +Nammatham (นามธรรม in Thai, pronounced `/naam ma tham/`, means **abstract** in Thai) is Azure Function Nodejs. + +## Getting Started for Azure Functions + +### Install + +```bash +# Including all packages +npm install nammatham@alpha +``` + +### Example + +You can see [examples](examples) or follow the minimal app getting started below: + +> `initNammatham.create()` is a factory function for creating Nammatham App, it's a wrapper for Azure Functions App. + +```typescript +import { initNammatham, expressPlugin } from 'nammatham'; + +const n = initNammatham.create(); +const func = n.func; +const app = n.app; + +const helloFunction = func + .httpGet('hello', { + route: 'hello-world', + }) + .handler(async c => { + c.context.log('HTTP trigger function processed a request.'); + c.context.debug(`Http function processed request for url "${c.trigger.url}"`); + const name = c.trigger.query.get('name') || (await c.trigger.text()) || 'world'; + return c.text(`Hello, ${name}!`); + }); + +app.addFunctions(helloFunction); + +const dev = process.env.NODE_ENV === 'development'; +app.register(expressPlugin({ dev })); +app.start(); +``` + +Then edit `package.json` like this; + +```json +{ + "main": "dist/src/main.js", + "scripts": { + "dev": "cross-env NODE_ENV=development tsx watch src/main.ts", + "start": "tsc && func start" + } +} +``` + +Run Dev Server on locally, (For dev server use `tsx watch` for reloading run dev server using `express` ) + +``` +npm run dev +``` + +Run Azure Functions on locally (Using Official Azure Functions Node.js) + +``` +npm start +``` + + +## Nammatham Packages + +- [core][@nammatham/core], Nammatham Core package for initializing Nammatham App + +### Available Adatpers + +- [azure-functions][@nammatham/azure-functions], Azure Functions Adapter for Nammatham, internally, Azure Functions in local dev mode is dependend on Express.js. + +### Available Plugins + +- [express][@nammatham/express], Express Plugin for run server. Nammatham itself doesn't contain any server, enabling this plugin to provide better DX than the original server e.g. Azure Functions Runtime +- [trpc-azure-functions][@nammatham/trpc-azure-functions], provide [tRPC](https://trpc.io/) Plugin for Azure Functions, inclduing [express][@nammatham/express] server for local testing. + +[@nammatham/core]: packages/core +[@nammatham/azure-functions]: packages/azure-functions +[@nammatham/express]: packages/express +[@nammatham/trpc-azure-functions]: packages/trpc-azure-functions + + +## Talks +Empowering TypeScript on Azure Functions with Nammatham, Azure Open Source Day @ Microsoft Thailand, 25 Mar 2023 +[![](docs/imgs/azure-open-source-day-2023.png)](https://www.youtube.com/watch?v=n6B4-5Lt2h0) (Thai speech, subtitle will added later) +- Slides: https://docs.google.com/presentation/d/1WUIXaUxXaiixZ2bgGCfx-f4Gdrmjl4RfbwKaEfAC6t4/edit?usp=sharing + + + + +## Local Dev Setup + +```bash +# Install dependencies +pnpm install +# Before dev (Update workspace to local dependencies) +pnpm pre-local && pnpm install +# While dev +pnpm dev +# After dev before submitting PRs (Update workspace to actual dependencies), `pnpm install` for making sure lockfile is correct. +pnpm post-local && pnpm install +# Release package +pnpm release +``` + +## Inspiration +- [Azure Functions .NET](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-csharp?tabs=azure-cli%2Cin-process) +- [inversify-express-utils](https://github.com/inversify/inversify-express-utils) - We use inversify as a Dependency Injection Tool. +- [Nestjs](https://nestjs.com/) +- [typestack/routing-controllers](https://github.com/typestack/routing-controllers) +- [azure-middleware](https://github.com/emanuelcasco/azure-middleware) - Azure Functions Middleware Libray + +## Author +- Thada Wangthammang, Software Engineer, Thailand \ No newline at end of file diff --git a/packages/inversify/package.json b/packages/inversify/package.json new file mode 100644 index 00000000..14802627 --- /dev/null +++ b/packages/inversify/package.json @@ -0,0 +1,33 @@ +{ + "name": "@nammatham/inversify", + "version": "2.0.0-alpha.13", + "description": "Type-safe Serverless Library for Azure Functions and friends", + "main": "dist/main.js", + "types": "dist/main.d.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "prepublishOnly": "npm run build", + "build": "tsup src/main.ts --dts", + "format": "prettier -w src", + "lint": "tsc --noEmit && eslint ./src && prettier -c src", + "lint:fix": "eslint --fix ./src && prettier -w src", + "dev": "nodemon --watch src --ext ts --exec 'npm run build'" + }, + "keywords": [ + "azure-functions", + "azure" + ], + "author": "Thada Wangthammang", + "license": "MIT", + "dependencies": { + "@nammatham/core": "2.0.0-alpha.13", + "inversify": "^6.0.2" + }, + "repository": { + "type": "git", + "url": "https://github.com/thaitype/nammatham.git" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org/" + } +} \ No newline at end of file diff --git a/packages/inversify/src/main.ts b/packages/inversify/src/main.ts new file mode 100644 index 00000000..1110b645 --- /dev/null +++ b/packages/inversify/src/main.ts @@ -0,0 +1 @@ +export * from './plugin'; diff --git a/packages/inversify/src/plugin.ts b/packages/inversify/src/plugin.ts new file mode 100644 index 00000000..8637bd22 --- /dev/null +++ b/packages/inversify/src/plugin.ts @@ -0,0 +1,14 @@ +import type { Container, interfaces } from 'inversify'; +import type { NammathamApp, BaseHandlerResolver } from '@nammatham/core'; + +export function inverisfyPlugin(options: { + container: Container; + services: interfaces.ServiceIdentifier[]; +}): (app: NammathamApp, handlerResolver: BaseHandlerResolver) => void { + return (app: NammathamApp, handlerResolver: BaseHandlerResolver) => { + for (const service of options.services) { + const controller = options.container.get(service); + // app.addFunctions(controller, handlerResolver); + } + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c2c24191..00b7ec73 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,6 +171,9 @@ importers: '@di-extra/inversify': specifier: ^0.2.0 version: 0.2.0 + '@nammatham/inversify': + specifier: 2.0.0-alpha.13 + version: link:../../packages/inversify inversify: specifier: ^6.0.2 version: 6.0.2 @@ -314,6 +317,15 @@ importers: specifier: ^4.18.2 version: 4.18.2 + packages/inversify: + dependencies: + '@nammatham/core': + specifier: 2.0.0-alpha.13 + version: link:../core + inversify: + specifier: ^6.0.2 + version: 6.0.2 + packages/main: dependencies: '@nammatham/azure-functions': From 5fb364ef4c3e4f6c41c38bbef9dab6022b114f45 Mon Sep 17 00:00:00 2001 From: Thada Wangthammang Date: Thu, 18 Apr 2024 17:44:35 +0700 Subject: [PATCH 5/6] misc: upgrade @azure/functions to v4.4.0 --- .../azure-functions-with-context/package.json | 2 +- .../package.json | 2 +- .../azure-functions-with-test/package.json | 2 +- .../azure-functions-with-trpc/package.json | 2 +- packages/azure-functions/package.json | 2 +- packages/trpc-azure-functions/package.json | 2 +- pnpm-lock.yaml | 40 +++++++++++++------ 7 files changed, 33 insertions(+), 19 deletions(-) diff --git a/examples/azure-functions-with-context/package.json b/examples/azure-functions-with-context/package.json index e5039cdf..f44d0fbc 100644 --- a/examples/azure-functions-with-context/package.json +++ b/examples/azure-functions-with-context/package.json @@ -12,7 +12,7 @@ "author": "Thada Wangthammang", "license": "MIT", "dependencies": { - "@azure/functions": "^4.1.0", + "@azure/functions": "^4.4.0", "@di-extra/inversify": "^0.2.0", "nammatham": "2.0.0-alpha.13", "inversify": "^6.0.2", diff --git a/examples/azure-functions-with-inversify/package.json b/examples/azure-functions-with-inversify/package.json index f0aa19bb..230c8261 100644 --- a/examples/azure-functions-with-inversify/package.json +++ b/examples/azure-functions-with-inversify/package.json @@ -12,7 +12,7 @@ "author": "Thada Wangthammang", "license": "MIT", "dependencies": { - "@azure/functions": "^4.1.0", + "@azure/functions": "^4.4.0", "@di-extra/inversify": "^0.2.0", "@nammatham/inversify": "2.0.0-alpha.13", "inversify": "^6.0.2", diff --git a/examples/azure-functions-with-test/package.json b/examples/azure-functions-with-test/package.json index 2a9ea72b..ca15aa41 100644 --- a/examples/azure-functions-with-test/package.json +++ b/examples/azure-functions-with-test/package.json @@ -12,7 +12,7 @@ "author": "Thada Wangthammang", "license": "MIT", "dependencies": { - "@azure/functions": "^4.1.0", + "@azure/functions": "^4.4.0", "nammatham": "2.0.0-alpha.13" }, "devDependencies": { diff --git a/examples/azure-functions-with-trpc/package.json b/examples/azure-functions-with-trpc/package.json index 558695aa..695c9d44 100644 --- a/examples/azure-functions-with-trpc/package.json +++ b/examples/azure-functions-with-trpc/package.json @@ -14,7 +14,7 @@ "author": "Thada Wangthammang", "license": "MIT", "dependencies": { - "@azure/functions": "^4.1.0", + "@azure/functions": "^4.4.0", "nammatham": "2.0.0-alpha.13", "@nammatham/trpc-azure-functions": "2.0.0-alpha.13", "@trpc/client": "^10.45.0", diff --git a/packages/azure-functions/package.json b/packages/azure-functions/package.json index 2f920263..4d206f91 100644 --- a/packages/azure-functions/package.json +++ b/packages/azure-functions/package.json @@ -20,7 +20,7 @@ "author": "Thada Wangthammang", "license": "MIT", "dependencies": { - "@azure/functions": "^4.1.0", + "@azure/functions": "^4.4.0", "@nammatham/core": "2.0.0-alpha.13", "colorette": "^2.0.20", "express": "^4.18.2", diff --git a/packages/trpc-azure-functions/package.json b/packages/trpc-azure-functions/package.json index 9e279411..6747cbaf 100644 --- a/packages/trpc-azure-functions/package.json +++ b/packages/trpc-azure-functions/package.json @@ -20,7 +20,7 @@ "author": "Thada Wangthammang", "license": "MIT", "dependencies": { - "@azure/functions": "^4.1.0", + "@azure/functions": "^4.4.0", "@nammatham/core": "2.0.0-alpha.13", "@nammatham/azure-functions": "2.0.0-alpha.13", "@nammatham/express": "2.0.0-alpha.13", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 00b7ec73..6e4f7ba7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,8 +135,8 @@ importers: examples/azure-functions-with-context: dependencies: '@azure/functions': - specifier: ^4.1.0 - version: 4.1.0 + specifier: ^4.4.0 + version: 4.4.0 '@di-extra/inversify': specifier: ^0.2.0 version: 0.2.0 @@ -166,8 +166,8 @@ importers: examples/azure-functions-with-inversify: dependencies: '@azure/functions': - specifier: ^4.1.0 - version: 4.1.0 + specifier: ^4.4.0 + version: 4.4.0 '@di-extra/inversify': specifier: ^0.2.0 version: 0.2.0 @@ -200,8 +200,8 @@ importers: examples/azure-functions-with-test: dependencies: '@azure/functions': - specifier: ^4.1.0 - version: 4.1.0 + specifier: ^4.4.0 + version: 4.4.0 nammatham: specifier: 2.0.0-alpha.13 version: link:../../packages/main @@ -222,8 +222,8 @@ importers: examples/azure-functions-with-trpc: dependencies: '@azure/functions': - specifier: ^4.1.0 - version: 4.1.0 + specifier: ^4.4.0 + version: 4.4.0 '@nammatham/trpc-azure-functions': specifier: 2.0.0-alpha.13 version: link:../../packages/trpc-azure-functions @@ -256,8 +256,8 @@ importers: packages/azure-functions: dependencies: '@azure/functions': - specifier: ^4.1.0 - version: 4.1.0 + specifier: ^4.4.0 + version: 4.4.0 '@nammatham/core': specifier: 2.0.0-alpha.13 version: link:../core @@ -341,8 +341,8 @@ importers: packages/trpc-azure-functions: dependencies: '@azure/functions': - specifier: ^4.1.0 - version: 4.1.0 + specifier: ^4.4.0 + version: 4.4.0 '@nammatham/azure-functions': specifier: 2.0.0-alpha.13 version: link:../azure-functions @@ -388,6 +388,15 @@ packages: undici: 5.20.0 dev: false + /@azure/functions@4.4.0: + resolution: {integrity: sha512-debidWolFTsfapsK53ftzLtXJc3dbYYPc9UqJoEm1GAj1lS7jFMARQnbfTQPDqBIhuJxLZ9D8WVvhIEV7Hifzw==} + engines: {node: '>=18.0'} + dependencies: + cookie: 0.6.0 + long: 4.0.0 + undici: 5.20.0 + dev: false + /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} @@ -1960,6 +1969,11 @@ packages: engines: {node: '>= 0.6'} dev: false + /cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + dev: false + /cross-env@7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -4651,7 +4665,7 @@ packages: /trpc-azure-functions-adapter@0.0.5: resolution: {integrity: sha512-/l5ev8RILqT8LG0EK2ACLwPphr3VAILnxSXmDnSVYtSCWKtCbk4KLan9IXRVBKdA/1t0wBIwJw7ZFLxO/H9CNg==} dependencies: - '@azure/functions': 4.1.0 + '@azure/functions': 4.4.0 '@trpc/server': 10.45.0 dev: false From 183d324ee82a90a2f6dc06ce1e24545dabd63fbe Mon Sep 17 00:00:00 2001 From: Thada Wangthammang Date: Thu, 18 Apr 2024 19:11:28 +0700 Subject: [PATCH 6/6] feat: poc inversify plugin completed --- .../src/container.ts | 3 +- .../src/controllers/home.controller.ts | 13 ++++++-- packages/core/src/bases/base-handler.ts | 1 + packages/inversify/src/plugin.ts | 31 +++++++++++++++++-- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/examples/azure-functions-with-inversify/src/container.ts b/examples/azure-functions-with-inversify/src/container.ts index 5ac6234e..69182eec 100644 --- a/examples/azure-functions-with-inversify/src/container.ts +++ b/examples/azure-functions-with-inversify/src/container.ts @@ -1,6 +1,7 @@ import { Container } from 'inversify'; import { DataService } from './services/data.service'; +import { HomeController } from './controllers/home.controller'; export const container = new Container(); container.bind(DataService).toSelf(); - +container.bind(HomeController).toSelf(); diff --git a/examples/azure-functions-with-inversify/src/controllers/home.controller.ts b/examples/azure-functions-with-inversify/src/controllers/home.controller.ts index 92df1fe4..ad97977b 100644 --- a/examples/azure-functions-with-inversify/src/controllers/home.controller.ts +++ b/examples/azure-functions-with-inversify/src/controllers/home.controller.ts @@ -1,12 +1,13 @@ -import { inject } from 'inversify'; +import { inject, injectable } from 'inversify'; import { func } from '../nammatham'; import { DataService } from '../services/data.service'; +@injectable() export class HomeController { constructor(@inject(DataService) public dataService: DataService) {} hello = func - .httpGet('hello', { + .httpGet('myHello', { route: 'hello-world', }) .handler(async c => { @@ -16,4 +17,12 @@ export class HomeController { data: 'hello world' + this.dataService.getData(), }); }); + + timer = func + .timer('myTimer', { + schedule: '0 */5 * * * *', + }) + .handler(async c => { + c.context.log('Timer trigger function processed a request.'); + }); } diff --git a/packages/core/src/bases/base-handler.ts b/packages/core/src/bases/base-handler.ts index 4f692364..c6806c16 100644 --- a/packages/core/src/bases/base-handler.ts +++ b/packages/core/src/bases/base-handler.ts @@ -1,6 +1,7 @@ import type { NammamthamEndpoint } from '../types'; export abstract class BaseHandler any> { + public readonly __baseHandler: boolean = true; abstract build(): NammamthamEndpoint; abstract handler(func: Handler): this; abstract getHandler(): Handler; diff --git a/packages/inversify/src/plugin.ts b/packages/inversify/src/plugin.ts index 8637bd22..0abb54f9 100644 --- a/packages/inversify/src/plugin.ts +++ b/packages/inversify/src/plugin.ts @@ -1,14 +1,39 @@ import type { Container, interfaces } from 'inversify'; -import type { NammathamApp, BaseHandlerResolver } from '@nammatham/core'; + +import { type NammathamApp, type BaseHandlerResolver, type BaseHandler, logger } from '@nammatham/core'; export function inverisfyPlugin(options: { container: Container; services: interfaces.ServiceIdentifier[]; }): (app: NammathamApp, handlerResolver: BaseHandlerResolver) => void { + // eslint-disable-next-line @typescript-eslint/no-unused-vars return (app: NammathamApp, handlerResolver: BaseHandlerResolver) => { for (const service of options.services) { - const controller = options.container.get(service); - // app.addFunctions(controller, handlerResolver); + const instance = options.container.get(service); + if (typeof instance !== 'object') { + throw new Error(`Service ${service.toString()} is not an object`); + } + if (!instance) { + throw new Error(`Service ${service.toString()} not found`); + } + app.addFunctions(...extractClassHandlers(instance)); } }; } + +function extractClassHandlers(classInstance: object) { + const handlers: BaseHandler[] = []; + const fields = Object.entries(classInstance); + fields.forEach(([methodName, method]) => { + const handler = method as BaseHandler; + if (handler.__baseHandler) { + logger.debug( + `Adding handler from ${classInstance.constructor.name}.${methodName} with function name "${ + handler.build().name + }"` + ); + handlers.push(handler); + } + }); + return handlers; +}