From d10bcb611dbc499ae86558828f91bae3f7266766 Mon Sep 17 00:00:00 2001 From: Gxkl Date: Wed, 18 Jun 2025 10:25:55 +0800 Subject: [PATCH 1/8] feat: module plugin (#325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - [x] `npm test` passes - [x] tests and/or benchmarks are included - [x] documentation is changed or added - [x] commit message follows commit guidelines --- .gitignore | 1 + core/aop-runtime/src/LoadUnitAopHook.ts | 1 + core/core-decorator/index.ts | 2 + .../src/decorator/EggLifecycleProto.ts | 26 ++ .../src/decorator/InnerObjectProto.ts | 14 + core/core-decorator/src/util/PrototypeUtil.ts | 62 +++- core/core-decorator/test/decorators.test.ts | 71 ++++ .../fixtures/decators/ControllerLifecycle.ts | 29 ++ .../test/fixtures/decators/Router.ts | 10 + core/lifecycle/src/decorator/index.ts | 1 - core/loader/src/LoaderFactory.ts | 47 ++- core/metadata/index.ts | 2 + .../src/impl/EggInnerObjectPrototypeImpl.ts | 145 ++++++++ core/metadata/src/impl/EggPrototypeBuilder.ts | 109 +----- .../src/impl/InjectObjectPrototypeFinder.ts | 120 +++++++ core/metadata/src/model/ModuleDescriptor.ts | 1 + .../src/model/ProtoDescriptorHelper.ts | 66 ++-- core/metadata/src/model/graph/GlobalGraph.ts | 84 +---- .../src/model/graph/GlobalModuleNode.ts | 33 +- .../model/graph/GlobalModuleNodeBuilder.ts | 4 +- .../src/model/graph/ProtoGraphUtils.ts | 76 ++++ core/metadata/src/model/graph/ProtoNode.ts | 5 +- core/runtime/index.ts | 1 + core/runtime/src/impl/EggInnerobjectImpl.ts | 192 ++++++++++ core/runtime/src/impl/EggObjectImpl.ts | 4 +- core/standalone-decorator/index.ts | 1 + core/standalone-decorator/package.json | 6 +- .../src/event/EventHandler.ts | 20 ++ core/test-util/StandaloneTestUtil.ts | 76 ++++ core/test-util/package.json | 3 +- .../types/core-decorator/EggLifecycleProto.ts | 7 + core/types/core-decorator/InnerObjectProto.ts | 3 + core/types/core-decorator/Prototype.ts | 1 + core/types/core-decorator/index.ts | 3 + .../core-decorator/model/EggLifecycleInfo.ts | 3 + core/types/metadata/model/ProtoDescriptor.ts | 28 +- core/types/standalone/ServiceWorkerContext.ts | 16 + core/types/standalone/fetch.ts | 5 + core/types/standalone/index.ts | 2 + plugin/dal/lib/TransactionPrototypeHook.ts | 9 +- standalone/controller/package.json | 70 ++++ .../src/ControllerMetadataManager.ts | 26 ++ .../controller/src/ControllerRegister.ts | 5 + .../src/ControllerRegisterFactory.ts | 26 ++ standalone/controller/src/RootProtoManager.ts | 39 ++ .../controller/src/ServiceWorkerContext.ts | 21 ++ .../src/hook/ControllerLoadUnitHook.ts | 43 +++ .../src/hook/ControllerPrototypeHook.ts | 17 + .../src/impl/http/FetchEventHandler.ts | 47 +++ .../controller/src/impl/http/FetchRouter.ts | 5 + .../src/impl/http/HTTPControllerRegister.ts | 77 ++++ .../src/impl/http/HTTPMethodRegister.ts | 169 +++++++++ .../impl/http/ServiceWorkerFetchContext.ts | 40 +++ .../controller/src/utils/RequestUtils.ts | 37 ++ .../controller/src/utils/ResponseUtils.ts | 16 + standalone/controller/test/Utils.ts | 29 ++ .../fixtures/http-params/ParamController.ts | 59 ++++ .../test/fixtures/http-params/package.json | 6 + .../http-priority/PriorityController.ts | 27 ++ .../fixtures/http-priority/ViewController.ts | 17 + .../test/fixtures/http-priority/package.json | 6 + .../test/fixtures/http/GetController.ts | 25 ++ .../test/fixtures/http/PostController.ts | 12 + .../test/fixtures/http/package.json | 6 + .../controller/test/http/params.test.ts | 83 +++++ .../controller/test/http/priority.test.ts | 39 ++ .../controller/test/http/response.test.ts | 36 ++ .../controller/test/http/router.test.ts | 40 +++ standalone/controller/tsconfig.json | 12 + standalone/controller/tsconfig.pub.json | 12 + standalone/service-worker-runtime/index.ts | 4 + .../service-worker-runtime/package.json | 61 ++++ .../src/ContextProtoLoadUnitHook.ts | 34 ++ .../src/ServiceWorkerRunner.ts | 16 + .../service-worker-runtime/src/constants.ts | 8 + .../service-worker-runtime/src/types.ts | 4 + .../service-worker-runtime/test/Utils.ts | 35 ++ .../test/fixtures/simple/Event.ts | 8 + .../test/fixtures/simple/FetchEventHandler.ts | 10 + .../test/fixtures/simple/package.json | 6 + .../service-worker-runtime/test/index.test.ts | 14 + .../service-worker-runtime/tsconfig.json | 12 + .../service-worker-runtime/tsconfig.pub.json | 12 + standalone/service-worker/index.ts | 1 + standalone/service-worker/package.json | 67 ++++ .../service-worker/src/ServiceWorkerApp.ts | 22 ++ standalone/service-worker/test/Utils.ts | 29 ++ .../test/fixtures/http/controller.ts | 12 + .../test/fixtures/http/package.json | 6 + standalone/service-worker/test/http.test.ts | 23 ++ standalone/service-worker/tsconfig.json | 12 + standalone/service-worker/tsconfig.pub.json | 12 + standalone/standalone/index.ts | 10 +- standalone/standalone/package.json | 3 +- standalone/standalone/src/Runner.ts | 17 +- standalone/standalone/src/StandaloneApp.ts | 332 ++++++++++++++++++ .../standalone/src/StandaloneClassLoader.ts | 62 ++++ .../standalone/src/StandaloneContextImpl.ts | 11 - .../standalone/src/StandaloneLoadUnit.ts | 84 ----- standalone/standalone/src/common/constant.ts | 4 + .../standalone/src/common/types/index.ts | 10 + .../standalone/src/common/utils/Timing.ts | 55 +++ .../initializer/ModuleLoadUnitInitializer.ts | 75 ++++ .../StandaloneLoadUnitInitializer.ts | 77 ++++ .../src/loadUnit/StandaloneLoadUnit.ts | 99 ++++++ .../loadUnit/StandaloneLoadUnitInstance.ts | 60 ++++ standalone/standalone/src/main.ts | 20 ++ standalone/standalone/test/Ajv.test.ts | 46 +++ standalone/standalone/test/Aop.test.ts | 23 ++ standalone/standalone/test/Dal.test.ts | 26 ++ standalone/standalone/test/Inject.test.ts | 40 +++ .../standalone/test/InnerObjectProto.test.ts | 23 ++ standalone/standalone/test/Lifecycle.test.ts | 21 ++ .../standalone/test/LifecycleProto.test.ts | 33 ++ .../standalone/test/ModuleConfig.test.ts | 73 ++++ .../test/MultiInstanceProto.test.ts | 31 ++ .../test/{index.test.ts => Runner.test.ts} | 4 +- .../standalone/test/StandaloneApp.test.ts | 82 +++++ standalone/standalone/test/Utils.ts | 86 +++++ .../test/fixtures/dal-module/src/main.ts | 7 +- .../dal-transaction-module/src/FooService.ts | 16 + .../dal-transaction-module/src/main.ts | 4 +- .../test/fixtures/dependency/foo.ts | 3 +- .../egg-context-lifecycle-proto/Foo.ts | 11 + .../FooEggContextHook.ts | 10 + .../egg-context-lifecycle-proto/package.json | 6 + .../egg-object-lifecycle-proto/Foo.ts | 12 + .../FooEggObjectHook.ts | 12 + .../egg-object-lifecycle-proto/package.json | 6 + .../egg-prototype-lifecycle-proto/Foo.ts | 12 + .../FooEggPrototypeHook.ts | 13 + .../package.json | 6 + .../test/fixtures/inner-object-proto/foo.ts | 14 + .../fixtures/inner-object-proto/innerBar.ts | 16 + .../fixtures/inner-object-proto/package.json | 6 + .../invalid-inner-object-inject/foo.ts | 14 + .../invalid-inner-object-inject/innerBar.ts | 4 + .../invalid-inner-object-inject/package.json | 6 + .../load-unit-instance-lifecycle-proto/Foo.ts | 12 + .../FooLoadUnitInstanceHook.ts | 14 + .../package.json | 6 + .../fixtures/load-unit-lifecycle-proto/Foo.ts | 8 + .../FooLoadUnitHook.ts | 27 ++ .../load-unit-lifecycle-proto/Runner.ts | 13 + .../load-unit-lifecycle-proto/package.json | 6 + .../logger/DynamicLogger.ts | 1 - .../test/fixtures/multi-modules/bar/bar.ts | 8 + .../test/fixtures/multi-modules/foo/foo.ts | 5 + 148 files changed, 4067 insertions(+), 362 deletions(-) create mode 100644 core/core-decorator/src/decorator/EggLifecycleProto.ts create mode 100644 core/core-decorator/src/decorator/InnerObjectProto.ts create mode 100644 core/core-decorator/test/fixtures/decators/ControllerLifecycle.ts create mode 100644 core/core-decorator/test/fixtures/decators/Router.ts create mode 100644 core/metadata/src/impl/EggInnerObjectPrototypeImpl.ts create mode 100644 core/metadata/src/impl/InjectObjectPrototypeFinder.ts create mode 100644 core/metadata/src/model/graph/ProtoGraphUtils.ts create mode 100644 core/runtime/src/impl/EggInnerobjectImpl.ts create mode 100644 core/standalone-decorator/src/event/EventHandler.ts create mode 100644 core/test-util/StandaloneTestUtil.ts create mode 100644 core/types/core-decorator/EggLifecycleProto.ts create mode 100644 core/types/core-decorator/InnerObjectProto.ts create mode 100644 core/types/core-decorator/model/EggLifecycleInfo.ts create mode 100644 core/types/standalone/ServiceWorkerContext.ts create mode 100644 core/types/standalone/fetch.ts create mode 100644 core/types/standalone/index.ts create mode 100644 standalone/controller/package.json create mode 100644 standalone/controller/src/ControllerMetadataManager.ts create mode 100644 standalone/controller/src/ControllerRegister.ts create mode 100644 standalone/controller/src/ControllerRegisterFactory.ts create mode 100644 standalone/controller/src/RootProtoManager.ts create mode 100644 standalone/controller/src/ServiceWorkerContext.ts create mode 100644 standalone/controller/src/hook/ControllerLoadUnitHook.ts create mode 100644 standalone/controller/src/hook/ControllerPrototypeHook.ts create mode 100644 standalone/controller/src/impl/http/FetchEventHandler.ts create mode 100644 standalone/controller/src/impl/http/FetchRouter.ts create mode 100644 standalone/controller/src/impl/http/HTTPControllerRegister.ts create mode 100644 standalone/controller/src/impl/http/HTTPMethodRegister.ts create mode 100644 standalone/controller/src/impl/http/ServiceWorkerFetchContext.ts create mode 100644 standalone/controller/src/utils/RequestUtils.ts create mode 100644 standalone/controller/src/utils/ResponseUtils.ts create mode 100644 standalone/controller/test/Utils.ts create mode 100644 standalone/controller/test/fixtures/http-params/ParamController.ts create mode 100644 standalone/controller/test/fixtures/http-params/package.json create mode 100644 standalone/controller/test/fixtures/http-priority/PriorityController.ts create mode 100644 standalone/controller/test/fixtures/http-priority/ViewController.ts create mode 100644 standalone/controller/test/fixtures/http-priority/package.json create mode 100644 standalone/controller/test/fixtures/http/GetController.ts create mode 100644 standalone/controller/test/fixtures/http/PostController.ts create mode 100644 standalone/controller/test/fixtures/http/package.json create mode 100644 standalone/controller/test/http/params.test.ts create mode 100644 standalone/controller/test/http/priority.test.ts create mode 100644 standalone/controller/test/http/response.test.ts create mode 100644 standalone/controller/test/http/router.test.ts create mode 100644 standalone/controller/tsconfig.json create mode 100644 standalone/controller/tsconfig.pub.json create mode 100644 standalone/service-worker-runtime/index.ts create mode 100644 standalone/service-worker-runtime/package.json create mode 100644 standalone/service-worker-runtime/src/ContextProtoLoadUnitHook.ts create mode 100644 standalone/service-worker-runtime/src/ServiceWorkerRunner.ts create mode 100644 standalone/service-worker-runtime/src/constants.ts create mode 100644 standalone/service-worker-runtime/src/types.ts create mode 100644 standalone/service-worker-runtime/test/Utils.ts create mode 100644 standalone/service-worker-runtime/test/fixtures/simple/Event.ts create mode 100644 standalone/service-worker-runtime/test/fixtures/simple/FetchEventHandler.ts create mode 100644 standalone/service-worker-runtime/test/fixtures/simple/package.json create mode 100644 standalone/service-worker-runtime/test/index.test.ts create mode 100644 standalone/service-worker-runtime/tsconfig.json create mode 100644 standalone/service-worker-runtime/tsconfig.pub.json create mode 100644 standalone/service-worker/index.ts create mode 100644 standalone/service-worker/package.json create mode 100644 standalone/service-worker/src/ServiceWorkerApp.ts create mode 100644 standalone/service-worker/test/Utils.ts create mode 100644 standalone/service-worker/test/fixtures/http/controller.ts create mode 100644 standalone/service-worker/test/fixtures/http/package.json create mode 100644 standalone/service-worker/test/http.test.ts create mode 100644 standalone/service-worker/tsconfig.json create mode 100644 standalone/service-worker/tsconfig.pub.json create mode 100644 standalone/standalone/src/StandaloneApp.ts create mode 100644 standalone/standalone/src/StandaloneClassLoader.ts delete mode 100644 standalone/standalone/src/StandaloneContextImpl.ts delete mode 100644 standalone/standalone/src/StandaloneLoadUnit.ts create mode 100644 standalone/standalone/src/common/constant.ts create mode 100644 standalone/standalone/src/common/types/index.ts create mode 100644 standalone/standalone/src/common/utils/Timing.ts create mode 100644 standalone/standalone/src/initializer/ModuleLoadUnitInitializer.ts create mode 100644 standalone/standalone/src/initializer/StandaloneLoadUnitInitializer.ts create mode 100644 standalone/standalone/src/loadUnit/StandaloneLoadUnit.ts create mode 100644 standalone/standalone/src/loadUnit/StandaloneLoadUnitInstance.ts create mode 100644 standalone/standalone/test/Ajv.test.ts create mode 100644 standalone/standalone/test/Aop.test.ts create mode 100644 standalone/standalone/test/Dal.test.ts create mode 100644 standalone/standalone/test/Inject.test.ts create mode 100644 standalone/standalone/test/InnerObjectProto.test.ts create mode 100644 standalone/standalone/test/Lifecycle.test.ts create mode 100644 standalone/standalone/test/LifecycleProto.test.ts create mode 100644 standalone/standalone/test/ModuleConfig.test.ts create mode 100644 standalone/standalone/test/MultiInstanceProto.test.ts rename standalone/standalone/test/{index.test.ts => Runner.test.ts} (99%) create mode 100644 standalone/standalone/test/StandaloneApp.test.ts create mode 100644 standalone/standalone/test/Utils.ts create mode 100644 standalone/standalone/test/fixtures/egg-context-lifecycle-proto/Foo.ts create mode 100644 standalone/standalone/test/fixtures/egg-context-lifecycle-proto/FooEggContextHook.ts create mode 100644 standalone/standalone/test/fixtures/egg-context-lifecycle-proto/package.json create mode 100644 standalone/standalone/test/fixtures/egg-object-lifecycle-proto/Foo.ts create mode 100644 standalone/standalone/test/fixtures/egg-object-lifecycle-proto/FooEggObjectHook.ts create mode 100644 standalone/standalone/test/fixtures/egg-object-lifecycle-proto/package.json create mode 100644 standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/Foo.ts create mode 100644 standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/FooEggPrototypeHook.ts create mode 100644 standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/package.json create mode 100644 standalone/standalone/test/fixtures/inner-object-proto/foo.ts create mode 100644 standalone/standalone/test/fixtures/inner-object-proto/innerBar.ts create mode 100644 standalone/standalone/test/fixtures/inner-object-proto/package.json create mode 100644 standalone/standalone/test/fixtures/invalid-inner-object-inject/foo.ts create mode 100644 standalone/standalone/test/fixtures/invalid-inner-object-inject/innerBar.ts create mode 100644 standalone/standalone/test/fixtures/invalid-inner-object-inject/package.json create mode 100644 standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/Foo.ts create mode 100644 standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/FooLoadUnitInstanceHook.ts create mode 100644 standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/package.json create mode 100644 standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Foo.ts create mode 100644 standalone/standalone/test/fixtures/load-unit-lifecycle-proto/FooLoadUnitHook.ts create mode 100644 standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Runner.ts create mode 100644 standalone/standalone/test/fixtures/load-unit-lifecycle-proto/package.json create mode 100644 standalone/standalone/test/fixtures/multi-modules/bar/bar.ts diff --git a/.gitignore b/.gitignore index 05928e84..2892378e 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ plugin/tegg/test/fixtures/apps/**/*.js !plugin/config/test/fixtures/**/node_modules .node .egg +fixtures/tmp/ diff --git a/core/aop-runtime/src/LoadUnitAopHook.ts b/core/aop-runtime/src/LoadUnitAopHook.ts index 7971da27..bc6aca9b 100644 --- a/core/aop-runtime/src/LoadUnitAopHook.ts +++ b/core/aop-runtime/src/LoadUnitAopHook.ts @@ -17,6 +17,7 @@ export class LoadUnitAopHook implements LifecycleHook { + for (const proto of loadUnit.iterateEggPrototype()) { const protoWithClazz = proto as EggPrototypeWithClazz; const clazz = protoWithClazz.clazz; diff --git a/core/core-decorator/index.ts b/core/core-decorator/index.ts index 0e2b9fe6..5e947c6a 100644 --- a/core/core-decorator/index.ts +++ b/core/core-decorator/index.ts @@ -9,6 +9,8 @@ export * from './src/decorator/EggQualifier'; export * from './src/decorator/MultiInstanceProto'; export * from './src/decorator/MultiInstanceInfo'; export * from './src/decorator/ConfigSource'; +export * from './src/decorator/EggLifecycleProto'; +export * from './src/decorator/InnerObjectProto'; export * from './src/util/MetadataUtil'; export * from './src/util/PrototypeUtil'; diff --git a/core/core-decorator/src/decorator/EggLifecycleProto.ts b/core/core-decorator/src/decorator/EggLifecycleProto.ts new file mode 100644 index 00000000..598a46e7 --- /dev/null +++ b/core/core-decorator/src/decorator/EggLifecycleProto.ts @@ -0,0 +1,26 @@ +import assert from 'node:assert'; +import type { CommonEggLifecycleProtoParams, EggLifecycleProtoParams, EggProtoImplClass } from '@eggjs/tegg-types'; +import { PrototypeUtil } from '../util/PrototypeUtil'; +import { InnerObjectProto } from './InnerObjectProto'; + +export function EggLifecycleProto(params: CommonEggLifecycleProtoParams) { + return function(clazz: EggProtoImplClass) { + const { type, ...protoParams } = params || {}; + assert(type, 'EggLifecycle decorator should have type property'); + + InnerObjectProto(protoParams)(clazz); + + PrototypeUtil.setIsEggLifecyclePrototype(clazz); + PrototypeUtil.setEggLifecyclePrototypeMetadata(clazz, { type }); + }; +} + +const createLifecycleProto = (type: CommonEggLifecycleProtoParams['type']) => { + return (params?: EggLifecycleProtoParams) => EggLifecycleProto({ type, ...params }); +}; + +export const LoadUnitLifecycleProto = createLifecycleProto('LoadUnit'); +export const LoadUnitInstanceLifecycleProto = createLifecycleProto('LoadUnitInstance'); +export const EggObjectLifecycleProto = createLifecycleProto('EggObject'); +export const EggPrototypeLifecycleProto = createLifecycleProto('EggPrototype'); +export const EggContextLifecycleProto = createLifecycleProto('EggContext'); diff --git a/core/core-decorator/src/decorator/InnerObjectProto.ts b/core/core-decorator/src/decorator/InnerObjectProto.ts new file mode 100644 index 00000000..4dda9f9e --- /dev/null +++ b/core/core-decorator/src/decorator/InnerObjectProto.ts @@ -0,0 +1,14 @@ +import { EGG_INNER_OBJECT_PROTO_IMPL_TYPE, EggProtoImplClass, InnerObjectProtoParams } from '@eggjs/tegg-types'; +import { PrototypeUtil } from '../util/PrototypeUtil'; +import { SingletonProto } from './SingletonProto'; + +export function InnerObjectProto(params?: InnerObjectProtoParams) { + return function(clazz: EggProtoImplClass) { + const protoParams = { + protoImplType: EGG_INNER_OBJECT_PROTO_IMPL_TYPE, + ...params, + }; + SingletonProto(protoParams)(clazz); + PrototypeUtil.setIsEggInnerObject(clazz); + }; +} diff --git a/core/core-decorator/src/util/PrototypeUtil.ts b/core/core-decorator/src/util/PrototypeUtil.ts index 775b6ba2..0dbf7951 100644 --- a/core/core-decorator/src/util/PrototypeUtil.ts +++ b/core/core-decorator/src/util/PrototypeUtil.ts @@ -1,12 +1,15 @@ import { + EggLifecycleInfo, EggMultiInstanceCallbackPrototypeInfo, EggMultiInstancePrototypeInfo, EggProtoImplClass, EggPrototypeInfo, - EggPrototypeName, InitTypeQualifierAttribute, + EggPrototypeName, + InitTypeQualifierAttribute, InjectConstructorInfo, InjectObjectInfo, - InjectType, LoadUnitNameQualifierAttribute, + InjectType, + LoadUnitNameQualifierAttribute, MultiInstancePrototypeGetObjectsContext, MultiInstanceType, QualifierAttribute, @@ -16,6 +19,9 @@ import { MetadataUtil } from './MetadataUtil'; export class PrototypeUtil { static readonly IS_EGG_OBJECT_PROTOTYPE = Symbol.for('EggPrototype#isEggPrototype'); static readonly IS_EGG_OBJECT_MULTI_INSTANCE_PROTOTYPE = Symbol.for('EggPrototype#isEggMultiInstancePrototype'); + static readonly IS_EGG_LIFECYCLE_PROTOTYPE = Symbol.for('EggPrototype#isEggLifecyclePrototype'); + static readonly EGG_LIFECYCLE_PROTOTYPE_METADATA = Symbol.for('EggPrototype#eggLifecyclePrototype#metadata'); + static readonly IS_EGG_INNER_OBJECT = Symbol.for('EggPrototype#isEggInnerObject'); static readonly FILE_PATH = Symbol.for('EggPrototype.filePath'); static readonly PROTOTYPE_PROPERTY = Symbol.for('EggPrototype.Property'); static readonly MULTI_INSTANCE_PROTOTYPE_STATIC_PROPERTY = Symbol.for('EggPrototype.MultiInstanceStaticProperty'); @@ -74,6 +80,58 @@ export class PrototypeUtil { return MultiInstanceType.DYNAMIC; } + /** + * Mark class is egg lifecycle prototype + * @param clazz - + */ + static setIsEggLifecyclePrototype(clazz: EggProtoImplClass) { + MetadataUtil.defineMetaData(PrototypeUtil.IS_EGG_LIFECYCLE_PROTOTYPE, true, clazz); + } + + /** + * If class is egg lifecycle prototype, return true + * @param clazz - + */ + static isEggLifecyclePrototype(clazz: EggProtoImplClass): boolean { + return MetadataUtil.getOwnBooleanMetaData(PrototypeUtil.IS_EGG_LIFECYCLE_PROTOTYPE, clazz); + } + + /** + * Set egg lifecycle prototype metadata, like the lifecycle type + * @param clazz - + * @param metadata - + */ + static setEggLifecyclePrototypeMetadata(clazz: EggProtoImplClass, metadata: EggLifecycleInfo) { + MetadataUtil.defineMetaData(PrototypeUtil.EGG_LIFECYCLE_PROTOTYPE_METADATA, metadata, clazz); + } + + /** + * Get egg lifecycle prototype metadata + * @param clazz - + */ + static getEggLifecyclePrototypeMetadata(clazz: EggProtoImplClass): EggLifecycleInfo | undefined { + if (!PrototypeUtil.isEggLifecyclePrototype(clazz)) { + return undefined; + } + return MetadataUtil.getOwnMetaData(PrototypeUtil.EGG_LIFECYCLE_PROTOTYPE_METADATA, clazz); + } + + /** + * Mark class is egg inner object prototype + * @param clazz - + */ + static setIsEggInnerObject(clazz: EggProtoImplClass) { + MetadataUtil.defineMetaData(PrototypeUtil.IS_EGG_INNER_OBJECT, true, clazz); + } + + /** + * If class is egg inner object prototype, return true + * @param clazz - + */ + static isEggInnerObject(clazz: EggProtoImplClass): boolean { + return MetadataUtil.getOwnBooleanMetaData(PrototypeUtil.IS_EGG_INNER_OBJECT, clazz); + } + /** * set class file path * @param {Function} clazz - diff --git a/core/core-decorator/test/decorators.test.ts b/core/core-decorator/test/decorators.test.ts index 2250e5b4..633886b0 100644 --- a/core/core-decorator/test/decorators.test.ts +++ b/core/core-decorator/test/decorators.test.ts @@ -6,6 +6,7 @@ import { InitTypeQualifierAttribute, DEFAULT_PROTO_IMPL_TYPE, MultiInstanceType, + EggProtoImplClass, } from '@eggjs/tegg-types'; import type { EggPrototypeInfo, EggMultiInstancePrototypeInfo, InjectObjectInfo } from '@eggjs/tegg-types'; @@ -25,6 +26,15 @@ import { ParentSingletonProto, ParentStaticMultiInstanceProto, } from './fixtures/decators/ChildService'; +import { OtherRouter, Router } from './fixtures/decators/Router'; +import { + ControllerContextLifecycle, + ControllerLoadUnitInstanceLifecycle, + ControllerLoadUnitLifecycle, + ControllerObjectLifecycle, + ControllerOtherLifecycle, + ControllerPrototypeLifecycle, +} from './fixtures/decators/ControllerLifecycle'; describe('test/decorator.test.ts', () => { describe('ContextProto', () => { @@ -192,6 +202,67 @@ describe('test/decorator.test.ts', () => { }); }); + describe('InnerObjectProto', () => { + it('should work', () => { + assert(PrototypeUtil.isEggPrototype(Router)); + assert(PrototypeUtil.isEggInnerObject(Router)); + const expectObjectProperty: EggPrototypeInfo = { + name: 'router', + initType: ObjectInitType.SINGLETON, + accessLevel: AccessLevel.PRIVATE, + protoImplType: DEFAULT_PROTO_IMPL_TYPE, + className: 'Router', + }; + assert.deepStrictEqual(PrototypeUtil.getProperty(Router), expectObjectProperty); + }); + + it('should params work', () => { + const expectObjectProperty: EggPrototypeInfo = { + name: 'customRouter', + initType: ObjectInitType.SINGLETON, + accessLevel: AccessLevel.PUBLIC, + protoImplType: DEFAULT_PROTO_IMPL_TYPE, + className: 'OtherRouter', + }; + assert.deepStrictEqual(PrototypeUtil.getProperty(OtherRouter), expectObjectProperty); + }); + }); + + describe('EggLifecycleProto', () => { + const assertLifecycleProtoMetadata = (clazz: EggProtoImplClass, type: string) => { + assert(PrototypeUtil.isEggPrototype(clazz)); + assert(PrototypeUtil.isEggInnerObject(clazz)); + const expectObjectProperty: EggPrototypeInfo = { + name: clazz.name.replace(/^./, c => c.toLowerCase()), + initType: ObjectInitType.SINGLETON, + accessLevel: AccessLevel.PRIVATE, + protoImplType: DEFAULT_PROTO_IMPL_TYPE, + className: clazz.name, + }; + assert.deepStrictEqual(PrototypeUtil.getProperty(clazz), expectObjectProperty); + assert.deepStrictEqual(PrototypeUtil.getEggLifecyclePrototypeMetadata(clazz), { type }); + }; + + it('should work', () => { + assertLifecycleProtoMetadata(ControllerLoadUnitLifecycle, 'LoadUnit'); + assertLifecycleProtoMetadata(ControllerLoadUnitInstanceLifecycle, 'LoadUnitInstance'); + assertLifecycleProtoMetadata(ControllerObjectLifecycle, 'EggObject'); + assertLifecycleProtoMetadata(ControllerPrototypeLifecycle, 'EggPrototype'); + assertLifecycleProtoMetadata(ControllerContextLifecycle, 'EggContext'); + }); + + it('should params work', () => { + const expectObjectProperty: EggPrototypeInfo = { + name: 'customName', + initType: ObjectInitType.SINGLETON, + accessLevel: AccessLevel.PUBLIC, + protoImplType: DEFAULT_PROTO_IMPL_TYPE, + className: 'ControllerOtherLifecycle', + }; + assert.deepStrictEqual(PrototypeUtil.getProperty(ControllerOtherLifecycle), expectObjectProperty); + }); + }); + it('should get the right file path', () => { assert(PrototypeUtil.getFilePath(CacheService) === CacheService.fileName); }); diff --git a/core/core-decorator/test/fixtures/decators/ControllerLifecycle.ts b/core/core-decorator/test/fixtures/decators/ControllerLifecycle.ts new file mode 100644 index 00000000..1362af5a --- /dev/null +++ b/core/core-decorator/test/fixtures/decators/ControllerLifecycle.ts @@ -0,0 +1,29 @@ +import { + AccessLevel, + EggContextLifecycleProto, + EggObjectLifecycleProto, + EggPrototypeLifecycleProto, + LoadUnitInstanceLifecycleProto, + LoadUnitLifecycleProto +} from '../../..'; + +@LoadUnitLifecycleProto() +export class ControllerLoadUnitLifecycle {} + +@LoadUnitInstanceLifecycleProto() +export class ControllerLoadUnitInstanceLifecycle {} + +@EggObjectLifecycleProto() +export class ControllerObjectLifecycle {} + +@EggPrototypeLifecycleProto() +export class ControllerPrototypeLifecycle {} + +@EggContextLifecycleProto() +export class ControllerContextLifecycle {} + +@LoadUnitLifecycleProto({ + accessLevel: AccessLevel.PUBLIC, + name: 'customName', +}) +export class ControllerOtherLifecycle {} diff --git a/core/core-decorator/test/fixtures/decators/Router.ts b/core/core-decorator/test/fixtures/decators/Router.ts new file mode 100644 index 00000000..219c77a5 --- /dev/null +++ b/core/core-decorator/test/fixtures/decators/Router.ts @@ -0,0 +1,10 @@ +import { AccessLevel, InnerObjectProto } from '../../..'; + +@InnerObjectProto() +export class Router {} + +@InnerObjectProto({ + accessLevel: AccessLevel.PUBLIC, + name: 'customRouter', +}) +export class OtherRouter {} diff --git a/core/lifecycle/src/decorator/index.ts b/core/lifecycle/src/decorator/index.ts index 84d8eba5..38874cef 100644 --- a/core/lifecycle/src/decorator/index.ts +++ b/core/lifecycle/src/decorator/index.ts @@ -21,7 +21,6 @@ function createStaticLifecycle(hookName: LifecycleHookName) { }; } - export const LifecyclePostConstruct = createLifecycle('postConstruct'); export const LifecyclePreInject = createLifecycle('preInject'); export const LifecyclePostInject = createLifecycle('postInject'); diff --git a/core/loader/src/LoaderFactory.ts b/core/loader/src/LoaderFactory.ts index 1c0bb21b..9c16b92b 100644 --- a/core/loader/src/LoaderFactory.ts +++ b/core/loader/src/LoaderFactory.ts @@ -23,25 +23,36 @@ export class LoaderFactory { const result: ModuleDescriptor[] = []; const multiInstanceClazzList: EggProtoImplClass[] = []; for (const moduleReference of moduleReferences) { - const loader = LoaderFactory.createLoader(moduleReference.path, moduleReference.loaderType || EggLoadUnitType.MODULE); - const res: ModuleDescriptor = { - name: moduleReference.name, - unitPath: moduleReference.path, - clazzList: [], - protos: [], - multiInstanceClazzList, - optional: moduleReference.optional, - }; - result.push(res); - const clazzList = loader.load(); - for (const clazz of clazzList) { - if (PrototypeUtil.isEggPrototype(clazz)) { - res.clazzList.push(clazz); - } else if (PrototypeUtil.isEggMultiInstancePrototype(clazz)) { - res.multiInstanceClazzList.push(clazz); - } - } + const module = LoaderFactory.loadModule(moduleReference, multiInstanceClazzList); + result.push(module); } return result; } + + static loadModule(moduleReference: ModuleReference, multiInstanceClazzList?: EggProtoImplClass[]): ModuleDescriptor { + const loader = LoaderFactory.createLoader(moduleReference.path, moduleReference.loaderType || EggLoadUnitType.MODULE); + + const res: ModuleDescriptor = { + name: moduleReference.name, + unitPath: moduleReference.path, + clazzList: [], + protos: [], + multiInstanceClazzList: multiInstanceClazzList || [], + innerObjectClazzList: [], + optional: moduleReference.optional, + }; + + const clazzList = loader.load(); + for (const clazz of clazzList) { + if (PrototypeUtil.isEggInnerObject(clazz)) { + res.innerObjectClazzList.push(clazz); + } else if (PrototypeUtil.isEggPrototype(clazz)) { + res.clazzList.push(clazz); + } else if (PrototypeUtil.isEggMultiInstancePrototype(clazz)) { + res.multiInstanceClazzList.push(clazz); + } + } + + return res; + } } diff --git a/core/metadata/index.ts b/core/metadata/index.ts index 8834354b..42b90820 100644 --- a/core/metadata/index.ts +++ b/core/metadata/index.ts @@ -7,6 +7,7 @@ export * from './src/model/LoadUnit'; export * from './src/errors'; export * from './src/util/ClassUtil'; export * from './src/impl/LoadUnitMultiInstanceProtoHook'; +export * from './src/impl/EggInnerObjectPrototypeImpl'; export * from './src/model/AppGraph'; export * from './src/model/graph/GlobalGraph'; @@ -14,6 +15,7 @@ export * from './src/model/graph/GlobalModuleNode'; export * from './src/model/graph/GlobalModuleNodeBuilder'; export * from './src/model/graph/ProtoNode'; export * from './src/model/graph/ProtoSelector'; +export * from './src/model/graph/ProtoGraphUtils'; export * from './src/model/ProtoDescriptor/AbstractProtoDescriptor'; export * from './src/model/ProtoDescriptor/ClassProtoDescriptor'; export * from './src/model/ModuleDescriptor'; diff --git a/core/metadata/src/impl/EggInnerObjectPrototypeImpl.ts b/core/metadata/src/impl/EggInnerObjectPrototypeImpl.ts new file mode 100644 index 00000000..427aa9dd --- /dev/null +++ b/core/metadata/src/impl/EggInnerObjectPrototypeImpl.ts @@ -0,0 +1,145 @@ +import assert from 'node:assert'; +import { + EGG_INNER_OBJECT_PROTO_IMPL_TYPE, + InjectType, + MetadataUtil, + PrototypeUtil, + QualifierAttribute, + QualifierUtil, +} from '@eggjs/core-decorator'; +import type { + AccessLevel, + EggProtoImplClass, + EggPrototype, + EggPrototypeLifecycleContext, + EggPrototypeName, + Id, + InjectConstructorProto, + InjectObjectProto, + MetaDataKey, + ObjectInitTypeLike, + QualifierInfo, + QualifierValue, +} from '@eggjs/tegg-types'; +import { InjectObjectPrototypeFinder } from './InjectObjectPrototypeFinder'; +import { IdenticalUtil } from '@eggjs/tegg-lifecycle'; +import { EggPrototypeCreatorFactory } from '../factory/EggPrototypeCreatorFactory'; + +export class EggInnerObjectPrototypeImpl implements EggPrototype { + private readonly clazz: EggProtoImplClass; + private readonly qualifiers: QualifierInfo[]; + readonly filepath: string; + + readonly id: string; + readonly name: EggPrototypeName; + readonly initType: ObjectInitTypeLike; + readonly accessLevel: AccessLevel; + readonly injectObjects: Array; + readonly injectType: InjectType; + readonly loadUnitId: Id; + readonly className?: string; + readonly multiInstanceConstructorIndex?: number; + readonly multiInstanceConstructorAttributes?: QualifierAttribute[]; + + constructor( + id: string, + name: EggPrototypeName, + clazz: EggProtoImplClass, + filepath: string, + initType: ObjectInitTypeLike, + accessLevel: AccessLevel, + injectObjectMap: Array, + loadUnitId: Id, + qualifiers: QualifierInfo[], + className?: string, + injectType?: InjectType, + multiInstanceConstructorIndex?: number, + multiInstanceConstructorAttributes?: QualifierAttribute[], + ) { + this.id = id; + this.clazz = clazz; + this.name = name; + this.filepath = filepath; + this.initType = initType; + this.accessLevel = accessLevel; + this.injectObjects = injectObjectMap; + this.loadUnitId = loadUnitId; + this.qualifiers = qualifiers; + this.className = className; + this.injectType = injectType || InjectType.PROPERTY; + this.multiInstanceConstructorIndex = multiInstanceConstructorIndex; + this.multiInstanceConstructorAttributes = multiInstanceConstructorAttributes; + } + + verifyQualifiers(qualifiers: QualifierInfo[]): boolean { + for (const qualifier of qualifiers) { + if (!this.verifyQualifier(qualifier)) { + return false; + } + } + return true; + } + + verifyQualifier(qualifier: QualifierInfo): boolean { + const selfQualifiers = this.qualifiers.find(t => t.attribute === qualifier.attribute); + return selfQualifiers?.value === qualifier.value; + } + + getQualifier(attribute: string): QualifierValue | undefined { + return this.qualifiers.find(t => t.attribute === attribute)?.value; + } + + constructEggObject(...args: any): object { + return Reflect.construct(this.clazz, args); + } + + getMetaData(metadataKey: MetaDataKey): T | undefined { + return MetadataUtil.getMetaData(metadataKey, this.clazz); + } + + static create(ctx: EggPrototypeLifecycleContext) { + const { clazz, loadUnit } = ctx; + const filepath = PrototypeUtil.getFilePath(clazz); + assert(filepath, 'not find filepath'); + const name = ctx.prototypeInfo.name; + const className = ctx.prototypeInfo.className; + const initType = ctx.prototypeInfo.initType; + const accessLevel = ctx.prototypeInfo.accessLevel; + const injectType = PrototypeUtil.getInjectType(clazz); + const injectObjects = PrototypeUtil.getInjectObjects(clazz) || []; + const qualifiers = QualifierUtil.mergeQualifiers( + QualifierUtil.getProtoQualifiers(clazz), + (ctx.prototypeInfo.qualifiers ?? []), + ); + const properQualifiers = ctx.prototypeInfo.properQualifiers ?? {}; + const multiInstanceConstructorIndex = PrototypeUtil.getMultiInstanceConstructorIndex(clazz); + const multiInstanceConstructorAttributes = PrototypeUtil.getMultiInstanceConstructorAttributes(clazz); + const injectObjectProtos = InjectObjectPrototypeFinder.findInjectObjectPrototypes({ + clazz, + loadUnit, + properQualifiers, + initType, + injectType, + injectObjects, + }); + const id = IdenticalUtil.createProtoId(loadUnit.id, name); + + return new EggInnerObjectPrototypeImpl( + id, + name, + clazz, + filepath, + initType, + accessLevel, + injectObjectProtos, + loadUnit.id, + qualifiers, + className, + injectType, + multiInstanceConstructorIndex, + multiInstanceConstructorAttributes, + ); + } +} + +EggPrototypeCreatorFactory.registerPrototypeCreator(EGG_INNER_OBJECT_PROTO_IMPL_TYPE, EggInnerObjectPrototypeImpl.create); diff --git a/core/metadata/src/impl/EggPrototypeBuilder.ts b/core/metadata/src/impl/EggPrototypeBuilder.ts index 8da11612..8437bffa 100644 --- a/core/metadata/src/impl/EggPrototypeBuilder.ts +++ b/core/metadata/src/impl/EggPrototypeBuilder.ts @@ -5,24 +5,18 @@ import type { EggProtoImplClass, EggPrototype, EggPrototypeLifecycleContext, - EggPrototypeName, InjectConstructor, + EggPrototypeName, + InjectConstructor, InjectObject, - InjectObjectProto, LoadUnit, ObjectInitTypeLike, QualifierInfo, } from '@eggjs/tegg-types'; -import { - DEFAULT_PROTO_IMPL_TYPE, - InitTypeQualifierAttribute, - InjectConstructorProto, - ObjectInitType, -} from '@eggjs/tegg-types'; -import { EggPrototypeFactory } from '../factory/EggPrototypeFactory'; +import { DEFAULT_PROTO_IMPL_TYPE } from '@eggjs/tegg-types'; import { IdenticalUtil } from '@eggjs/tegg-lifecycle'; import { EggPrototypeImpl } from './EggPrototypeImpl'; import { EggPrototypeCreatorFactory } from '../factory/EggPrototypeCreatorFactory'; -import { EggPrototypeNotFound, MultiPrototypeFound } from '../errors'; +import { InjectObjectPrototypeFinder } from './InjectObjectPrototypeFinder'; export class EggPrototypeBuilder { private clazz: EggProtoImplClass; @@ -63,94 +57,15 @@ export class EggPrototypeBuilder { return builder.build(); } - private tryFindDefaultPrototype(injectObject: InjectObject | InjectConstructor): EggPrototype { - const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - const multiInstancePropertyQualifiers = this.properQualifiers[injectObject.refName as string] ?? []; - return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, QualifierUtil.mergeQualifiers( - propertyQualifiers, - multiInstancePropertyQualifiers, - )); - } - - private tryFindContextPrototype(injectObject: InjectObject | InjectConstructor): EggPrototype { - const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - const multiInstancePropertyQualifiers = this.properQualifiers[injectObject.refName as string] ?? []; - return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, QualifierUtil.mergeQualifiers( - propertyQualifiers, - multiInstancePropertyQualifiers, - [{ - attribute: InitTypeQualifierAttribute, - value: ObjectInitType.CONTEXT, - }], - )); - } - - private tryFindSelfInitTypePrototype(injectObject: InjectObject | InjectConstructor): EggPrototype { - const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - const multiInstancePropertyQualifiers = this.properQualifiers[injectObject.refName as string] ?? []; - return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, QualifierUtil.mergeQualifiers( - propertyQualifiers, - multiInstancePropertyQualifiers, - [{ - attribute: InitTypeQualifierAttribute, - value: this.initType, - }], - )); - } - - private findInjectObjectPrototype(injectObject: InjectObject | InjectConstructor): EggPrototype { - const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - try { - return this.tryFindDefaultPrototype(injectObject); - } catch (e) { - if (!(e instanceof MultiPrototypeFound && !propertyQualifiers.find(t => t.attribute === InitTypeQualifierAttribute))) { - throw e; - } - } - try { - return this.tryFindContextPrototype(injectObject); - } catch (e) { - if (!(e instanceof EggPrototypeNotFound)) { - throw e; - } - } - return this.tryFindSelfInitTypePrototype(injectObject); - } - public build(): EggPrototype { - const injectObjectProtos: Array = []; - for (const injectObject of this.injectObjects) { - const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - try { - const proto = this.findInjectObjectPrototype(injectObject); - let injectObjectProto: InjectObjectProto | InjectConstructorProto; - if (this.injectType === InjectType.PROPERTY) { - injectObjectProto = { - refName: injectObject.refName, - objName: injectObject.objName, - qualifiers: propertyQualifiers, - proto, - }; - } else { - injectObjectProto = { - refIndex: (injectObject as InjectConstructor).refIndex, - refName: injectObject.refName, - objName: injectObject.objName, - qualifiers: propertyQualifiers, - proto, - }; - } - if (injectObject.optional) { - injectObject.optional = true; - } - injectObjectProtos.push(injectObjectProto); - } catch (e) { - if (e instanceof EggPrototypeNotFound && injectObject.optional) { - continue; - } - throw e; - } - } + const injectObjectProtos = InjectObjectPrototypeFinder.findInjectObjectPrototypes({ + clazz: this.clazz, + loadUnit: this.loadUnit, + properQualifiers: this.properQualifiers, + initType: this.initType, + injectType: this.injectType, + injectObjects: this.injectObjects, + }); const id = IdenticalUtil.createProtoId(this.loadUnit.id, this.name); return new EggPrototypeImpl( id, diff --git a/core/metadata/src/impl/InjectObjectPrototypeFinder.ts b/core/metadata/src/impl/InjectObjectPrototypeFinder.ts new file mode 100644 index 00000000..7b02dd77 --- /dev/null +++ b/core/metadata/src/impl/InjectObjectPrototypeFinder.ts @@ -0,0 +1,120 @@ +import { + EggProtoImplClass, + EggPrototype, + InitTypeQualifierAttribute, + InjectConstructor, + InjectConstructorProto, + InjectObject, + type InjectObjectProto, + InjectType, + LoadUnit, + ObjectInitType, + type ObjectInitTypeLike, + QualifierInfo, +} from '@eggjs/tegg-types'; +import { QualifierUtil } from '@eggjs/core-decorator'; +import { EggPrototypeFactory } from '../factory/EggPrototypeFactory'; +import { EggPrototypeNotFound, MultiPrototypeFound } from '../errors'; + +interface EggProtoInfo { + clazz: EggProtoImplClass; + loadUnit: LoadUnit; + properQualifiers: Record; + initType: ObjectInitTypeLike; + injectType?: InjectType; + injectObjects: Array; +} + +export class InjectObjectPrototypeFinder { + private static tryFindDefaultPrototype(proto: EggProtoInfo, injectObject: InjectObject | InjectConstructor): EggPrototype { + const propertyQualifiers = QualifierUtil.getProperQualifiers(proto.clazz, injectObject.refName); + const multiInstancePropertyQualifiers = proto.properQualifiers[injectObject.refName as string] ?? []; + return EggPrototypeFactory.instance.getPrototype(injectObject.objName, proto.loadUnit, QualifierUtil.mergeQualifiers( + propertyQualifiers, + multiInstancePropertyQualifiers, + )); + } + + private static tryFindContextPrototype(proto: EggProtoInfo, injectObject: InjectObject | InjectConstructor): EggPrototype { + const propertyQualifiers = QualifierUtil.getProperQualifiers(proto.clazz, injectObject.refName); + const multiInstancePropertyQualifiers = proto.properQualifiers[injectObject.refName as string] ?? []; + return EggPrototypeFactory.instance.getPrototype(injectObject.objName, proto.loadUnit, QualifierUtil.mergeQualifiers( + propertyQualifiers, + multiInstancePropertyQualifiers, + [{ + attribute: InitTypeQualifierAttribute, + value: ObjectInitType.CONTEXT, + }], + )); + } + + private static tryFindSelfInitTypePrototype(proto: EggProtoInfo, injectObject: InjectObject | InjectConstructor): EggPrototype { + const propertyQualifiers = QualifierUtil.getProperQualifiers(proto.clazz, injectObject.refName); + const multiInstancePropertyQualifiers = proto.properQualifiers[injectObject.refName as string] ?? []; + return EggPrototypeFactory.instance.getPrototype(injectObject.objName, proto.loadUnit, QualifierUtil.mergeQualifiers( + propertyQualifiers, + multiInstancePropertyQualifiers, + [{ + attribute: InitTypeQualifierAttribute, + value: proto.initType, + }], + )); + } + + private static findInjectObjectPrototype(proto: EggProtoInfo, injectObject: InjectObject | InjectConstructor): EggPrototype { + const propertyQualifiers = QualifierUtil.getProperQualifiers(proto.clazz, injectObject.refName); + try { + return InjectObjectPrototypeFinder.tryFindDefaultPrototype(proto, injectObject); + } catch (e) { + if (!(e instanceof MultiPrototypeFound && !propertyQualifiers.find(t => t.attribute === InitTypeQualifierAttribute))) { + throw e; + } + } + try { + return InjectObjectPrototypeFinder.tryFindContextPrototype(proto, injectObject); + } catch (e) { + if (!(e instanceof EggPrototypeNotFound)) { + throw e; + } + } + return InjectObjectPrototypeFinder.tryFindSelfInitTypePrototype(proto, injectObject); + } + + static findInjectObjectPrototypes(targetProto: EggProtoInfo) { + const injectObjectProtos: Array = []; + for (const injectObject of targetProto.injectObjects) { + const propertyQualifiers = QualifierUtil.getProperQualifiers(targetProto.clazz, injectObject.refName); + try { + const proto = InjectObjectPrototypeFinder.findInjectObjectPrototype(targetProto, injectObject); + let injectObjectProto: InjectObjectProto | InjectConstructorProto; + if (targetProto.injectType === InjectType.PROPERTY) { + injectObjectProto = { + refName: injectObject.refName, + objName: injectObject.objName, + qualifiers: propertyQualifiers, + proto, + }; + } else { + injectObjectProto = { + refIndex: (injectObject as InjectConstructor).refIndex, + refName: injectObject.refName, + objName: injectObject.objName, + qualifiers: propertyQualifiers, + proto, + }; + } + if (injectObject.optional) { + injectObject.optional = true; + } + injectObjectProtos.push(injectObjectProto); + } catch (e) { + if (e instanceof EggPrototypeNotFound && injectObject.optional) { + continue; + } + throw e; + } + } + + return injectObjectProtos; + } +} diff --git a/core/metadata/src/model/ModuleDescriptor.ts b/core/metadata/src/model/ModuleDescriptor.ts index 9e3d54aa..bb26130a 100644 --- a/core/metadata/src/model/ModuleDescriptor.ts +++ b/core/metadata/src/model/ModuleDescriptor.ts @@ -11,6 +11,7 @@ export interface ModuleDescriptor { optional?: boolean; clazzList: EggProtoImplClass[]; multiInstanceClazzList: EggProtoImplClass[]; + innerObjectClazzList: EggProtoImplClass[]; protos: ProtoDescriptor[]; } diff --git a/core/metadata/src/model/ProtoDescriptorHelper.ts b/core/metadata/src/model/ProtoDescriptorHelper.ts index ff8e0d4f..cbc3587e 100644 --- a/core/metadata/src/model/ProtoDescriptorHelper.ts +++ b/core/metadata/src/model/ProtoDescriptorHelper.ts @@ -1,3 +1,4 @@ +import assert from 'node:assert'; import { EggMultiInstancePrototypeInfo, PrototypeUtil, @@ -5,16 +6,17 @@ import { } from '@eggjs/core-decorator'; import { EggProtoImplClass, - InitTypeQualifierAttribute, InjectObjectDescriptor, + InitTypeQualifierAttribute, + InjectObjectDescriptor, LoadUnitNameQualifierAttribute, ObjectInitTypeLike, ProtoDescriptor, QualifierInfo, AccessLevel, - MultiInstancePrototypeGetObjectsContext, MultiInstanceType, + CreateProtoDescriptorContext, + CreateMultiInstanceProtoDescriptorContext, } from '@eggjs/tegg-types'; -import assert from 'node:assert'; import { ProtoSelectorContext } from './graph/ProtoSelector'; import { ClassProtoDescriptor } from './ProtoDescriptor/ClassProtoDescriptor'; @@ -38,61 +40,41 @@ export class ProtoDescriptorHelper { return res; } - static createByMultiInstanceClazz(clazz: EggProtoImplClass, options: { - defineModuleName: string; - defineUnitPath: string; - instanceModuleName: string; - instanceDefineUnitPath: string; - }): ProtoDescriptor[] { + static createByMultiInstanceClazz(clazz: EggProtoImplClass, ctx: CreateMultiInstanceProtoDescriptorContext): ProtoDescriptor[] { assert(PrototypeUtil.isEggMultiInstancePrototype(clazz), `clazz ${clazz.name} is not MultiInstancePrototype`); const type = PrototypeUtil.getEggMultiInstancePrototypeType(clazz); if (type === MultiInstanceType.DYNAMIC) { - return ProtoDescriptorHelper.createByDynamicMultiInstanceClazz(clazz, options); + return ProtoDescriptorHelper.createByDynamicMultiInstanceClazz(clazz, ctx); } else if (type === MultiInstanceType.STATIC) { // static multi instance proto create only in self module - if (options.defineModuleName === options.instanceModuleName) { - return ProtoDescriptorHelper.createByStaticMultiInstanceClazz(clazz, options); + if (ctx.moduleName === ctx.defineModuleName) { + return ProtoDescriptorHelper.createByStaticMultiInstanceClazz(clazz, ctx); } } return []; } - static createByDynamicMultiInstanceClazz(clazz: EggProtoImplClass, options: { - defineModuleName: string; - defineUnitPath: string; - instanceModuleName: string; - instanceDefineUnitPath: string; - }): ProtoDescriptor[] { + static createByDynamicMultiInstanceClazz(clazz: EggProtoImplClass, ctx: CreateMultiInstanceProtoDescriptorContext): ProtoDescriptor[] { assert(PrototypeUtil.isEggMultiInstancePrototype(clazz), `clazz ${clazz.name} is not MultiInstancePrototype`); const instanceProperty = PrototypeUtil.getDynamicMultiInstanceProperty(clazz, { - moduleName: options.instanceModuleName, - unitPath: options.instanceDefineUnitPath, + moduleName: ctx.moduleName, + unitPath: ctx.unitPath, }); assert(instanceProperty, `not found PrototypeInfo for clazz ${clazz.name}`); - return ProtoDescriptorHelper.#createByMultiInstanceClazz(clazz, instanceProperty, options); + return ProtoDescriptorHelper.#createByMultiInstanceClazz(clazz, instanceProperty, ctx); } - static createByStaticMultiInstanceClazz(clazz: EggProtoImplClass, options: { - defineModuleName: string; - defineUnitPath: string; - instanceModuleName: string; - instanceDefineUnitPath: string; - }): ProtoDescriptor[] { + static createByStaticMultiInstanceClazz(clazz: EggProtoImplClass, ctx: CreateMultiInstanceProtoDescriptorContext): ProtoDescriptor[] { assert(PrototypeUtil.isEggMultiInstancePrototype(clazz), `clazz ${clazz.name} is not MultiInstancePrototype`); const instanceProperty = PrototypeUtil.getStaticMultiInstanceProperty(clazz); assert(instanceProperty, `not found PrototypeInfo for clazz ${clazz.name}`); - return ProtoDescriptorHelper.#createByMultiInstanceClazz(clazz, instanceProperty, options); + return ProtoDescriptorHelper.#createByMultiInstanceClazz(clazz, instanceProperty, ctx); } - static #createByMultiInstanceClazz(clazz: EggProtoImplClass, instanceProperty: EggMultiInstancePrototypeInfo, options: { - defineModuleName: string; - defineUnitPath: string; - instanceModuleName: string; - instanceDefineUnitPath: string; - }): ProtoDescriptor[] { + static #createByMultiInstanceClazz(clazz: EggProtoImplClass, instanceProperty: EggMultiInstancePrototypeInfo, ctx: CreateMultiInstanceProtoDescriptorContext): ProtoDescriptor[] { const res: ProtoDescriptor[] = []; for (const obj of instanceProperty.objects) { @@ -100,7 +82,7 @@ export class ProtoDescriptorHelper { QualifierUtil.getProtoQualifiers(clazz), obj.qualifiers, ); - qualifiers = ProtoDescriptorHelper.addDefaultQualifier(qualifiers, instanceProperty.initType, options.instanceModuleName); + qualifiers = ProtoDescriptorHelper.addDefaultQualifier(qualifiers, instanceProperty.initType, ctx.moduleName); const injectObjects: InjectObjectDescriptor[] = PrototypeUtil.getInjectObjects(clazz) .map(t => { const qualifiers = QualifierUtil.getProperQualifiers(clazz, t.refName); @@ -120,10 +102,10 @@ export class ProtoDescriptorHelper { protoImplType: instanceProperty.protoImplType, qualifiers, injectObjects, - instanceModuleName: options.instanceModuleName, - instanceDefineUnitPath: options.instanceDefineUnitPath, - defineModuleName: options.defineModuleName, - defineUnitPath: options.defineUnitPath, + instanceModuleName: ctx.moduleName, + instanceDefineUnitPath: ctx.unitPath, + defineModuleName: ctx.defineModuleName, + defineUnitPath: ctx.defineUnitPath, clazz, properQualifiers: obj.properQualifiers || {}, })); @@ -131,7 +113,7 @@ export class ProtoDescriptorHelper { return res; } - static createByInstanceClazz(clazz: EggProtoImplClass, ctx: MultiInstancePrototypeGetObjectsContext): ProtoDescriptor { + static createByInstanceClazz(clazz: EggProtoImplClass, ctx: CreateProtoDescriptorContext): ProtoDescriptor { assert(PrototypeUtil.isEggPrototype(clazz), `clazz ${clazz.name} is not EggPrototype`); assert(!PrototypeUtil.isEggMultiInstancePrototype(clazz), `clazz ${clazz.name} is not Prototype`); @@ -156,8 +138,8 @@ export class ProtoDescriptorHelper { injectObjects, instanceDefineUnitPath: ctx.unitPath, instanceModuleName: ctx.moduleName, - defineUnitPath: ctx.unitPath, - defineModuleName: ctx.moduleName, + defineUnitPath: ctx.defineUnitPath || ctx.unitPath, + defineModuleName: ctx.defineModuleName || ctx.moduleName, clazz, properQualifiers: {}, }); diff --git a/core/metadata/src/model/graph/GlobalGraph.ts b/core/metadata/src/model/graph/GlobalGraph.ts index 4dd412e3..5e3a48ec 100644 --- a/core/metadata/src/model/graph/GlobalGraph.ts +++ b/core/metadata/src/model/graph/GlobalGraph.ts @@ -1,18 +1,12 @@ import { Graph, GraphNode, ModuleReference } from '@eggjs/tegg-common-util'; -import { - InitTypeQualifierAttribute, - InjectObjectDescriptor, LoadUnitNameQualifierAttribute, - ObjectInitType, - ProtoDescriptor, - QualifierInfo, -} from '@eggjs/tegg-types'; -import { ModuleDependencyMeta, GlobalModuleNode } from './GlobalModuleNode'; -import { ProtoDependencyMeta, ProtoNode } from './ProtoNode'; +import { InjectObjectDescriptor, ProtoDescriptor } from '@eggjs/tegg-types'; +import { GlobalModuleNode, ModuleDependencyMeta } from './GlobalModuleNode'; +import { ProtoDependencyMeta, ProtoGraphNode, ProtoNode } from './ProtoNode'; import { FrameworkErrorFormater } from 'egg-errors'; -import { EggPrototypeNotFound, MultiPrototypeFound } from '../../errors'; +import { EggPrototypeNotFound } from '../../errors'; import { GlobalModuleNodeBuilder } from './GlobalModuleNodeBuilder'; import { ModuleDescriptor } from '../ModuleDescriptor'; -import { QualifierUtil } from '@eggjs/core-decorator'; +import { ProtoGraphUtils } from './ProtoGraphUtils'; export interface GlobalGraphOptions { // TODO next major version refactor to force strict @@ -88,6 +82,12 @@ export class GlobalGraph { } } + addProtoNode(protoNode: ProtoGraphNode) { + if (!this.protoGraph.addVertex(protoNode)) { + throw new Error(`duplicate proto: ${protoNode}`); + } + } + build() { for (const moduleNode of this.moduleGraph.nodes.values()) { for (const protoNode of moduleNode.val.protos) { @@ -140,66 +140,8 @@ export class GlobalGraph { return edge?.val.proto; } - #findDependencyProtoWithDefaultQualifiers(proto: ProtoDescriptor, injectObject: InjectObjectDescriptor, qualifiers: QualifierInfo[]): GraphNode[] { - // TODO perf O(n(proto count)*m(inject count)*n) - const result: GraphNode[] = []; - for (const node of this.protoGraph.nodes.values()) { - if (node.val.selectProto({ - name: injectObject.objName, - qualifiers: QualifierUtil.mergeQualifiers( - injectObject.qualifiers, - qualifiers, - ), - moduleName: proto.instanceModuleName, - })) { - result.push(node); - } - } - return result; - } - - findDependencyProtoNode(proto: ProtoDescriptor, injectObject: InjectObjectDescriptor): GraphNode | undefined { - // 1. find proto with request - // 2. try to add Context qualifier to find - // 3. try to add self init type qualifier to find - const protos = this.#findDependencyProtoWithDefaultQualifiers(proto, injectObject, []); - if (protos.length === 0) { - return; - // throw FrameworkErrorFormater.formatError(new EggPrototypeNotFound(injectObject.objName, proto.instanceModuleName)); - } - if (protos.length === 1) { - return protos[0]; - } - - const protoWithContext = this.#findDependencyProtoWithDefaultQualifiers(proto, injectObject, [{ - attribute: InitTypeQualifierAttribute, - value: ObjectInitType.CONTEXT, - }]); - if (protoWithContext.length === 1) { - return protoWithContext[0]; - } - - const protoWithSelfInitType = this.#findDependencyProtoWithDefaultQualifiers(proto, injectObject, [{ - attribute: InitTypeQualifierAttribute, - value: proto.initType, - }]); - if (protoWithSelfInitType.length === 1) { - return protoWithSelfInitType[0]; - } - const loadUnitQualifier = injectObject.qualifiers.find(t => t.attribute === LoadUnitNameQualifierAttribute); - if (!loadUnitQualifier) { - return this.findDependencyProtoNode(proto, { - ...injectObject, - qualifiers: QualifierUtil.mergeQualifiers( - injectObject.qualifiers, - [{ - attribute: LoadUnitNameQualifierAttribute, - value: proto.instanceModuleName, - }], - ), - }); - } - throw FrameworkErrorFormater.formatError(new MultiPrototypeFound(injectObject.objName, injectObject.qualifiers)); + findDependencyProtoNode(proto: ProtoDescriptor, injectObject: InjectObjectDescriptor): ProtoGraphNode | undefined { + return ProtoGraphUtils.findDependencyProtoNode(this.protoGraph, proto, injectObject); } findModuleNode(moduleName: string) { diff --git a/core/metadata/src/model/graph/GlobalModuleNode.ts b/core/metadata/src/model/graph/GlobalModuleNode.ts index 4805e3ea..19023953 100644 --- a/core/metadata/src/model/graph/GlobalModuleNode.ts +++ b/core/metadata/src/model/graph/GlobalModuleNode.ts @@ -1,6 +1,7 @@ import { GraphNode, GraphNodeObj, EdgeMeta } from '@eggjs/tegg-common-util'; -import { ProtoDependencyMeta, ProtoNode } from './ProtoNode'; -import { ProtoDescriptor } from '@eggjs/tegg-types'; +import { ProtoDependencyMeta, ProtoGraphNode, ProtoNode } from './ProtoNode'; +import { EggProtoImplClass, ProtoDescriptor } from '@eggjs/tegg-types'; +import { ProtoDescriptorHelper } from '../ProtoDescriptorHelper'; export interface GlobalModuleNodeOptions { name: string; @@ -27,7 +28,7 @@ export class GlobalModuleNode implements GraphNodeObj { readonly name: string; readonly unitPath: string; readonly optional: boolean; - readonly protos: GraphNode[]; + readonly protos: ProtoGraphNode[]; constructor(options: GlobalModuleNodeOptions) { this.id = options.unitPath; @@ -37,8 +38,32 @@ export class GlobalModuleNode implements GraphNodeObj { this.protos = []; } + addProtoByClazz(clazz: EggProtoImplClass) { + const proto = ProtoDescriptorHelper.createByInstanceClazz(clazz, { + moduleName: this.name, + unitPath: this.unitPath, + }); + return this.addProto(proto); + } + + addProtoByMultiInstanceClazz(clazz: EggProtoImplClass, defineModuleName: string, defineUnitPath: string) { + const protos = ProtoDescriptorHelper.createByMultiInstanceClazz(clazz, { + moduleName: this.name, + unitPath: this.unitPath, + defineModuleName, + defineUnitPath, + }); + const result: ProtoGraphNode[] = []; + for (const proto of protos) { + result.push(this.addProto(proto)); + } + return result; + } + addProto(proto: ProtoDescriptor) { - this.protos.push(new GraphNode(new ProtoNode(proto))); + const protoGraphNode = new GraphNode(new ProtoNode(proto)); + this.protos.push(protoGraphNode); + return protoGraphNode; } toString() { diff --git a/core/metadata/src/model/graph/GlobalModuleNodeBuilder.ts b/core/metadata/src/model/graph/GlobalModuleNodeBuilder.ts index 1f7787a7..ca36156a 100644 --- a/core/metadata/src/model/graph/GlobalModuleNodeBuilder.ts +++ b/core/metadata/src/model/graph/GlobalModuleNodeBuilder.ts @@ -27,10 +27,10 @@ export class GlobalModuleNodeBuilder { addMultiInstanceClazz(clazz: EggProtoImplClass, defineModuleName: string, defineUnitPath: string) { const protos = ProtoDescriptorHelper.createByMultiInstanceClazz(clazz, { + moduleName: this.name, + unitPath: this.unitPath, defineModuleName, defineUnitPath, - instanceModuleName: this.name, - instanceDefineUnitPath: this.unitPath, }); this.protos.push(...protos); return this; diff --git a/core/metadata/src/model/graph/ProtoGraphUtils.ts b/core/metadata/src/model/graph/ProtoGraphUtils.ts new file mode 100644 index 00000000..b36baa98 --- /dev/null +++ b/core/metadata/src/model/graph/ProtoGraphUtils.ts @@ -0,0 +1,76 @@ +import { + InitTypeQualifierAttribute, + InjectObjectDescriptor, + LoadUnitNameQualifierAttribute, + ObjectInitType, + ProtoDescriptor, + QualifierInfo, +} from '@eggjs/tegg-types'; +import { GraphNode } from '@eggjs/tegg-common-util'; +import { ProtoDependencyMeta, ProtoGraph, ProtoGraphNode, ProtoNode } from './ProtoNode'; +import { FrameworkErrorFormater } from 'egg-errors'; +import { MultiPrototypeFound } from '../../errors'; +import { QualifierUtil } from '@eggjs/core-decorator'; +import { ProtoSelectorContext } from './ProtoSelector'; + +export class ProtoGraphUtils { + static findDependencyProtoNode(graph: ProtoGraph, proto: ProtoDescriptor, injectObject: InjectObjectDescriptor): ProtoGraphNode | undefined { + // 1. find proto with request + // 2. try to add Context qualifier to find + // 3. try to add self init type qualifier to find + const protos = ProtoGraphUtils.#findDependencyProtoWithDefaultQualifiers(graph, proto, injectObject, []); + if (protos.length === 0) { + return; + // throw FrameworkErrorFormater.formatError(new EggPrototypeNotFound(injectObject.objName, proto.instanceModuleName)); + } + if (protos.length === 1) { + return protos[0]; + } + + const protoWithContext = ProtoGraphUtils.#findDependencyProtoWithDefaultQualifiers(graph, proto, injectObject, [{ + attribute: InitTypeQualifierAttribute, + value: ObjectInitType.CONTEXT, + }]); + if (protoWithContext.length === 1) { + return protoWithContext[0]; + } + + const protoWithSelfInitType = ProtoGraphUtils.#findDependencyProtoWithDefaultQualifiers(graph, proto, injectObject, [{ + attribute: InitTypeQualifierAttribute, + value: proto.initType, + }]); + if (protoWithSelfInitType.length === 1) { + return protoWithSelfInitType[0]; + } + const loadUnitQualifier = injectObject.qualifiers.find(t => t.attribute === LoadUnitNameQualifierAttribute); + if (!loadUnitQualifier) { + return ProtoGraphUtils.findDependencyProtoNode(graph, proto, { + ...injectObject, + qualifiers: QualifierUtil.mergeQualifiers( + injectObject.qualifiers, + [{ + attribute: LoadUnitNameQualifierAttribute, + value: proto.instanceModuleName, + }], + ), + }); + } + throw FrameworkErrorFormater.formatError(new MultiPrototypeFound(injectObject.objName, injectObject.qualifiers)); + } + + static #findDependencyProtoWithDefaultQualifiers(graph: ProtoGraph, proto: ProtoDescriptor, injectObject: InjectObjectDescriptor, qualifiers: QualifierInfo[]): GraphNode[] { + // TODO perf O(n(proto count)*m(inject count)*n) + const result: GraphNode[] = []; + for (const node of graph.nodes.values()) { + const ctx: ProtoSelectorContext = { + name: injectObject.objName, + qualifiers: QualifierUtil.mergeQualifiers(injectObject.qualifiers, qualifiers), + moduleName: proto.instanceModuleName, + }; + if (node.val.selectProto(ctx)) { + result.push(node); + } + } + return result; + } +} diff --git a/core/metadata/src/model/graph/ProtoNode.ts b/core/metadata/src/model/graph/ProtoNode.ts index 09033ef2..3671b0ba 100644 --- a/core/metadata/src/model/graph/ProtoNode.ts +++ b/core/metadata/src/model/graph/ProtoNode.ts @@ -1,6 +1,6 @@ import { GraphNodeObj, ProtoDescriptor } from '@eggjs/tegg-types'; import { ProtoSelectorContext } from './ProtoSelector'; -import { EdgeMeta } from '@eggjs/tegg-common-util'; +import { EdgeMeta, Graph, GraphNode } from '@eggjs/tegg-common-util'; import { ProtoDescriptorHelper } from '../ProtoDescriptorHelper'; export class ProtoDependencyMeta implements EdgeMeta { @@ -50,3 +50,6 @@ export class ProtoNode implements GraphNodeObj { return id.join('@'); } } + +export type ProtoGraph = Graph; +export type ProtoGraphNode = GraphNode; diff --git a/core/runtime/index.ts b/core/runtime/index.ts index 4c941f91..5eea7c4b 100644 --- a/core/runtime/index.ts +++ b/core/runtime/index.ts @@ -13,3 +13,4 @@ export * from './src/model/ContextHandler'; import './src/impl/EggAlwaysNewObjectContainer'; import './src/impl/ModuleLoadUnitInstance'; +import './src/impl/EggInnerobjectImpl'; diff --git a/core/runtime/src/impl/EggInnerobjectImpl.ts b/core/runtime/src/impl/EggInnerobjectImpl.ts new file mode 100644 index 00000000..987e5e31 --- /dev/null +++ b/core/runtime/src/impl/EggInnerobjectImpl.ts @@ -0,0 +1,192 @@ +import { EggInnerObjectPrototypeImpl, LoadUnitFactory } from '@eggjs/tegg-metadata'; +import { + EggObject, + EggObjectLifecycle, + EggObjectLifeCycleContext, + EggObjectName, + EggObjectStatus, + EggPrototype, + InjectType, + LifecycleHookName, + ObjectInfo, + ObjectInitType, + QualifierInfo, +} from '@eggjs/tegg-types'; +import { IdenticalUtil } from '@eggjs/tegg-lifecycle'; +import { EggObjectLifecycleUtil } from '../model/EggObject'; +import { EggContainerFactory } from '../factory/EggContainerFactory'; +import { EggObjectUtil } from './EggObjectUtil'; +import { ContextHandler } from '../model/ContextHandler'; +import { EggObjectFactory } from '../factory/EggObjectFactory'; + +export default class EggInnerObjectImpl implements EggObject { + private _obj: object; + private status: EggObjectStatus = EggObjectStatus.PENDING; + + readonly proto: EggPrototype; + readonly name: EggObjectName; + readonly id: string; + + constructor(name: EggObjectName, proto: EggPrototype) { + this.name = name; + this.proto = proto; + const ctx = ContextHandler.getContext(); + this.id = IdenticalUtil.createObjectId(this.proto.id, ctx?.id); + } + + async initWithInjectProperty(ctx: EggObjectLifeCycleContext) { + // 1. create obj + // 2. call obj lifecycle preCreate + // 3. inject deps + // 4. call obj lifecycle postCreate + // 5. success create + try { + this._obj = this.proto.constructEggObject(); + + // global hook + await EggObjectLifecycleUtil.objectPreCreate(ctx, this); + // self hook + await this.callObjectLifecycle('postConstruct', ctx); + + await this.callObjectLifecycle('preInject', ctx); + await Promise.all(this.proto.injectObjects.map(async injectObject => { + const proto = injectObject.proto; + const loadUnit = LoadUnitFactory.getLoadUnitById(proto.loadUnitId); + if (!loadUnit) { + throw new Error(`can not find load unit: ${proto.loadUnitId}`); + } + if (this.proto.initType !== ObjectInitType.CONTEXT && injectObject.proto.initType === ObjectInitType.CONTEXT) { + this.injectProperty(injectObject.refName, EggObjectUtil.contextEggObjectGetProperty(proto, injectObject.objName)); + } else { + const injectObj = await EggContainerFactory.getOrCreateEggObject(proto, injectObject.objName); + this.injectProperty(injectObject.refName, EggObjectUtil.eggObjectGetProperty(injectObj)); + } + })); + + // global hook + await EggObjectLifecycleUtil.objectPostCreate(ctx, this); + + // self hook + await this.callObjectLifecycle('postInject', ctx); + + await this.callObjectLifecycle('init', ctx); + + this.status = EggObjectStatus.READY; + } catch (e) { + this.status = EggObjectStatus.ERROR; + throw e; + } + } + + async initWithInjectConstructor(ctx: EggObjectLifeCycleContext) { + // 1. create inject deps + // 2. create obj + // 3. call obj lifecycle preCreate + // 4. call obj lifecycle postCreate + // 5. success create + try { + const constructArgs: any[] = await Promise.all(this.proto.injectObjects!.map(async injectObject => { + const proto = injectObject.proto; + const loadUnit = LoadUnitFactory.getLoadUnitById(proto.loadUnitId); + if (!loadUnit) { + throw new Error(`can not find load unit: ${proto.loadUnitId}`); + } + if (this.proto.initType !== ObjectInitType.CONTEXT && injectObject.proto.initType === ObjectInitType.CONTEXT) { + return EggObjectUtil.contextEggObjectProxy(proto, injectObject.objName); + } + const injectObj = await EggContainerFactory.getOrCreateEggObject(proto, injectObject.objName); + return EggObjectUtil.eggObjectProxy(injectObj); + })); + if (typeof this.proto.multiInstanceConstructorIndex !== 'undefined') { + const qualifiers = this.proto.multiInstanceConstructorAttributes + ?.map(t => { + return { + attribute: t, + value: this.proto.getQualifier(t), + } as QualifierInfo; + }) + ?.filter(t => typeof t.value !== 'undefined') + ?? []; + const objInfo: ObjectInfo = { + name: this.proto.name, + qualifiers, + }; + constructArgs.splice(this.proto.multiInstanceConstructorIndex, 0, objInfo); + } + + this._obj = this.proto.constructEggObject(...constructArgs); + + // global hook + await EggObjectLifecycleUtil.objectPreCreate(ctx, this); + // self hook + await this.callObjectLifecycle('postConstruct', ctx); + + await this.callObjectLifecycle('preInject', ctx); + + // global hook + await EggObjectLifecycleUtil.objectPostCreate(ctx, this); + + // self hook + await this.callObjectLifecycle('postInject', ctx); + + await this.callObjectLifecycle('init', ctx); + + this.status = EggObjectStatus.READY; + } catch (e) { + this.status = EggObjectStatus.ERROR; + throw e; + } + } + + async init(ctx: EggObjectLifeCycleContext) { + if (this.proto.injectType === InjectType.CONSTRUCTOR) { + await this.initWithInjectConstructor(ctx); + } else { + await this.initWithInjectProperty(ctx); + } + } + + async destroy(ctx: EggObjectLifeCycleContext) { + if (this.status === EggObjectStatus.READY) { + this.status = EggObjectStatus.DESTROYING; + // global hook + await EggObjectLifecycleUtil.objectPreDestroy(ctx, this); + + // self hook + await this.callObjectLifecycle('preDestroy', ctx); + + await this.callObjectLifecycle('destroy', ctx); + + this.status = EggObjectStatus.DESTROYED; + } + } + + injectProperty(name: EggObjectName, descriptor: PropertyDescriptor) { + Reflect.defineProperty(this._obj, name, descriptor); + } + + get obj() { + return this._obj; + } + + get isReady() { + return this.status === EggObjectStatus.READY; + } + + private async callObjectLifecycle(hookName: LifecycleHookName, ctx: EggObjectLifeCycleContext) { + const objLifecycleHook = this._obj as EggObjectLifecycle; + const lifecycleHook = EggObjectLifecycleUtil.getLifecycleHook(hookName, this.proto); + if (lifecycleHook) { + await objLifecycleHook[lifecycleHook]?.(ctx, this); + return; + } + } + + static async createObject(name: EggObjectName, proto: EggPrototype, lifecycleContext: EggObjectLifeCycleContext): Promise { + const obj = new EggInnerObjectImpl(name, proto); + await obj.init(lifecycleContext); + return obj; + } +} + +EggObjectFactory.registerEggObjectCreateMethod(EggInnerObjectPrototypeImpl, EggInnerObjectImpl.createObject); diff --git a/core/runtime/src/impl/EggObjectImpl.ts b/core/runtime/src/impl/EggObjectImpl.ts index ad197e27..b20c940b 100644 --- a/core/runtime/src/impl/EggObjectImpl.ts +++ b/core/runtime/src/impl/EggObjectImpl.ts @@ -4,7 +4,9 @@ import type { EggObjectLifecycle, EggObjectLifeCycleContext, EggObjectName, - EggPrototype, ObjectInfo, QualifierInfo, + EggPrototype, + ObjectInfo, + QualifierInfo, } from '@eggjs/tegg-types'; import { EggObjectStatus, InjectType, ObjectInitType } from '@eggjs/tegg-types'; import { IdenticalUtil } from '@eggjs/tegg-lifecycle'; diff --git a/core/standalone-decorator/index.ts b/core/standalone-decorator/index.ts index 29c353b5..6ef063bc 100644 --- a/core/standalone-decorator/index.ts +++ b/core/standalone-decorator/index.ts @@ -1,3 +1,4 @@ export * from './src/typing'; export * from './src/util/StandaloneUtil'; export * from './src/decorator/Runner'; +export * from './src/event/EventHandler'; diff --git a/core/standalone-decorator/package.json b/core/standalone-decorator/package.json index 0f1fe02e..112664bb 100644 --- a/core/standalone-decorator/package.json +++ b/core/standalone-decorator/package.json @@ -42,13 +42,17 @@ "publishConfig": { "access": "public" }, + "peerDependencies": { + "@eggjs/tegg": "^3" + }, "devDependencies": { "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", "mocha": "^10.2.0", "ts-node": "^10.9.1", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "@eggjs/tegg": "^3.57.12" }, "gitHead": "b49e4c70e7f09a073e989493b995f8dd3ce482e9" } diff --git a/core/standalone-decorator/src/event/EventHandler.ts b/core/standalone-decorator/src/event/EventHandler.ts new file mode 100644 index 00000000..1d0db766 --- /dev/null +++ b/core/standalone-decorator/src/event/EventHandler.ts @@ -0,0 +1,20 @@ +import { type EggProtoImplClass, ImplDecorator, SingletonProtoParams } from '@eggjs/tegg-types'; +import { QualifierImplDecoratorUtil, SingletonProto } from '@eggjs/tegg'; + +export abstract class AbstractEventHandler { + abstract handleEvent(event: E): Promise; +} + +export const EVENT_HANDLER_ATTRIBUTE = Symbol('EVENT_HANDLER_ATTRIBUTE'); + +export type EventType = Record; + +export const EventHandler: ImplDecorator = + QualifierImplDecoratorUtil.generatorDecorator(AbstractEventHandler, EVENT_HANDLER_ATTRIBUTE); + +export const EventHandlerProto = (type: EventType[keyof EventType], params?: SingletonProtoParams) => { + return (clazz: EggProtoImplClass) => { + EventHandler(type)(clazz); + SingletonProto(params)(clazz); + }; +}; diff --git a/core/test-util/StandaloneTestUtil.ts b/core/test-util/StandaloneTestUtil.ts new file mode 100644 index 00000000..8e6524a3 --- /dev/null +++ b/core/test-util/StandaloneTestUtil.ts @@ -0,0 +1,76 @@ +import { createServer, IncomingMessage, OutgoingHttpHeaders, Server, ServerOptions, ServerResponse } from 'node:http'; +import { pipeline } from 'node:stream'; +import { Headers, BodyInit, Request, Response } from 'undici'; +import { FetchEvent } from '@eggjs/tegg-types/standalone'; + +export type FetchEventListener = (event: FetchEvent) => Promise; + +export interface StartHTTPServerOptions extends ServerOptions { + listener: FetchEventListener; +} + +export class StandaloneTestUtil { + static #buildRequest(req: IncomingMessage): Request { + const origin = `http://${req.headers.host ?? 'localhost'}`; + const url = new URL(req.url ?? '', origin); + + const body: BodyInit | null = req.method === 'GET' || req.method === 'HEAD' ? null : req; + + req.headers.host = url.host; + + const headers = new Headers(); + for (const [ name, values ] of Object.entries(req.headers)) { + if (Array.isArray(values)) { + for (const value of values) { + headers.append(name, value); + } + } else if (values !== undefined) { + headers.append(name, values); + } + } + + return new Request(url, { + method: req.method, + headers, + body, + duplex: body ? 'half' : undefined, + }); + } + + static #createHTTPServerListener(listener: FetchEventListener) { + return async (req: IncomingMessage, res: ServerResponse) => { + const request = StandaloneTestUtil.#buildRequest(req); + // TODO currently fake FetchEvent + const event: any = new Event('fetch'); + event.request = request; + const response = await listener(event); + + const headers: OutgoingHttpHeaders = {}; + for (const [ key, value ] of response.headers) { + headers[key.toLowerCase()] = value; + } + + res.writeHead(response.status, headers); + + if (!response.body) { + res.end(); + return; + } + pipeline(response.body, res, e => { + if (e) { + console.error(`pipeline writing response error for url ${response.url}`, e); + res.end(); + } + }); + }; + } + + static startHTTPServer(host: string, port: number, { listener, ...options }: StartHTTPServerOptions) { + const serverListener = StandaloneTestUtil.#createHTTPServerListener(listener); + const server = createServer(options ?? {}, serverListener); + + return new Promise(resolve => { + server.listen(port, host, () => resolve(server)); + }); + } +} diff --git a/core/test-util/package.json b/core/test-util/package.json index b448d152..59f0836c 100644 --- a/core/test-util/package.json +++ b/core/test-util/package.json @@ -41,7 +41,8 @@ "@eggjs/tegg-metadata": "^3.57.14", "@eggjs/tegg-runtime": "^3.57.14", "globby": "^11.1.0", - "mm": "^3.2.1" + "mm": "^3.2.1", + "undici": "^5.26.5" }, "devDependencies": { "@types/mocha": "^10.0.1", diff --git a/core/types/core-decorator/EggLifecycleProto.ts b/core/types/core-decorator/EggLifecycleProto.ts new file mode 100644 index 00000000..947ca0ea --- /dev/null +++ b/core/types/core-decorator/EggLifecycleProto.ts @@ -0,0 +1,7 @@ +import { InnerObjectProtoParams } from './InnerObjectProto'; + +export interface CommonEggLifecycleProtoParams extends InnerObjectProtoParams { + type: 'LoadUnit' | 'LoadUnitInstance' | 'EggObject' | 'EggPrototype' | 'EggContext' | string; +} + +export type EggLifecycleProtoParams = Omit; diff --git a/core/types/core-decorator/InnerObjectProto.ts b/core/types/core-decorator/InnerObjectProto.ts new file mode 100644 index 00000000..b96c65c2 --- /dev/null +++ b/core/types/core-decorator/InnerObjectProto.ts @@ -0,0 +1,3 @@ +import { SingletonProtoParams } from './SingletonProto'; + +export type InnerObjectProtoParams = SingletonProtoParams; diff --git a/core/types/core-decorator/Prototype.ts b/core/types/core-decorator/Prototype.ts index 1250098b..bbc0ea93 100644 --- a/core/types/core-decorator/Prototype.ts +++ b/core/types/core-decorator/Prototype.ts @@ -9,3 +9,4 @@ export interface PrototypeParams { } export const DEFAULT_PROTO_IMPL_TYPE = 'DEFAULT'; +export const EGG_INNER_OBJECT_PROTO_IMPL_TYPE = 'EGG_INNER_OBJECT_PROTOTYPE'; diff --git a/core/types/core-decorator/index.ts b/core/types/core-decorator/index.ts index d0d366e1..1ee715ce 100644 --- a/core/types/core-decorator/index.ts +++ b/core/types/core-decorator/index.ts @@ -5,6 +5,7 @@ export * from './enum/Qualifier'; export * from './enum/InjectType'; export * from './enum/MultiInstanceType'; +export * from './model/EggLifecycleInfo'; export * from './model/EggPrototypeInfo'; export * from './model/InjectObjectInfo'; export * from './model/InjectConstructorInfo'; @@ -12,7 +13,9 @@ export * from './model/QualifierInfo'; export * from './model/EggMultiInstancePrototypeInfo'; export * from './ContextProto'; +export * from './EggLifecycleProto'; export * from './Inject'; +export * from './InnerObjectProto'; export * from './Metadata'; export * from './MultiInstanceProto'; export * from './Prototype'; diff --git a/core/types/core-decorator/model/EggLifecycleInfo.ts b/core/types/core-decorator/model/EggLifecycleInfo.ts new file mode 100644 index 00000000..4829600b --- /dev/null +++ b/core/types/core-decorator/model/EggLifecycleInfo.ts @@ -0,0 +1,3 @@ +export interface EggLifecycleInfo { + type: string; +} diff --git a/core/types/metadata/model/ProtoDescriptor.ts b/core/types/metadata/model/ProtoDescriptor.ts index 218ab105..75a2108c 100644 --- a/core/types/metadata/model/ProtoDescriptor.ts +++ b/core/types/metadata/model/ProtoDescriptor.ts @@ -1,4 +1,10 @@ -import { AccessLevel, EggPrototypeInfo, ObjectInitTypeLike, QualifierInfo } from '../../core-decorator'; +import { + AccessLevel, + EggProtoImplClass, + EggPrototypeInfo, + ObjectInitTypeLike, + QualifierInfo, +} from '../../core-decorator'; import { ProtoDescriptorType } from '../enum/ProtoDescriptorType'; export type ProtoDescriptorTypeLike = ProtoDescriptorType | string; @@ -29,3 +35,23 @@ export interface ProtoDescriptor extends EggPrototypeInfo { // test is the same proto equal(protoDescriptor: ProtoDescriptor): boolean; } + +export interface CreateProtoDescriptorContext { + moduleName: string; + unitPath: string; + defineModuleName?: string; + defineUnitPath?: string; +} + +export interface CreateMultiInstanceProtoDescriptorContext { + moduleName: string; + unitPath: string; + defineModuleName: string; + defineUnitPath: string; +} + +export interface PrototypeClassDefinition { + clazz: EggProtoImplClass; + defineModuleName: string; + defineUnitPath: string; +} diff --git a/core/types/standalone/ServiceWorkerContext.ts b/core/types/standalone/ServiceWorkerContext.ts new file mode 100644 index 00000000..7ecf046c --- /dev/null +++ b/core/types/standalone/ServiceWorkerContext.ts @@ -0,0 +1,16 @@ +import { FetchEvent } from './fetch'; + +export interface ServiceWorkerContextInit { + event: T; +} + +export interface ServiceWorkerContext { + event: Event; + get response(): Response | undefined; + set response(response: Response); + + get body(): any | undefined; + set body(body: any); +} + +export type ServiceWorkerFetchContext = ServiceWorkerContext; diff --git a/core/types/standalone/fetch.ts b/core/types/standalone/fetch.ts new file mode 100644 index 00000000..cd0027bf --- /dev/null +++ b/core/types/standalone/fetch.ts @@ -0,0 +1,5 @@ +export interface FetchEvent extends Event { + request: Request; + waitUntil(f: Promise): void; + respondWith(r: Response | PromiseLike): void; +} diff --git a/core/types/standalone/index.ts b/core/types/standalone/index.ts new file mode 100644 index 00000000..c25290f7 --- /dev/null +++ b/core/types/standalone/index.ts @@ -0,0 +1,2 @@ +export * from './fetch'; +export * from './ServiceWorkerContext'; diff --git a/plugin/dal/lib/TransactionPrototypeHook.ts b/plugin/dal/lib/TransactionPrototypeHook.ts index 0ca1fe5d..1e06bf37 100644 --- a/plugin/dal/lib/TransactionPrototypeHook.ts +++ b/plugin/dal/lib/TransactionPrototypeHook.ts @@ -8,9 +8,9 @@ import { MysqlDataSourceManager } from './MysqlDataSourceManager'; export class TransactionPrototypeHook implements LifecycleHook { private readonly moduleConfigs: Record; - private readonly logger: Logger; + private readonly logger?: Logger; - constructor(moduleConfigs: Record, logger: Logger) { + constructor(moduleConfigs: Record, logger?: Logger) { this.moduleConfigs = moduleConfigs; this.logger = logger; } @@ -30,7 +30,7 @@ export class TransactionPrototypeHook implements LifecycleHook=14.0.0" + }, + "author": "killagu ", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@eggjs/router": "^3.0.6", + "path-to-regexp": "^1.8.0", + "type-is": "^1.6.18" + }, + "peerDependencies": { + "@eggjs/tegg": "^3", + "@eggjs/tegg-service-worker": "^3" + }, + "devDependencies": { + "@eggjs/tegg": "^3.57.12", + "@eggjs/tegg-service-worker": "^3.57.12", + "@eggjs/module-test-util": "^3.57.12", + "@types/mocha": "^10.0.1", + "@types/node": "^20.2.4", + "@types/type-is": "^1.6.0", + "cross-env": "^7.0.3", + "mm": "^3.2.1", + "mocha": "^10.2.0", + "supertest": "^7.1.1", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + } +} diff --git a/standalone/controller/src/ControllerMetadataManager.ts b/standalone/controller/src/ControllerMetadataManager.ts new file mode 100644 index 00000000..f68fe66d --- /dev/null +++ b/standalone/controller/src/ControllerMetadataManager.ts @@ -0,0 +1,26 @@ +import { ControllerMetadata, ControllerTypeLike, InnerObjectProto } from '@eggjs/tegg'; +import { MapUtil } from '@eggjs/tegg/helper'; + +@InnerObjectProto() +export class ControllerMetadataManager { + private readonly controllers = new Map(); + + addController(metadata: ControllerMetadata) { + const typeControllers = MapUtil.getOrStore(this.controllers, metadata.type, []); + // 1.check controller name + // 2.check proto name + const sameNameControllers = typeControllers.filter(c => c.controllerName === metadata.controllerName); + if (sameNameControllers.length) { + throw new Error(`duplicate controller name ${metadata.controllerName}`); + } + const sameProtoControllers = typeControllers.filter(c => c.protoName === metadata.protoName); + if (sameProtoControllers.length) { + throw new Error(`duplicate proto name ${String(metadata.protoName)}`); + } + typeControllers.push(metadata); + } + + clear() { + this.controllers.clear(); + } +} diff --git a/standalone/controller/src/ControllerRegister.ts b/standalone/controller/src/ControllerRegister.ts new file mode 100644 index 00000000..8bc3bde7 --- /dev/null +++ b/standalone/controller/src/ControllerRegister.ts @@ -0,0 +1,5 @@ +import { RootProtoManager } from './RootProtoManager'; + +export interface ControllerRegister { + register(rootProtoManager: RootProtoManager): Promise; +} diff --git a/standalone/controller/src/ControllerRegisterFactory.ts b/standalone/controller/src/ControllerRegisterFactory.ts new file mode 100644 index 00000000..8b80beed --- /dev/null +++ b/standalone/controller/src/ControllerRegisterFactory.ts @@ -0,0 +1,26 @@ +import { ControllerMetadata, ControllerTypeLike, InnerObjectProto } from '@eggjs/tegg'; +import { EggPrototype } from '@eggjs/tegg/helper'; +import { ControllerRegister } from './ControllerRegister'; + +export type RegisterCreator = (proto: EggPrototype, controllerMeta: ControllerMetadata) => ControllerRegister; + +@InnerObjectProto() +export class ControllerRegisterFactory { + #registerCreatorMap: Map; + + constructor() { + this.#registerCreatorMap = new Map(); + } + + registerControllerRegister(type: ControllerTypeLike, creator: RegisterCreator) { + this.#registerCreatorMap.set(type, creator); + } + + getControllerRegister(proto: EggPrototype, metadata: ControllerMetadata): ControllerRegister | undefined { + const creator = this.#registerCreatorMap.get(metadata.type); + if (!creator) { + return; + } + return creator(proto, metadata); + } +} diff --git a/standalone/controller/src/RootProtoManager.ts b/standalone/controller/src/RootProtoManager.ts new file mode 100644 index 00000000..8c90cda3 --- /dev/null +++ b/standalone/controller/src/RootProtoManager.ts @@ -0,0 +1,39 @@ +import { EggPrototype, MapUtil } from '@eggjs/tegg/helper'; +import { AccessLevel, EggContext, InnerObjectProto } from '@eggjs/tegg'; + +export type GetRootProtoCallback = (ctx: EggContext) => EggPrototype | undefined; + +@InnerObjectProto({ accessLevel: AccessLevel.PUBLIC }) +export class RootProtoManager { + // + protoMap: Map = new Map(); + + registerRootProto(method: string, cb: GetRootProtoCallback, host?: string) { + host = host || ''; + const cbList = MapUtil.getOrStore(this.protoMap, method + host, []); + cbList.push(cb); + } + + getRootProto(ctx: EggContext): EggPrototype | undefined { + const hostCbList = this.protoMap.get(ctx.method + ctx.host); + if (hostCbList) { + for (const cb of hostCbList) { + const proto = cb(ctx); + if (proto) { + return proto; + } + } + } + + const cbList = this.protoMap.get(ctx.method); + if (!cbList) { + return; + } + for (const cb of cbList) { + const proto = cb(ctx); + if (proto) { + return proto; + } + } + } +} diff --git a/standalone/controller/src/ServiceWorkerContext.ts b/standalone/controller/src/ServiceWorkerContext.ts new file mode 100644 index 00000000..8d1905a0 --- /dev/null +++ b/standalone/controller/src/ServiceWorkerContext.ts @@ -0,0 +1,21 @@ +import { ServiceWorkerContext, ServiceWorkerContextInit } from '@eggjs/tegg-types/standalone'; + +export abstract class BaseServiceWorkerContextImpl implements ServiceWorkerContext { + event: Event; + #response: Response; + + constructor(init: ServiceWorkerContextInit) { + this.event = init.event; + } + + get response(): Response | undefined { + return this.#response; + } + + set response(response: Response) { + this.#response = response; + } + + abstract get body(): any | undefined; + abstract set body(body: any); +} diff --git a/standalone/controller/src/hook/ControllerLoadUnitHook.ts b/standalone/controller/src/hook/ControllerLoadUnitHook.ts new file mode 100644 index 00000000..5e7172fa --- /dev/null +++ b/standalone/controller/src/hook/ControllerLoadUnitHook.ts @@ -0,0 +1,43 @@ +import { LifecycleHook, LifecyclePostInject } from '@eggjs/tegg-lifecycle'; +import { EggPrototype, LoadUnit, LoadUnitLifecycleContext } from '@eggjs/tegg/helper'; +import { CONTROLLER_META_DATA, ControllerMetadata, ControllerType, Inject, LoadUnitLifecycleProto } from '@eggjs/tegg'; +import { ControllerRegisterFactory } from '../ControllerRegisterFactory'; +import { RootProtoManager } from '../RootProtoManager'; +import { ControllerMetadataManager } from '../ControllerMetadataManager'; +import { FetchRouter } from '../impl/http/FetchRouter'; +import { HTTPControllerRegister } from '../impl/http/HTTPControllerRegister'; + +@LoadUnitLifecycleProto() +export class ControllerLoadUnitHook implements LifecycleHook { + @Inject() + private readonly controllerRegisterFactory: ControllerRegisterFactory; + @Inject() + private readonly rootProtoManager: RootProtoManager; + @Inject() + private readonly controllerMetadataManager: ControllerMetadataManager; + @Inject() + private readonly fetchRouter: FetchRouter; + + @LifecyclePostInject() + registerControllerRegister() { + this.controllerRegisterFactory.registerControllerRegister(ControllerType.HTTP, (proto: EggPrototype, controllerMeta: ControllerMetadata) => { + return HTTPControllerRegister.create(proto, controllerMeta, this.fetchRouter); + }); + } + + async postCreate(_: LoadUnitLifecycleContext, loadUnit: LoadUnit): Promise { + const iterator = loadUnit.iterateEggPrototype(); + for (const proto of iterator) { + const metadata: ControllerMetadata | undefined = proto.getMetaData(CONTROLLER_META_DATA); + if (!metadata) { + continue; + } + const register = this.controllerRegisterFactory.getControllerRegister(proto, metadata); + if (!register) { + throw new Error(`not find controller implement for ${String(proto.name)} which type is ${metadata.type}`); + } + this.controllerMetadataManager.addController(metadata); + await register.register(this.rootProtoManager); + } + } +} diff --git a/standalone/controller/src/hook/ControllerPrototypeHook.ts b/standalone/controller/src/hook/ControllerPrototypeHook.ts new file mode 100644 index 00000000..8bb588bf --- /dev/null +++ b/standalone/controller/src/hook/ControllerPrototypeHook.ts @@ -0,0 +1,17 @@ +import { EggPrototype, EggPrototypeLifecycleContext } from '@eggjs/tegg-metadata'; +import { + ControllerMetaBuilderFactory, + ControllerMetadataUtil, + EggPrototypeLifecycleProto, + LifecycleHook, +} from '@eggjs/tegg'; + +@EggPrototypeLifecycleProto() +export class ControllerPrototypeHook implements LifecycleHook { + async postCreate(ctx: EggPrototypeLifecycleContext): Promise { + const metadata = ControllerMetaBuilderFactory.build(ctx.clazz); + if (metadata) { + ControllerMetadataUtil.setControllerMetadata(ctx.clazz, metadata); + } + } +} diff --git a/standalone/controller/src/impl/http/FetchEventHandler.ts b/standalone/controller/src/impl/http/FetchEventHandler.ts new file mode 100644 index 00000000..b1f73f1a --- /dev/null +++ b/standalone/controller/src/impl/http/FetchEventHandler.ts @@ -0,0 +1,47 @@ +import { MiddlewareFuncWithRouter } from '@eggjs/router'; +import { FetchEvent } from '@eggjs/tegg-types/standalone'; +import { AccessLevel, Inject, InjectOptional, LifecycleInit, LifecyclePostInject, Logger } from '@eggjs/tegg'; +import { AbstractEventHandler, EventHandlerProto } from '@eggjs/tegg/standalone'; +import { FetchRouter } from './FetchRouter'; +import { ServiceWorkerFetchContext } from './ServiceWorkerFetchContext'; +import { RootProtoManager } from '../../RootProtoManager'; +import { HTTPControllerRegister } from './HTTPControllerRegister'; + +@EventHandlerProto('fetch', { accessLevel: AccessLevel.PUBLIC }) +export class FetchEventHandler extends AbstractEventHandler { + @InjectOptional() + private readonly coreLogger?: Logger; + + @Inject() + private readonly fetchRouter: FetchRouter; + + @Inject() + private readonly rootProtoManager: RootProtoManager; + + #routes: MiddlewareFuncWithRouter; + + @LifecyclePostInject() + initRoutes() { + this.#routes = this.fetchRouter.middleware(); + } + + @LifecycleInit() + doRegister() { + HTTPControllerRegister.instance?.doRegister(this.rootProtoManager); + } + + async handleEvent(event: FetchEvent): Promise { + const ctx = new ServiceWorkerFetchContext({ event }); + try { + await this.#routes(ctx, async () => { /**/ }); + if (ctx.response) { + return ctx.response; + } + + return new Response(null, { status: 404 }); + } catch (e) { + this.coreLogger?.error('handle event failed:', e); + return new Response(e.message, { status: 500 }); + } + } +} diff --git a/standalone/controller/src/impl/http/FetchRouter.ts b/standalone/controller/src/impl/http/FetchRouter.ts new file mode 100644 index 00000000..58608213 --- /dev/null +++ b/standalone/controller/src/impl/http/FetchRouter.ts @@ -0,0 +1,5 @@ +import { KoaRouter } from '@eggjs/router'; +import { AccessLevel, InnerObjectProto } from '@eggjs/tegg'; + +@InnerObjectProto({ accessLevel: AccessLevel.PUBLIC }) +export class FetchRouter extends KoaRouter {} diff --git a/standalone/controller/src/impl/http/HTTPControllerRegister.ts b/standalone/controller/src/impl/http/HTTPControllerRegister.ts new file mode 100644 index 00000000..debc32c7 --- /dev/null +++ b/standalone/controller/src/impl/http/HTTPControllerRegister.ts @@ -0,0 +1,77 @@ +import assert from 'assert'; +import { Router as KoaRouter } from '@eggjs/router'; +import { + CONTROLLER_META_DATA, + ControllerMetadata, + ControllerType, + HTTPControllerMeta, + HTTPMethodMeta, +} from '@eggjs/tegg'; +import { EggPrototype } from '@eggjs/tegg/helper'; +import { ControllerRegister } from '../../ControllerRegister'; +import { HTTPMethodRegister } from './HTTPMethodRegister'; +import { RootProtoManager } from '../../RootProtoManager'; + +export class HTTPControllerRegister implements ControllerRegister { + static instance?: HTTPControllerRegister; + + private readonly router: KoaRouter; + private readonly checkRouters: Map; + private controllerProtos: EggPrototype[] = []; + + static create(proto: EggPrototype, controllerMeta: ControllerMetadata, router: KoaRouter) { + assert(controllerMeta.type === ControllerType.HTTP, 'controller meta type is not HTTP'); + if (!HTTPControllerRegister.instance) { + HTTPControllerRegister.instance = new HTTPControllerRegister(router); + } + HTTPControllerRegister.instance.controllerProtos.push(proto); + return HTTPControllerRegister.instance; + } + + constructor(router: KoaRouter) { + this.router = router; + this.checkRouters = new Map(); + this.checkRouters.set('default', router); + } + + register(): Promise { + // do noting + return Promise.resolve(); + } + + static clean() { + if (this.instance) { + this.instance.controllerProtos = []; + this.instance.checkRouters.clear(); + } + this.instance = undefined; + } + + doRegister(rootProtoManager: RootProtoManager) { + const methodMap = new Map(); + for (const proto of this.controllerProtos) { + const metadata = proto.getMetaData(CONTROLLER_META_DATA) as HTTPControllerMeta; + for (const method of metadata.methods) { + methodMap.set(method, proto); + } + } + const allMethods = Array.from(methodMap.keys()) + .sort((a, b) => b.priority - a.priority); + + for (const method of allMethods) { + const controllerProto = methodMap.get(method)!; + const controllerMeta = controllerProto.getMetaData(CONTROLLER_META_DATA) as HTTPControllerMeta; + const methodRegister = new HTTPMethodRegister( + controllerProto, controllerMeta, method, this.router, this.checkRouters); + methodRegister.checkDuplicate(); + } + + for (const method of allMethods) { + const controllerProto = methodMap.get(method)!; + const controllerMeta = controllerProto.getMetaData(CONTROLLER_META_DATA) as HTTPControllerMeta; + const methodRegister = new HTTPMethodRegister( + controllerProto, controllerMeta, method, this.router, this.checkRouters); + methodRegister.register(rootProtoManager); + } + } +} diff --git a/standalone/controller/src/impl/http/HTTPMethodRegister.ts b/standalone/controller/src/impl/http/HTTPMethodRegister.ts new file mode 100644 index 00000000..a93fe8ab --- /dev/null +++ b/standalone/controller/src/impl/http/HTTPMethodRegister.ts @@ -0,0 +1,169 @@ +import pathToRegexp from 'path-to-regexp'; +import { FrameworkErrorFormater } from 'egg-errors'; +import { Router as KoaRouter } from '@eggjs/router'; +import { + EggContext, + HTTPControllerMeta, + HTTPMethodMeta, + HTTPParamType, + IncomingHttpHeaders, + Next, + PathParamMeta, + QueriesParamMeta, + QueryParamMeta, +} from '@eggjs/tegg'; +import { EggContainerFactory, EggPrototype } from '@eggjs/tegg/helper'; +import { RootProtoManager } from '../../RootProtoManager'; +import { ServiceWorkerFetchContext } from './ServiceWorkerFetchContext'; +import { RequestUtils } from '../../utils/RequestUtils'; + +const noop = () => { /* noop */ }; + +export class HTTPMethodRegister { + private readonly router: KoaRouter; + private readonly checkRouters: Map; + private readonly controllerMeta: HTTPControllerMeta; + private readonly methodMeta: HTTPMethodMeta; + private readonly proto: EggPrototype; + + constructor( + proto: EggPrototype, + controllerMeta: HTTPControllerMeta, + methodMeta: HTTPMethodMeta, + router: KoaRouter, + checkRouters: Map, + ) { + this.proto = proto; + this.controllerMeta = controllerMeta; + this.router = router; + this.methodMeta = methodMeta; + this.checkRouters = checkRouters; + } + + private createHandler(methodMeta: HTTPMethodMeta, host: string | undefined) { + const argsLength = methodMeta.paramMap.size; + const hasContext = methodMeta.contextParamIndex !== undefined; + const contextIndex = methodMeta.contextParamIndex; + const methodArgsLength = argsLength + (hasContext ? 1 : 0); + const self = this; + return async function(ctx: ServiceWorkerFetchContext, next: Next) { + // if hosts is not empty and host is not matched, not execute + if (host && host !== ctx.host) { + return await next(); + } + // HTTP decorator core implement + // use controller metadata map http request to function arguments + const eggObj = await EggContainerFactory.getOrCreateEggObject(self.proto, self.proto.name); + const realObj = eggObj.obj; + const realMethod = realObj[methodMeta.name]; + const args: Array = new Array(methodArgsLength); + if (hasContext) { + args[contextIndex!] = ctx; + } + for (const [ index, param ] of methodMeta.paramMap) { + switch (param.type) { + case HTTPParamType.BODY: { + const request = ctx.event.request; + args[index] = await RequestUtils.getRequestBody(request); + break; + } + case HTTPParamType.PARAM: { + const pathParam: PathParamMeta = param as PathParamMeta; + args[index] = ctx.params[pathParam.name]; + break; + } + case HTTPParamType.QUERY: { + const queryParam: QueryParamMeta = param as QueryParamMeta; + args[index] = ctx.url.searchParams.get(queryParam.name) as string; + break; + } + case HTTPParamType.QUERIES: { + const queryParam: QueriesParamMeta = param as QueriesParamMeta; + args[index] = ctx.url.searchParams.getAll(queryParam.name); + break; + } + case HTTPParamType.HEADERS: { + const headers: IncomingHttpHeaders = {}; + for (const [ k, v ] of ctx.event.request.headers.entries()) { + headers[k] = v; + } + args[index] = headers; + break; + } + case HTTPParamType.REQUEST: { + args[index] = ctx.event.request; + break; + } + default: + throw new Error(`unknown param type ${param.type} in method ${self.controllerMeta.controllerName}.${methodMeta.name}`); + } + } + const res = await Reflect.apply(realMethod, realObj, args); + if (res instanceof Response) { + ctx.response = res; + } else { + ctx.body = res; + } + }; + } + + checkDuplicate() { + // 1. check duplicate with egg controller + this.checkDuplicateInRouter(this.router); + + // 2. check duplicate with host tegg controller + let hostRouter; + const hosts = this.controllerMeta.getMethodHosts(this.methodMeta) || []; + hosts.forEach(h => { + if (h) { + hostRouter = this.checkRouters.get(h); + if (!hostRouter) { + hostRouter = new KoaRouter({ sensitive: true }); + this.checkRouters.set(h, hostRouter); + } + } + if (hostRouter) { + this.checkDuplicateInRouter(hostRouter); + this.registerToRouter(hostRouter); + } + }); + } + + private registerToRouter(router: KoaRouter) { + const routerFunc = router[this.methodMeta.method.toLowerCase()]; + const methodRealPath = this.controllerMeta.getMethodRealPath(this.methodMeta); + const methodName = this.controllerMeta.getMethodName(this.methodMeta); + Reflect.apply(routerFunc, router, [ methodName, methodRealPath, noop ]); + } + + private checkDuplicateInRouter(router: KoaRouter) { + const methodRealPath = this.controllerMeta.getMethodRealPath(this.methodMeta); + const matched = router.match(methodRealPath, this.methodMeta.method); + const methodName = this.controllerMeta.getMethodName(this.methodMeta); + if (matched.route) { + const [ layer ] = matched.path; + const err = new Error(`register http controller ${methodName} failed, ${this.methodMeta.method} ${methodRealPath} is conflict with exists rule ${layer.path}`); + throw FrameworkErrorFormater.format(err); + } + } + + register(rootProtoManager: RootProtoManager) { + const methodRealPath = this.controllerMeta.getMethodRealPath(this.methodMeta); + const methodName = this.controllerMeta.getMethodName(this.methodMeta); + const routerFunc = this.router[this.methodMeta.method.toLowerCase()]; + const methodMiddlewares = this.controllerMeta.getMethodMiddlewares(this.methodMeta); + + const hosts = this.controllerMeta.getMethodHosts(this.methodMeta) || [ undefined ]; + hosts.forEach(h => { + const handler = this.createHandler(this.methodMeta, h); + Reflect.apply(routerFunc, this.router, [ methodName, methodRealPath, ...methodMiddlewares, handler ]); + // https://github.com/eggjs/egg-core/blob/0af6178022e7734c4a8b17bb56d592b315207883/lib/egg.js#L279 + const regExp = pathToRegexp(methodRealPath, { sensitive: true }); + rootProtoManager.registerRootProto(this.methodMeta.method, (ctx: EggContext) => { + if (regExp.test(ctx.path)) { + return this.proto; + } + }, h || ''); + }); + } +} diff --git a/standalone/controller/src/impl/http/ServiceWorkerFetchContext.ts b/standalone/controller/src/impl/http/ServiceWorkerFetchContext.ts new file mode 100644 index 00000000..71293fa2 --- /dev/null +++ b/standalone/controller/src/impl/http/ServiceWorkerFetchContext.ts @@ -0,0 +1,40 @@ +import { FetchEvent, ServiceWorkerContextInit } from '@eggjs/tegg-types/standalone'; +import { BaseServiceWorkerContextImpl } from '../../ServiceWorkerContext'; +import { ResponseUtils } from '../../utils/ResponseUtils'; + +export class ServiceWorkerFetchContext extends BaseServiceWorkerContextImpl { + url: URL; + method: string; + path: string; + host: string; + // params will be set in @eggjs/router + params: Record = {}; + #body?: any; + + constructor(init: ServiceWorkerContextInit) { + super(init); + + this.url = new URL(this.event.request.url); + this.method = this.event.request.method; + this.path = this.url.pathname; + this.host = this.url.hostname; + } + + get response(): Response | undefined { + return super.response; + } + + set response(response: Response) { + super.response = response; + this.#body = response.body; + } + + get body(): any | undefined { + return this.#body; + } + + set body(body: any) { + this.response = ResponseUtils.createResponseByBody(body); + this.#body = body; + } +} diff --git a/standalone/controller/src/utils/RequestUtils.ts b/standalone/controller/src/utils/RequestUtils.ts new file mode 100644 index 00000000..a4ffafd0 --- /dev/null +++ b/standalone/controller/src/utils/RequestUtils.ts @@ -0,0 +1,37 @@ +import typeis from 'type-is'; + +export class RequestUtils { + static ContentTypes = { + json: [ + 'application/json', + 'application/json-patch+json', + 'application/vnd.api+json', + 'application/csp-report', + 'application/scim+json', + ], + form: [ 'application/x-www-form-urlencoded' ], + text: [ 'text/plain' ], + }; + + static async getRequestBody(request: Request) { + if (RequestUtils.matchContentTypes(request, RequestUtils.ContentTypes.json)) { + return await request.json(); + } + if (RequestUtils.matchContentTypes(request, RequestUtils.ContentTypes.text)) { + return await request.text(); + } + if (RequestUtils.matchContentTypes(request, RequestUtils.ContentTypes.form)) { + return await request.formData(); + } + } + + static matchContentTypes(request: Request, types: string[]) { + const contentType = request.headers.get('content-type'); + const contentTypeValue = typeof contentType === 'string' + // trim extra semicolon + ? contentType.replace(/;$/, '') + : contentType; + + return typeis.is(contentTypeValue!, types); + } +} diff --git a/standalone/controller/src/utils/ResponseUtils.ts b/standalone/controller/src/utils/ResponseUtils.ts new file mode 100644 index 00000000..93720532 --- /dev/null +++ b/standalone/controller/src/utils/ResponseUtils.ts @@ -0,0 +1,16 @@ +export class ResponseUtils { + static createResponseByBody(body: any) { + if (typeof body === 'undefined' || body === null) { + return new Response(null, { status: 204 }); + } + if (Buffer.isBuffer(body) || typeof body === 'string' || body instanceof ReadableStream) { + return new Response(body, { status: 200 }); + } + return new Response(JSON.stringify(body), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } +} diff --git a/standalone/controller/test/Utils.ts b/standalone/controller/test/Utils.ts new file mode 100644 index 00000000..954cd53a --- /dev/null +++ b/standalone/controller/test/Utils.ts @@ -0,0 +1,29 @@ +import path from 'node:path'; +import { ServiceWorkerApp, ServiceWorkerAppInit } from '@eggjs/tegg-service-worker'; +import { StandaloneTestUtil } from '@eggjs/module-test-util/StandaloneTestUtil'; + +export class TestUtils { + static baseDir(name: string) { + return path.join(__dirname, 'fixtures', name); + } + + static async createApp(name: string, init?: ServiceWorkerAppInit) { + const app = new ServiceWorkerApp(init); + await app.init({ + baseDir: TestUtils.baseDir(name), + env: 'unittest', + name, + }); + + return app; + } + + static async createFetchApp(name: string, init?: ServiceWorkerAppInit) { + const app = await TestUtils.createApp(name, init); + const server = await StandaloneTestUtil.startHTTPServer('127.0.0.1', 7001, { + listener: e => app.handleEvent(e), + }); + + return { app, server }; + } +} diff --git a/standalone/controller/test/fixtures/http-params/ParamController.ts b/standalone/controller/test/fixtures/http-params/ParamController.ts new file mode 100644 index 00000000..7ba50d4d --- /dev/null +++ b/standalone/controller/test/fixtures/http-params/ParamController.ts @@ -0,0 +1,59 @@ +import { + HTTPBody, + HTTPController, + HTTPHeaders, + HTTPMethod, + HTTPMethodEnum, + HTTPParam, + HTTPQueries, + HTTPQuery, + HTTPRequest, + Request +} from '@eggjs/tegg'; + +@HTTPController() +export class ParamController { + @HTTPMethod({ method: HTTPMethodEnum.GET, path: '/query' }) + async hello(@HTTPQuery() name: string, @HTTPQueries() type: string[]) { + return { + name, + type, + }; + } + + @HTTPMethod({ method: HTTPMethodEnum.GET, path: '/find/:id' }) + async find(@HTTPParam() id: string) { + return { + id, + }; + } + + @HTTPMethod({ method: HTTPMethodEnum.POST, path: '/echo/body' }) + async echoBody(@HTTPBody() body: object) { + if (body.constructor.name === 'FormData') { + const res = {}; + for (const [ key, value ] of (body as FormData).entries()) { + res[key] = value; + } + return { type: 'formData', body: res }; + } + return { body }; + } + + @HTTPMethod({ method: HTTPMethodEnum.GET, path: '/headers' }) + async headers(@HTTPHeaders() headers: Record) { + return { + headers, + }; + } + + @HTTPMethod({ method: HTTPMethodEnum.POST, path: '/request' }) + async request(@Request() req: HTTPRequest) { + return { + url: req.url, + method: req.method, + customHeaders: req.headers.get('x-custom'), + body: await req.json(), + }; + } +} diff --git a/standalone/controller/test/fixtures/http-params/package.json b/standalone/controller/test/fixtures/http-params/package.json new file mode 100644 index 00000000..d53116ee --- /dev/null +++ b/standalone/controller/test/fixtures/http-params/package.json @@ -0,0 +1,6 @@ +{ + "name": "http-params-app", + "eggModule": { + "name": "httpParamsApp" + } +} diff --git a/standalone/controller/test/fixtures/http-priority/PriorityController.ts b/standalone/controller/test/fixtures/http-priority/PriorityController.ts new file mode 100644 index 00000000..8de26161 --- /dev/null +++ b/standalone/controller/test/fixtures/http-priority/PriorityController.ts @@ -0,0 +1,27 @@ +import { + HTTPController, + HTTPMethod, + HTTPMethodEnum, +} from '@eggjs/tegg'; + +@HTTPController({ + path: '/users', +}) +export class PriorityController { + + @HTTPMethod({ + method: HTTPMethodEnum.GET, + path: '/*', + }) + async lowPriority() { + return 'low priority'; + } + + @HTTPMethod({ + method: HTTPMethodEnum.GET, + path: '/group', + }) + async highPriority() { + return 'high priority'; + } +} diff --git a/standalone/controller/test/fixtures/http-priority/ViewController.ts b/standalone/controller/test/fixtures/http-priority/ViewController.ts new file mode 100644 index 00000000..0f6a8af5 --- /dev/null +++ b/standalone/controller/test/fixtures/http-priority/ViewController.ts @@ -0,0 +1,17 @@ +import { + HTTPController, + HTTPMethod, + HTTPMethodEnum, +} from '@eggjs/tegg'; + +@HTTPController() +export class ViewController { + + @HTTPMethod({ + method: HTTPMethodEnum.GET, + path: '/*', + }) + async get() { + return 'hello, view'; + } +} diff --git a/standalone/controller/test/fixtures/http-priority/package.json b/standalone/controller/test/fixtures/http-priority/package.json new file mode 100644 index 00000000..d53116ee --- /dev/null +++ b/standalone/controller/test/fixtures/http-priority/package.json @@ -0,0 +1,6 @@ +{ + "name": "http-params-app", + "eggModule": { + "name": "httpParamsApp" + } +} diff --git a/standalone/controller/test/fixtures/http/GetController.ts b/standalone/controller/test/fixtures/http/GetController.ts new file mode 100644 index 00000000..0fd5a215 --- /dev/null +++ b/standalone/controller/test/fixtures/http/GetController.ts @@ -0,0 +1,25 @@ +import { HTTPMethodEnum, HTTPController, HTTPMethod, HTTPQuery } from '@eggjs/tegg'; + +@HTTPController() +export class GetController { + @HTTPMethod({ method: HTTPMethodEnum.GET, path: '/hello' }) + async hello() { + return 'hello'; + } + + @HTTPMethod({ method: HTTPMethodEnum.GET, path: '/api/null-body' }) + async nullBody(@HTTPQuery() nil: string) { + return nil ? null : undefined; + } + + @HTTPMethod({ method: HTTPMethodEnum.GET, path: '/api/response' }) + async response() { + return new Response('full response', { + status: 500, + headers: { + 'content-type': 'text/plain', + 'x-custom-header': 'custom-value', + }, + }); + } +} diff --git a/standalone/controller/test/fixtures/http/PostController.ts b/standalone/controller/test/fixtures/http/PostController.ts new file mode 100644 index 00000000..a3b5576d --- /dev/null +++ b/standalone/controller/test/fixtures/http/PostController.ts @@ -0,0 +1,12 @@ +import { HTTPMethodEnum, HTTPController, HTTPMethod, HTTPBody } from '@eggjs/tegg'; + +@HTTPController() +export class PostController { + @HTTPMethod({ method: HTTPMethodEnum.POST, path: '/echo' }) + async hello(@HTTPBody() data: object) { + return { + success: true, + data, + }; + } +} diff --git a/standalone/controller/test/fixtures/http/package.json b/standalone/controller/test/fixtures/http/package.json new file mode 100644 index 00000000..b1f87de6 --- /dev/null +++ b/standalone/controller/test/fixtures/http/package.json @@ -0,0 +1,6 @@ +{ + "name": "http-app", + "eggModule": { + "name": "httpApp" + } +} diff --git a/standalone/controller/test/http/params.test.ts b/standalone/controller/test/http/params.test.ts new file mode 100644 index 00000000..4d6b2823 --- /dev/null +++ b/standalone/controller/test/http/params.test.ts @@ -0,0 +1,83 @@ +import { Server } from 'node:http'; +import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; +import { TestUtils } from '../Utils'; +import httpRequest from 'supertest'; +import assert from 'node:assert'; + +describe('standalone/service-worker-runtime/test/http/params.test.ts', () => { + let app: ServiceWorkerApp; + let server: Server; + + before(async () => { + ({ app, server } = await TestUtils.createFetchApp('http-params')); + }); + + after(async () => { + server?.close(); + await app?.destroy(); + }); + + it('should query param work', async () => { + await httpRequest(server) + .get('/query?name=tegg&type=1&type=2') + .expect(200, { + name: 'tegg', + type: [ '1', '2' ], + }); + }); + + it('should path param work', async () => { + await httpRequest(server) + .get('/find/123') + .expect(200, { + id: '123', + }); + }); + + describe('@HTTPBody()', () => { + it('should json body param work', async () => { + await httpRequest(server) + .post('/echo/body') + .type('json') + .send({ foo: 'bar' }) + .expect(200, { body: { foo: 'bar' } }); + }); + + it('should formData body param work', async () => { + await httpRequest(server) + .post('/echo/body') + .type('form') + .send({ foo: 'bar' }) + .expect(200, { type: 'formData', body: { foo: 'bar' } }); + }); + + it('should text body param work', async () => { + await httpRequest(server) + .post('/echo/body') + .type('text') + .send('hello world') + .expect(200, { body: 'hello world' }); + }); + }); + + it('should headers param work', async () => { + const res = await httpRequest(server) + .get('/headers') + .set('x-custom-header', 'custom-value') + .expect(200); + assert.equal(res.body.headers['x-custom-header'], 'custom-value'); + }); + + it('should request param work', async () => { + await httpRequest(server) + .post('/request') + .set('x-custom', 'custom-value') + .send({ foo: 'bar' }) + .expect(200, { + url: 'http://127.0.0.1:7001/request', + method: 'POST', + customHeaders: 'custom-value', + body: { foo: 'bar' }, + }); + }); +}); diff --git a/standalone/controller/test/http/priority.test.ts b/standalone/controller/test/http/priority.test.ts new file mode 100644 index 00000000..1089eebf --- /dev/null +++ b/standalone/controller/test/http/priority.test.ts @@ -0,0 +1,39 @@ +import { Server } from 'node:http'; +import httpRequest from 'supertest'; +import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; +import { TestUtils } from '../Utils'; + +describe('standalone/service-worker-runtime/test/http/priority.test.ts', () => { + let app: ServiceWorkerApp; + let server: Server; + + before(async () => { + ({ app, server } = await TestUtils.createFetchApp('http-priority')); + }); + + after(async () => { + server?.close(); + await app?.destroy(); + }); + + it('should /* work', async () => { + await httpRequest(server) + .get('/view/foo') + .expect(200) + .expect('hello, view'); + }); + + it('should /users/group work', async () => { + await httpRequest(server) + .get('/users/group') + .expect(200) + .expect('high priority'); + }); + + it('should /users/* work', async () => { + await httpRequest(server) + .get('/users/foo') + .expect(200) + .expect('low priority'); + }); +}); diff --git a/standalone/controller/test/http/response.test.ts b/standalone/controller/test/http/response.test.ts new file mode 100644 index 00000000..33e5a034 --- /dev/null +++ b/standalone/controller/test/http/response.test.ts @@ -0,0 +1,36 @@ +import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; +import { Server } from 'node:http'; +import { TestUtils } from '../Utils'; +import httpRequest from 'supertest'; + +describe('standalone/service-worker-runtime/test/http/response.test.ts', () => { + let app: ServiceWorkerApp; + let server: Server; + + before(async () => { + ({ app, server } = await TestUtils.createFetchApp('http')); + }); + + after(async () => { + server?.close(); + await app?.destroy(); + }); + + it('should return Response work', async () => { + await httpRequest(server) + .get('/api/response') + .expect(500, 'full response') + .expect('Content-Type', 'text/plain') + .expect('x-custom-header', 'custom-value'); + }); + + it('should return 204 with no content', async () => { + await httpRequest(server) + .get('/api/null-body') + .expect(204, ''); + + await httpRequest(server) + .get('/api/null-body?nil=1') + .expect(204, ''); + }); +}); diff --git a/standalone/controller/test/http/router.test.ts b/standalone/controller/test/http/router.test.ts new file mode 100644 index 00000000..4f3958df --- /dev/null +++ b/standalone/controller/test/http/router.test.ts @@ -0,0 +1,40 @@ +import { Server } from 'node:http'; +import httpRequest from 'supertest'; +import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; +import { TestUtils } from '../Utils'; + +describe('standalone/service-worker-runtime/test/http/router.test.ts', () => { + let app: ServiceWorkerApp; + let server: Server; + + before(async () => { + ({ app, server } = await TestUtils.createFetchApp('http')); + }); + + after(async () => { + server?.close(); + await app?.destroy(); + }); + + it('should get work', async () => { + await httpRequest(server) + .get('/hello') + .expect(200, 'hello'); + }); + + it('should post work', async () => { + await httpRequest(server) + .post('/echo') + .send({ name: 'tegg' }) + .expect(200, { + success: true, + data: { name: 'tegg' }, + }); + }); + + it('should return 404 with invalid path', async () => { + await httpRequest(server) + .get('/invalid-path') + .expect(404); + }); +}); diff --git a/standalone/controller/tsconfig.json b/standalone/controller/tsconfig.json new file mode 100644 index 00000000..64b22405 --- /dev/null +++ b/standalone/controller/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": "./" + }, + "exclude": [ + "dist", + "node_modules", + "test" + ] +} diff --git a/standalone/controller/tsconfig.pub.json b/standalone/controller/tsconfig.pub.json new file mode 100644 index 00000000..64b22405 --- /dev/null +++ b/standalone/controller/tsconfig.pub.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": "./" + }, + "exclude": [ + "dist", + "node_modules", + "test" + ] +} diff --git a/standalone/service-worker-runtime/index.ts b/standalone/service-worker-runtime/index.ts new file mode 100644 index 00000000..fb9613a3 --- /dev/null +++ b/standalone/service-worker-runtime/index.ts @@ -0,0 +1,4 @@ +export * from './src/constants'; +export * from './src/types'; +export * from './src/ContextProtoLoadUnitHook'; +export * from './src/ServiceWorkerRunner'; diff --git a/standalone/service-worker-runtime/package.json b/standalone/service-worker-runtime/package.json new file mode 100644 index 00000000..d28c3b85 --- /dev/null +++ b/standalone/service-worker-runtime/package.json @@ -0,0 +1,61 @@ +{ + "name": "@eggjs/tegg-service-worker-runtime", + "description": "tegg service worker runtime", + "eggModule": { + "name": "serviceWorkerRuntime" + }, + "version": "3.57.12", + "keywords": [ + "egg", + "typescript", + "background", + "async", + "tegg", + "standalone", + "service worker" + ], + "main": "dist/index.js", + "files": [ + "dist/**/*.js", + "dist/**/*.d.ts" + ], + "typings": "dist/index.d.ts", + "scripts": { + "test": "cross-env NODE_ENV=test NODE_OPTIONS='--no-deprecation' mocha", + "clean": "tsc -b --clean", + "tsc": "npm run clean && tsc -p ./tsconfig.json", + "tsc:pub": "npm run clean && tsc -p ./tsconfig.pub.json", + "prepublishOnly": "npm run tsc:pub" + }, + "homepage": "https://github.com/eggjs/tegg", + "bugs": { + "url": "https://github.com/eggjs/tegg/issues" + }, + "repository": { + "type": "git", + "url": "git@github.com:eggjs/tegg.git", + "directory": "standalone/standalone" + }, + "engines": { + "node": ">=14.0.0" + }, + "author": "killagu ", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "peerDependencies": { + "@eggjs/tegg": "^3" + }, + "devDependencies": { + "@eggjs/tegg": "^3.57.12", + "@eggjs/tegg-standalone": "^3.57.12", + "@types/mocha": "^10.0.1", + "@types/node": "^20.2.4", + "cross-env": "^7.0.3", + "mm": "^3.2.1", + "mocha": "^10.2.0", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + } +} diff --git a/standalone/service-worker-runtime/src/ContextProtoLoadUnitHook.ts b/standalone/service-worker-runtime/src/ContextProtoLoadUnitHook.ts new file mode 100644 index 00000000..ff936f12 --- /dev/null +++ b/standalone/service-worker-runtime/src/ContextProtoLoadUnitHook.ts @@ -0,0 +1,34 @@ +import assert from 'node:assert'; +import { IdenticalUtil, LifecycleHook } from '@eggjs/tegg-lifecycle'; +import { ContextHandler, EggPrototypeFactory, LoadUnit, LoadUnitLifecycleContext } from '@eggjs/tegg/helper'; +import { StandaloneInnerObjectProto } from '@eggjs/tegg-standalone'; +import { ObjectInitType } from '@eggjs/tegg-types'; +import { LoadUnitLifecycleProto } from '@eggjs/tegg'; +import { ProtoMeta } from './types'; +import { ContextProtoProperty } from './constants'; + +@LoadUnitLifecycleProto() +export class ContextProtoLoadUnitHook implements LifecycleHook { + async preCreate(_: LoadUnitLifecycleContext, loadUnit: LoadUnit): Promise { + if (loadUnit.name === 'serviceWorkerRuntime') { + // can `@Inject() event` + ContextProtoLoadUnitHook.registerPrototype(ContextProtoProperty.Event, loadUnit); + } + } + + static registerPrototype(protoMeta: ProtoMeta, loadUnit: LoadUnit) { + const proto = new StandaloneInnerObjectProto( + IdenticalUtil.createProtoId(loadUnit.id, protoMeta.protoName), + protoMeta.protoName, + (() => { + const ctx = ContextHandler.getContext(); + assert(ctx, 'context should not be null'); + return ctx.get(protoMeta.contextKey); + }) as any, + ObjectInitType.CONTEXT, + loadUnit.id, + [], + ); + EggPrototypeFactory.instance.registerPrototype(proto, loadUnit); + } +} diff --git a/standalone/service-worker-runtime/src/ServiceWorkerRunner.ts b/standalone/service-worker-runtime/src/ServiceWorkerRunner.ts new file mode 100644 index 00000000..37e34078 --- /dev/null +++ b/standalone/service-worker-runtime/src/ServiceWorkerRunner.ts @@ -0,0 +1,16 @@ +import { SingletonProto, Inject, EggObjectFactory } from '@eggjs/tegg'; +import { Runner, AbstractEventHandler } from '@eggjs/tegg/standalone'; + +@Runner() +@SingletonProto() +export class ServiceWorkerRunner { + @Inject() + private readonly event: Event; + @Inject() + private readonly eggObjectFactory: EggObjectFactory; + + async main(): Promise { + const handler = await this.eggObjectFactory.getEggObject(AbstractEventHandler, this.event.type); + return await handler.handleEvent(this.event); + } +} diff --git a/standalone/service-worker-runtime/src/constants.ts b/standalone/service-worker-runtime/src/constants.ts new file mode 100644 index 00000000..e3e77a35 --- /dev/null +++ b/standalone/service-worker-runtime/src/constants.ts @@ -0,0 +1,8 @@ +import { ProtoMeta } from './types'; + +export class ContextProtoProperty { + static readonly Event: ProtoMeta = { + protoName: 'event', + contextKey: Symbol('context#event'), + }; +} diff --git a/standalone/service-worker-runtime/src/types.ts b/standalone/service-worker-runtime/src/types.ts new file mode 100644 index 00000000..eaf35916 --- /dev/null +++ b/standalone/service-worker-runtime/src/types.ts @@ -0,0 +1,4 @@ +export interface ProtoMeta { + protoName: PropertyKey; + contextKey: string | symbol; +} diff --git a/standalone/service-worker-runtime/test/Utils.ts b/standalone/service-worker-runtime/test/Utils.ts new file mode 100644 index 00000000..045b5140 --- /dev/null +++ b/standalone/service-worker-runtime/test/Utils.ts @@ -0,0 +1,35 @@ +import path from 'node:path'; +import { StandaloneApp, StandaloneAppInit, StandaloneContext } from '@eggjs/tegg-standalone'; +import { ContextProtoProperty } from '../src/constants'; + +export class StandAloneAppTest { + static baseDir(name: string) { + return path.join(__dirname, 'fixtures', name); + } + + static async run(name: string, event: any, init?: StandaloneAppInit): Promise { + const app = new StandaloneApp({ + frameworkDeps: [ + path.dirname(require.resolve('@eggjs/tegg-dynamic-inject-runtime/package.json')), + { baseDir: path.join(__dirname, '..'), extraFilePattern: [ '!**/test' ] }, + ], + ...init, + }); + try { + await app.init({ + baseDir: StandAloneAppTest.baseDir(name), + env: 'unittest', + name, + }); + + const ctx = new StandaloneContext(); + ctx.set(ContextProtoProperty.Event.contextKey, event); + return await app.run(ctx); + } finally { + await app.destroy().catch(e => { + e.message = `[tegg/standalone] destroy tegg failed: ${e.message}`; + console.warn(e); + }); + } + } +} diff --git a/standalone/service-worker-runtime/test/fixtures/simple/Event.ts b/standalone/service-worker-runtime/test/fixtures/simple/Event.ts new file mode 100644 index 00000000..33f31a8c --- /dev/null +++ b/standalone/service-worker-runtime/test/fixtures/simple/Event.ts @@ -0,0 +1,8 @@ +export class CustomEvent extends Event { + readonly data: any; + + constructor(type: 'custom', data: any) { + super(type); + this.data = data; + } +} diff --git a/standalone/service-worker-runtime/test/fixtures/simple/FetchEventHandler.ts b/standalone/service-worker-runtime/test/fixtures/simple/FetchEventHandler.ts new file mode 100644 index 00000000..4c6a2c5f --- /dev/null +++ b/standalone/service-worker-runtime/test/fixtures/simple/FetchEventHandler.ts @@ -0,0 +1,10 @@ +import { AccessLevel } from '@eggjs/tegg'; +import { AbstractEventHandler, EventHandlerProto } from '@eggjs/tegg/standalone'; +import { CustomEvent } from './Event'; + +@EventHandlerProto('custom', { accessLevel: AccessLevel.PUBLIC }) +export class FetchEventHandler extends AbstractEventHandler { + async handleEvent(event: CustomEvent): Promise { + return 'hello:' + JSON.stringify(event.data); + } +} diff --git a/standalone/service-worker-runtime/test/fixtures/simple/package.json b/standalone/service-worker-runtime/test/fixtures/simple/package.json new file mode 100644 index 00000000..1c4562cc --- /dev/null +++ b/standalone/service-worker-runtime/test/fixtures/simple/package.json @@ -0,0 +1,6 @@ +{ + "name": "simple", + "eggModule": { + "name": "simple" + } +} diff --git a/standalone/service-worker-runtime/test/index.test.ts b/standalone/service-worker-runtime/test/index.test.ts new file mode 100644 index 00000000..fffefa01 --- /dev/null +++ b/standalone/service-worker-runtime/test/index.test.ts @@ -0,0 +1,14 @@ +import { strict as assert } from 'node:assert'; +import { StandAloneAppTest } from './Utils'; +import { CustomEvent } from './fixtures/simple/Event'; + +describe('standalone/service-worker-runtime/test/index.test.ts', () => { + describe('simple', () => { + it('should work', async () => { + const event = new CustomEvent('custom', { foo: 'bar' }); + const msg = await StandAloneAppTest.run('simple', event); + + assert(msg, 'hello:{"foo":"bar"}'); + }); + }); +}); diff --git a/standalone/service-worker-runtime/tsconfig.json b/standalone/service-worker-runtime/tsconfig.json new file mode 100644 index 00000000..64b22405 --- /dev/null +++ b/standalone/service-worker-runtime/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": "./" + }, + "exclude": [ + "dist", + "node_modules", + "test" + ] +} diff --git a/standalone/service-worker-runtime/tsconfig.pub.json b/standalone/service-worker-runtime/tsconfig.pub.json new file mode 100644 index 00000000..64b22405 --- /dev/null +++ b/standalone/service-worker-runtime/tsconfig.pub.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": "./" + }, + "exclude": [ + "dist", + "node_modules", + "test" + ] +} diff --git a/standalone/service-worker/index.ts b/standalone/service-worker/index.ts new file mode 100644 index 00000000..c8803ed8 --- /dev/null +++ b/standalone/service-worker/index.ts @@ -0,0 +1 @@ +export * from './src/ServiceWorkerApp'; diff --git a/standalone/service-worker/package.json b/standalone/service-worker/package.json new file mode 100644 index 00000000..c0139e38 --- /dev/null +++ b/standalone/service-worker/package.json @@ -0,0 +1,67 @@ +{ + "name": "@eggjs/tegg-service-worker", + "description": "tegg service worker", + "version": "3.57.12", + "keywords": [ + "egg", + "typescript", + "background", + "async", + "tegg", + "standalone", + "service worker" + ], + "main": "dist/index.js", + "files": [ + "dist/**/*.js", + "dist/**/*.d.ts" + ], + "typings": "dist/index.d.ts", + "scripts": { + "test": "cross-env NODE_ENV=test NODE_OPTIONS='--no-deprecation' mocha", + "clean": "tsc -b --clean", + "tsc": "npm run clean && tsc -p ./tsconfig.json", + "tsc:pub": "npm run clean && tsc -p ./tsconfig.pub.json", + "prepublishOnly": "npm run tsc:pub" + }, + "homepage": "https://github.com/eggjs/tegg", + "bugs": { + "url": "https://github.com/eggjs/tegg/issues" + }, + "repository": { + "type": "git", + "url": "git@github.com:eggjs/tegg.git", + "directory": "standalone/standalone" + }, + "engines": { + "node": ">=14.0.0" + }, + "author": "killagu ", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@eggjs/tegg-standalone": "^3.57.12", + "@eggjs/tegg-dynamic-inject-runtime": "^3.57.12", + "@eggjs/tegg-ajv-plugin": "^3.57.12", + "@eggjs/tegg-dal-plugin": "^3.57.12", + "@eggjs/tegg-aop-runtime": "^3.57.12", + "@eggjs/tegg-service-worker-runtime": "^3.57.12", + "@eggjs/tegg-standalone-controller": "^3.57.12" + }, + "peerDependencies": { + "@eggjs/tegg": "^3" + }, + "devDependencies": { + "@eggjs/tegg": "^3.57.12", + "@types/mocha": "^10.0.1", + "@types/node": "^20.2.4", + "cross-env": "^7.0.3", + "mm": "^3.2.1", + "mocha": "^10.2.0", + "ts-node": "^10.9.1", + "typescript": "^5.0.4", + "undici": "^5.26.5" + } +} diff --git a/standalone/service-worker/src/ServiceWorkerApp.ts b/standalone/service-worker/src/ServiceWorkerApp.ts new file mode 100644 index 00000000..bd0ddfdd --- /dev/null +++ b/standalone/service-worker/src/ServiceWorkerApp.ts @@ -0,0 +1,22 @@ +import path from 'node:path'; +import { StandaloneApp, StandaloneAppInit, StandaloneContext } from '@eggjs/tegg-standalone'; +import { ContextProtoProperty } from '@eggjs/tegg-service-worker-runtime'; + +export type ServiceWorkerAppInit = Omit; + +export class ServiceWorkerApp extends StandaloneApp { + constructor(init?: ServiceWorkerAppInit) { + const opts: StandaloneAppInit = { + ...init, + frameworkDeps: [{ baseDir: path.join(__dirname, '..'), extraFilePattern: [ '!**/test' ] }], + }; + super(opts); + } + + async handleEvent(event: Event) { + const context = new StandaloneContext(); + context.set(ContextProtoProperty.Event.contextKey, event); + + return await this.run(context); + } +} diff --git a/standalone/service-worker/test/Utils.ts b/standalone/service-worker/test/Utils.ts new file mode 100644 index 00000000..9fb35af7 --- /dev/null +++ b/standalone/service-worker/test/Utils.ts @@ -0,0 +1,29 @@ +import path from 'node:path'; +import { Request, RequestInfo, RequestInit } from 'undici'; +import { FetchEvent } from '@eggjs/tegg-types/standalone'; +import { ServiceWorkerApp, ServiceWorkerAppInit } from '../src/ServiceWorkerApp'; + +export class TestUtils { + static baseDir(name: string) { + return path.join(__dirname, 'fixtures', name); + } + + static async createApp(name: string, init?: ServiceWorkerAppInit) { + const app = new ServiceWorkerApp(init); + await app.init({ + baseDir: TestUtils.baseDir(name), + env: 'unittest', + name, + }); + + return app; + } + + static createFetchEvent(input: RequestInfo, init?: RequestInit): FetchEvent { + const request = new Request(input, init); + const event: any = new Event('fetch'); + event.request = request; + + return event; + } +} diff --git a/standalone/service-worker/test/fixtures/http/controller.ts b/standalone/service-worker/test/fixtures/http/controller.ts new file mode 100644 index 00000000..9eedf354 --- /dev/null +++ b/standalone/service-worker/test/fixtures/http/controller.ts @@ -0,0 +1,12 @@ +import { HTTPController, HTTPMethod, HTTPMethodEnum, HTTPQuery } from '@eggjs/tegg'; + +@HTTPController() +export class Controller { + @HTTPMethod({ method: HTTPMethodEnum.GET, path: '/echo' }) + async echo(@HTTPQuery() name: string) { + return { + success: true, + message: 'hello ' + name, + }; + } +} diff --git a/standalone/service-worker/test/fixtures/http/package.json b/standalone/service-worker/test/fixtures/http/package.json new file mode 100644 index 00000000..b1f87de6 --- /dev/null +++ b/standalone/service-worker/test/fixtures/http/package.json @@ -0,0 +1,6 @@ +{ + "name": "http-app", + "eggModule": { + "name": "httpApp" + } +} diff --git a/standalone/service-worker/test/http.test.ts b/standalone/service-worker/test/http.test.ts new file mode 100644 index 00000000..5373816a --- /dev/null +++ b/standalone/service-worker/test/http.test.ts @@ -0,0 +1,23 @@ +import { strict as assert } from 'node:assert'; +import { ServiceWorkerApp } from '../src/ServiceWorkerApp'; +import { TestUtils } from './Utils'; + +describe('standalone/service-worker/test/http.test.ts', () => { + let app: ServiceWorkerApp; + + afterEach(async () => { + await app?.destroy(); + }); + + it('should get work', async () => { + app = await TestUtils.createApp('http'); + + const event = TestUtils.createFetchEvent('http://127.0.0.1/echo?name=foo', { method: 'GET' }); + + const res: Response = await app.handleEvent(event); + assert.deepEqual(await res.json(), { + success: true, + message: 'hello foo', + }); + }); +}); diff --git a/standalone/service-worker/tsconfig.json b/standalone/service-worker/tsconfig.json new file mode 100644 index 00000000..64b22405 --- /dev/null +++ b/standalone/service-worker/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": "./" + }, + "exclude": [ + "dist", + "node_modules", + "test" + ] +} diff --git a/standalone/service-worker/tsconfig.pub.json b/standalone/service-worker/tsconfig.pub.json new file mode 100644 index 00000000..64b22405 --- /dev/null +++ b/standalone/service-worker/tsconfig.pub.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": "./" + }, + "exclude": [ + "dist", + "node_modules", + "test" + ] +} diff --git a/standalone/standalone/index.ts b/standalone/standalone/index.ts index 0ff5948c..e365f739 100644 --- a/standalone/standalone/index.ts +++ b/standalone/standalone/index.ts @@ -1,6 +1,12 @@ +export * from './src/common/constant'; +export * from './src/common/types'; +export * from './src/common/utils/Timing'; export * from './src/EggModuleLoader'; export * from './src/Runner'; -export * from './src/main'; -export * from './src/StandaloneInnerObjectProto'; +export * from './src/StandaloneApp'; export * from './src/StandaloneContext'; +export * from './src/StandaloneClassLoader'; +export * from './src/StandaloneContextHandler'; +export * from './src/StandaloneInnerObjectProto'; export * from './src/StandaloneInnerObject'; +export * from './src/main'; diff --git a/standalone/standalone/package.json b/standalone/standalone/package.json index 293bf6c9..6ce5ce50 100644 --- a/standalone/standalone/package.json +++ b/standalone/standalone/package.json @@ -48,7 +48,8 @@ "@eggjs/tegg-lifecycle": "^3.57.14", "@eggjs/tegg-loader": "^3.57.14", "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14" + "@eggjs/tegg-runtime": "^3.57.14", + "time-profile": "^2.0.0" }, "publishConfig": { "access": "public" diff --git a/standalone/standalone/src/Runner.ts b/standalone/standalone/src/Runner.ts index d36a64b4..0d527e48 100644 --- a/standalone/standalone/src/Runner.ts +++ b/standalone/standalone/src/Runner.ts @@ -1,7 +1,8 @@ -import { ModuleConfigUtil, ModuleReference, ReadModuleReferenceOptions, RuntimeConfig } from '@eggjs/tegg-common-util'; +import { ModuleConfigUtil, ModuleReference, RuntimeConfig } from '@eggjs/tegg-common-util'; import { EggPrototype, - EggPrototypeLifecycleUtil, GlobalGraph, + EggPrototypeLifecycleUtil, + GlobalGraph, LoadUnit, LoadUnitFactory, LoadUnitLifecycleUtil, @@ -30,11 +31,11 @@ import { crossCutGraphHook, EggObjectAopHook, EggPrototypeCrossCutHook, - LoadUnitAopHook, pointCutGraphHook, + LoadUnitAopHook, + pointCutGraphHook, } from '@eggjs/tegg-aop-runtime'; - import { EggModuleLoader } from './EggModuleLoader'; -import { InnerObject, StandaloneLoadUnit, StandaloneLoadUnitType } from './StandaloneLoadUnit'; +import { StandaloneLoadUnit } from './loadUnit/StandaloneLoadUnit'; import { StandaloneContext } from './StandaloneContext'; import { StandaloneContextHandler } from './StandaloneContextHandler'; import { ConfigSourceLoadUnitHook } from './ConfigSourceLoadUnitHook'; @@ -44,10 +45,8 @@ import { MysqlDataSourceManager } from '@eggjs/tegg-dal-plugin/lib/MysqlDataSour import { SqlMapManager } from '@eggjs/tegg-dal-plugin/lib/SqlMapManager'; import { TableModelManager } from '@eggjs/tegg-dal-plugin/lib/TableModelManager'; import { TransactionPrototypeHook } from '@eggjs/tegg-dal-plugin/lib/TransactionPrototypeHook'; - -export interface ModuleDependency extends ReadModuleReferenceOptions { - baseDir: string; -} +import { InnerObject, ModuleDependency } from './common/types'; +import { StandaloneLoadUnitType } from './common/constant'; export interface RunnerOptions { /** diff --git a/standalone/standalone/src/StandaloneApp.ts b/standalone/standalone/src/StandaloneApp.ts new file mode 100644 index 00000000..f900d9fc --- /dev/null +++ b/standalone/standalone/src/StandaloneApp.ts @@ -0,0 +1,332 @@ +import { + ConfigSourceQualifierAttribute, + EggPrototype, + LoadUnit, + LoadUnitInstance, + Logger, + ModuleConfigHolder, + ModuleReference, + type ReadModuleReferenceOptions, + RuntimeConfig, +} from '@eggjs/tegg-types'; +import { ModuleConfigs, ModuleConfigUtil } from '@eggjs/tegg-common-util'; +import { PrototypeUtil } from '@eggjs/core-decorator'; +import { EggPrototypeLifecycleUtil, GlobalGraph, LoadUnitFactory, LoadUnitLifecycleUtil } from '@eggjs/tegg-metadata'; +import { + ContextHandler, + EggContainerFactory, + EggContext, + EggObjectLifecycleUtil, + LoadUnitInstanceFactory, +} from '@eggjs/tegg-runtime'; +import { MainRunner, StandaloneUtil } from '@eggjs/tegg/standalone'; +import { TimeProfile, Timing } from './common/utils/Timing'; +import { StandaloneClassLoader } from './StandaloneClassLoader'; +import { InnerObject, ModuleDependency } from './common/types'; +import { StandaloneLoadUnitInitializer } from './initializer/StandaloneLoadUnitInitializer'; +import { ModuleLoadUnitInitializer } from './initializer/ModuleLoadUnitInitializer'; +import { StandaloneContext } from './StandaloneContext'; +import { StandaloneContextHandler } from './StandaloneContextHandler'; +import './loadUnit/StandaloneLoadUnitInstance'; +import { + crossCutGraphHook, + EggObjectAopHook, + EggPrototypeCrossCutHook, + LoadUnitAopHook, + pointCutGraphHook, +} from '@eggjs/tegg-aop-runtime'; +import { ConfigSourceLoadUnitHook } from './ConfigSourceLoadUnitHook'; +import { CrosscutAdviceFactory } from '@eggjs/tegg/aop'; +import { DalModuleLoadUnitHook } from '@eggjs/tegg-dal-plugin/lib/DalModuleLoadUnitHook'; +import { DalTableEggPrototypeHook } from '@eggjs/tegg-dal-plugin/lib/DalTableEggPrototypeHook'; +import { TransactionPrototypeHook } from '@eggjs/tegg-dal-plugin/lib/TransactionPrototypeHook'; +import { MysqlDataSourceManager } from '@eggjs/tegg-dal-plugin/lib/MysqlDataSourceManager'; +import { SqlMapManager } from '@eggjs/tegg-dal-plugin/lib/SqlMapManager'; +import { TableModelManager } from '@eggjs/tegg-dal-plugin/lib/TableModelManager'; + +export interface StandaloneAppInit { + frameworkDeps?: Array; + dump?: boolean; + innerObjects?: Record; + logger?: Logger; +} + +export interface InitStandaloneAppOptions { + name: string; + env?: string; + baseDir: string; +} + +export class StandaloneApp { + readonly #frameworkDeps: ModuleDependency[]; + readonly #moduleReferences: ModuleReference[]; + readonly #classLoader: StandaloneClassLoader; + readonly #innerObjects: Record; + readonly #moduleConfigs: Record; + readonly #runtimeConfig: RuntimeConfig; + readonly #standaloneLoadUnitInitializer: StandaloneLoadUnitInitializer; + readonly #moduleLoadUnitInitializer: ModuleLoadUnitInitializer; + readonly #loadUnits: LoadUnit[]; + readonly #loadUnitInstances: LoadUnitInstance[]; + readonly #dump: boolean; + readonly #logger?: Logger; + #handleDestroy?: () => void; + #runnerProto: EggPrototype; + + constructor(init?: StandaloneAppInit) { + this.#frameworkDeps = (init?.frameworkDeps || []).map(baseDir => (typeof baseDir === 'string' ? { baseDir } : baseDir)); + this.#moduleReferences = []; + this.#moduleConfigs = {}; + // in constructor, there is no runtime config yet, pre-create the object first + this.#runtimeConfig = {} as any; + this.#loadUnits = []; + this.#loadUnitInstances = []; + this.#dump = init?.dump !== false; + this.#logger = init?.logger; + const classLoader = new StandaloneClassLoader(); + this.#classLoader = classLoader; + this.#standaloneLoadUnitInitializer = new StandaloneLoadUnitInitializer({ classLoader }); + const globalGraph = new GlobalGraph(); + GlobalGraph.instance = globalGraph; + this.#moduleLoadUnitInitializer = new ModuleLoadUnitInitializer({ classLoader, globalGraph }); + + this.#innerObjects = this.#createInnerObjects(init); + } + + #createInnerObjects(init?: StandaloneAppInit) { + return Object.assign({}, init?.innerObjects, { + moduleConfigs: [{ + obj: new ModuleConfigs(this.#moduleConfigs), + }], + moduleConfig: [], + runtimeConfig: [{ + obj: this.#runtimeConfig, + }], + }); + } + + // TODO, should be revamped to LifecycleProto + #handleCompatibility(opts: InitStandaloneAppOptions) { + const configSourceEggPrototypeHook = new ConfigSourceLoadUnitHook(); + LoadUnitLifecycleUtil.registerLifecycle(configSourceEggPrototypeHook); + + const crosscutAdviceFactory = new CrosscutAdviceFactory(); + const loadUnitAopHook = new LoadUnitAopHook(crosscutAdviceFactory); + const eggPrototypeCrossCutHook = new EggPrototypeCrossCutHook(crosscutAdviceFactory); + const eggObjectAopHook = new EggObjectAopHook(); + + EggPrototypeLifecycleUtil.registerLifecycle(eggPrototypeCrossCutHook); + LoadUnitLifecycleUtil.registerLifecycle(loadUnitAopHook); + EggObjectLifecycleUtil.registerLifecycle(eggObjectAopHook); + + const dalModuleLoadUnitHook = new DalModuleLoadUnitHook(opts.env ?? '', this.#moduleConfigs, this.#logger); + const dalTableEggPrototypeHook = new DalTableEggPrototypeHook(this.#logger || console); + const transactionPrototypeHook = new TransactionPrototypeHook(this.#moduleConfigs, this.#logger); + EggPrototypeLifecycleUtil.registerLifecycle(dalTableEggPrototypeHook); + EggPrototypeLifecycleUtil.registerLifecycle(transactionPrototypeHook); + LoadUnitLifecycleUtil.registerLifecycle(dalModuleLoadUnitHook); + + return () => { + LoadUnitLifecycleUtil.deleteLifecycle(configSourceEggPrototypeHook); + + EggPrototypeLifecycleUtil.deleteLifecycle(eggPrototypeCrossCutHook); + LoadUnitLifecycleUtil.deleteLifecycle(loadUnitAopHook); + EggObjectLifecycleUtil.deleteLifecycle(eggObjectAopHook); + + EggPrototypeLifecycleUtil.deleteLifecycle(dalTableEggPrototypeHook); + EggPrototypeLifecycleUtil.deleteLifecycle(transactionPrototypeHook); + LoadUnitLifecycleUtil.deleteLifecycle(dalModuleLoadUnitHook); + }; + } + + initRuntime(opts: InitStandaloneAppOptions) { + this.#runtimeConfig.name = opts.name; + this.#runtimeConfig.env = opts.env || ''; + this.#runtimeConfig.baseDir = opts.baseDir; + this.#logger?.debug('init runtime config: %j', this.#runtimeConfig); + + // load module.yml and module.env.yml by default + if (!ModuleConfigUtil.configNames && this.#runtimeConfig.env) { + ModuleConfigUtil.configNames = [ 'module.default', `module.${this.#runtimeConfig.env}` ]; + } + this.#logger?.debug('use module config names: %j', ModuleConfigUtil.configNames); + + GlobalGraph.instance!.registerBuildHook(crossCutGraphHook); + GlobalGraph.instance!.registerBuildHook(pointCutGraphHook); + + this.#handleDestroy = this.#handleCompatibility(opts); + + StandaloneContextHandler.register(); + } + + @TimeProfile() + loadFramework() { + for (const dep of this.#frameworkDeps) { + this.#loadModule(dep.baseDir, dep); + } + } + + @TimeProfile() + loadStandaloneModule(opts: InitStandaloneAppOptions) { + this.#loadModule(opts.baseDir); + } + + @TimeProfile() + async loadModuleConfig() { + for (const reference of this.#moduleReferences) { + const moduleConfig = { + name: reference.name, + reference, + config: await ModuleConfigUtil.loadModuleConfig(reference.path), + }; + this.#logger?.debug('load module config %j', moduleConfig); + + this.#moduleConfigs[reference.name] = moduleConfig; + + this.#innerObjects.moduleConfig.push({ + obj: moduleConfig.config, + qualifiers: [{ + attribute: ConfigSourceQualifierAttribute, + value: moduleConfig.name, + }], + }); + } + } + + @TimeProfile() + loadModuleConfigSync() { + for (const reference of this.#moduleReferences) { + const moduleConfig = { + name: reference.name, + reference, + config: ModuleConfigUtil.loadModuleConfigSync(reference.path), + }; + this.#logger?.debug('load module config %j', moduleConfig); + + this.#moduleConfigs[reference.name] = moduleConfig; + + this.#innerObjects.moduleConfig.push({ + obj: moduleConfig.config, + qualifiers: [{ + attribute: ConfigSourceQualifierAttribute, + value: moduleConfig.name, + }], + }); + } + } + + @TimeProfile() + async dump(opts: InitStandaloneAppOptions) { + if (this.#dump) { + await this.#classLoader.dump({ + baseDir: opts.baseDir, + logger: this.#logger, + }); + } + } + + @TimeProfile() + async instantiate() { + await this.instantiateStandaloneLoadUnit(); + await this.instantiateModuleLoadUnit(); + } + + @TimeProfile() + async instantiateStandaloneLoadUnit() { + const standaloneLoadUnit = await this.#standaloneLoadUnitInitializer.createLoadUnit({ innerObjects: this.#innerObjects }); + this.#loadUnits.push(standaloneLoadUnit); + const instance = await LoadUnitInstanceFactory.createLoadUnitInstance(standaloneLoadUnit); + this.#loadUnitInstances.push(instance); + } + + @TimeProfile() + async instantiateModuleLoadUnit() { + const loadUnits = await Timing.profile(async () => { + return await this.#moduleLoadUnitInitializer.createModuleLoadUnits(); + }, 'createLoadUnits'); + + for (const loadUnit of loadUnits) { + this.#loadUnits.push(loadUnit); + await Timing.profile(async () => { + const instance = await LoadUnitInstanceFactory.createLoadUnitInstance(loadUnit); + this.#loadUnitInstances.push(instance); + }, `create ${loadUnit.name} load unit instance`); + } + } + + initRunner() { + const runnerClass = StandaloneUtil.getMainRunner(); + if (!runnerClass) { + throw new Error('not found runner class. Do you add @Runner decorator?'); + } + const proto = PrototypeUtil.getClazzProto(runnerClass); + if (!proto) { + throw new Error(`can not get proto for runner clazz ${runnerClass.name}`); + } + this.#runnerProto = proto as EggPrototype; + } + + #loadModule(baseDir: string, options?: ReadModuleReferenceOptions) { + const moduleReferences = Timing.profile(() => { + return ModuleConfigUtil.readModuleReference(baseDir, options); + }, 'scanModuleReference'); + this.#logger?.debug('scan module references in %s, find %j', baseDir, moduleReferences); + + for (const module of moduleReferences) { + this.#moduleReferences.push(module); + Timing.profile(() => this.#classLoader.loadModule(module), `load module ${module.name}`); + this.#standaloneLoadUnitInitializer.addInnerObjectProto(module); + this.#moduleLoadUnitInitializer.addModule(module); + } + } + + async init(opts: InitStandaloneAppOptions) { + this.initRuntime(opts); + this.loadFramework(); + this.loadStandaloneModule(opts); + await this.loadModuleConfig(); + this.dump(opts); + await this.instantiate(); + this.initRunner(); + } + + async run(aCtx?: EggContext) { + const lifecycle = {}; + const ctx = aCtx || new StandaloneContext(); + return await ContextHandler.run(ctx, async () => { + await ctx.init?.(lifecycle); + const eggObject = await EggContainerFactory.getOrCreateEggObject(this.#runnerProto); + const runner = eggObject.obj as MainRunner; + try { + return await runner.main(); + } finally { + ctx.destroy?.(lifecycle).catch(e => { + e.message = `[tegg/standalone] destroy tegg context failed: ${e.message}`; + console.warn(e); + }); + } + }); + } + + async destroy() { + while (this.#loadUnitInstances.length > 0) { + const loadUnitInstance = this.#loadUnitInstances.pop(); + await LoadUnitInstanceFactory.destroyLoadUnitInstance(loadUnitInstance!); + } + + while (this.#loadUnits.length > 0) { + const loadUnit = this.#loadUnits.pop(); + if (loadUnit) { + await LoadUnitFactory.destroyLoadUnit(loadUnit); + } + } + + this.#handleDestroy?.(); + + MysqlDataSourceManager.instance.clear(); + SqlMapManager.instance.clear(); + TableModelManager.instance.clear(); + // clear configNames + ModuleConfigUtil.setConfigNames(undefined); + } +} diff --git a/standalone/standalone/src/StandaloneClassLoader.ts b/standalone/standalone/src/StandaloneClassLoader.ts new file mode 100644 index 00000000..6f9102d4 --- /dev/null +++ b/standalone/standalone/src/StandaloneClassLoader.ts @@ -0,0 +1,62 @@ +import { ModuleDescriptor, ModuleDescriptorDumper, PrototypeClassDefinition } from '@eggjs/tegg-metadata'; +import { Logger, ModuleReference } from '@eggjs/tegg-types'; +import { LoaderFactory } from '@eggjs/tegg-loader'; + +export interface DumpStandaloneModule { + baseDir: string; + logger?: Logger; +} + +export class StandaloneClassLoader { + readonly #moduleDescriptorMap: Record; + + constructor() { + this.#moduleDescriptorMap = {}; + } + + loadModule(moduleReference: ModuleReference) { + const id = StandaloneClassLoader.#moduleDescriptorId(moduleReference); + if (!this.#moduleDescriptorMap[id]) { + this.#moduleDescriptorMap[id] = LoaderFactory.loadModule(moduleReference); + } + + return this.#moduleDescriptorMap[id]; + } + + getInnerObjectClass(moduleReference: ModuleReference) { + const descriptor = this.loadModule(moduleReference); + return descriptor.innerObjectClazzList; + } + + getMultiInstanceClassDefinitions(): PrototypeClassDefinition[] { + const definitions: PrototypeClassDefinition[] = []; + for (const moduleDescriptor of Object.values(this.#moduleDescriptorMap)) { + for (const clazz of moduleDescriptor.multiInstanceClazzList) { + const definition: PrototypeClassDefinition = { + clazz, + defineModuleName: moduleDescriptor.name, + defineUnitPath: moduleDescriptor.unitPath, + }; + definitions.push(definition); + } + } + + return definitions; + } + + async dump(opts: DumpStandaloneModule) { + const dumpDir = opts.baseDir; + for (const moduleDescriptor of Object.values(this.#moduleDescriptorMap)) { + try { + await ModuleDescriptorDumper.dump(moduleDescriptor, { dumpDir }); + } catch (e: any) { + e.message = 'dump module descriptor failed: ' + e.message; + opts.logger?.warn(e); + } + } + } + + static #moduleDescriptorId(moduleReference: ModuleReference): string { + return `${moduleReference.name}@${moduleReference.path}`; + } +} diff --git a/standalone/standalone/src/StandaloneContextImpl.ts b/standalone/standalone/src/StandaloneContextImpl.ts deleted file mode 100644 index 56b49cb0..00000000 --- a/standalone/standalone/src/StandaloneContextImpl.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { AbstractEggContext } from '@eggjs/tegg-runtime'; -import { IdenticalUtil } from '@eggjs/tegg'; - -export class StandaloneContextImpl extends AbstractEggContext { - readonly id: string; - - constructor() { - super(); - this.id = IdenticalUtil.createContextId(); - } -} diff --git a/standalone/standalone/src/StandaloneLoadUnit.ts b/standalone/standalone/src/StandaloneLoadUnit.ts deleted file mode 100644 index 5e054b8a..00000000 --- a/standalone/standalone/src/StandaloneLoadUnit.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { EggPrototype, EggPrototypeFactory, LoadUnit } from '@eggjs/tegg-metadata'; -import { EggPrototypeName, ObjectInitType, QualifierInfo } from '@eggjs/tegg'; -import { MapUtil } from '@eggjs/tegg-common-util'; -import { IdenticalUtil } from '@eggjs/tegg-lifecycle'; -import { StandaloneInnerObjectProto } from './StandaloneInnerObjectProto'; - -export const StandaloneLoadUnitType = 'StandaloneLoadUnitType'; - -export interface InnerObject { - obj: object, - qualifiers?: QualifierInfo[], -} - -export class StandaloneLoadUnit implements LoadUnit { - readonly id: string = 'StandaloneLoadUnit'; - readonly name: string = 'StandaloneLoadUnit'; - readonly unitPath: string = 'MockStandaloneLoadUnitPath'; - readonly type = StandaloneLoadUnitType; - - private innerObject: Record; - private protoMap: Map = new Map(); - - constructor(innerObject: Record) { - this.innerObject = innerObject; - } - - async init() { - for (const [ name, objs ] of Object.entries(this.innerObject)) { - for (const { obj, qualifiers } of objs) { - const proto = new StandaloneInnerObjectProto( - IdenticalUtil.createProtoId(this.id, name), - name, - (() => obj) as any, - ObjectInitType.SINGLETON, - this.id, - qualifiers || [], - ); - EggPrototypeFactory.instance.registerPrototype(proto, this); - } - } - } - - containPrototype(proto: EggPrototype): boolean { - return !!(this.protoMap.get(proto.name)?.find(t => t === proto)); - } - - getEggPrototype(name: string, qualifiers: QualifierInfo[]): EggPrototype[] { - const protos = this.protoMap.get(name); - return protos?.filter(proto => proto.verifyQualifiers(qualifiers)) || []; - } - - registerEggPrototype(proto: EggPrototype) { - const protoList = MapUtil.getOrStore(this.protoMap, proto.name, []); - protoList.push(proto); - } - - deletePrototype(proto: EggPrototype) { - const protos = this.protoMap.get(proto.name); - if (protos) { - const index = protos.indexOf(proto); - if (index !== -1) { - protos.splice(index, 1); - } - } - } - - async destroy() { - for (const namedProtoMap of this.protoMap.values()) { - for (const proto of namedProtoMap.values()) { - EggPrototypeFactory.instance.deletePrototype(proto, this); - } - } - this.protoMap.clear(); - } - - iterateEggPrototype(): IterableIterator { - const protos: EggPrototype[] = Array.from(this.protoMap.values()) - .reduce((p, c) => { - p = p.concat(c); - return p; - }, []); - return protos.values(); - } -} diff --git a/standalone/standalone/src/common/constant.ts b/standalone/standalone/src/common/constant.ts new file mode 100644 index 00000000..24d8cb7e --- /dev/null +++ b/standalone/standalone/src/common/constant.ts @@ -0,0 +1,4 @@ +export const StandaloneLoadUnitType = 'StandaloneLoadUnitType'; +export const StandaloneLoadUnitId = 'StandaloneLoadUnit'; +export const StandaloneLoadUnitName = 'StandaloneLoadUnit'; +export const StandaloneLoadUnitPath = 'MockStandaloneLoadUnitPath'; diff --git a/standalone/standalone/src/common/types/index.ts b/standalone/standalone/src/common/types/index.ts new file mode 100644 index 00000000..5058ca59 --- /dev/null +++ b/standalone/standalone/src/common/types/index.ts @@ -0,0 +1,10 @@ +import { QualifierInfo, ReadModuleReferenceOptions } from '@eggjs/tegg-types'; + +export interface InnerObject { + obj: object, + qualifiers?: QualifierInfo[], +} + +export interface ModuleDependency extends ReadModuleReferenceOptions { + baseDir: string; +} diff --git a/standalone/standalone/src/common/utils/Timing.ts b/standalone/standalone/src/common/utils/Timing.ts new file mode 100644 index 00000000..7a9b0e0b --- /dev/null +++ b/standalone/standalone/src/common/utils/Timing.ts @@ -0,0 +1,55 @@ +import { getProfiler } from 'time-profile'; + +export class Timing { + static #profile?: any; + + static enable(profile: string | any) { + if (typeof profile === 'string') { + Timing.#profile = getProfiler(profile); + } else if (typeof profile === 'object') { + Timing.#profile = profile; + } + } + + static start(name: string) { + this.#profile?.start(name); + + return { + end: () => this.end(name), + }; + } + + static end(name: string) { + this.#profile?.end(name); + } + + static profile any>(fn: F, name: string): ReturnType { + if (!this.#profile) { + return fn(); + } + return this.#profile.profileTagged(fn, name); + } + + static toString(destroy?: boolean) { + const str = this.#profile?.toString(); + if (destroy) { + this.#profile?.destroy(); + } + return str; + } +} + +export function TimeProfile() { + return function(_: any, propertyKey: string, descriptor: TypedPropertyDescriptor) { + const originalMethod = descriptor.value!; + + descriptor.value = function(this: any, ...args: any[]) { + try { + Timing.start(propertyKey); + return originalMethod.apply(this, args); + } finally { + Timing.end(propertyKey); + } + }; + }; +} diff --git a/standalone/standalone/src/initializer/ModuleLoadUnitInitializer.ts b/standalone/standalone/src/initializer/ModuleLoadUnitInitializer.ts new file mode 100644 index 00000000..52448df4 --- /dev/null +++ b/standalone/standalone/src/initializer/ModuleLoadUnitInitializer.ts @@ -0,0 +1,75 @@ +import { + EggLoadUnitType, + GlobalGraph, + GlobalModuleNode, + LoadUnit, + LoadUnitFactory, +} from '@eggjs/tegg-metadata'; +import { LoaderFactory } from '@eggjs/tegg-loader'; +import { StandaloneClassLoader } from '../StandaloneClassLoader'; +import { ModuleReference } from '@eggjs/tegg-types'; +import { Timing } from '../common/utils/Timing'; + +export interface ModuleLoadUnitInitializerInit { + globalGraph?: GlobalGraph; + classLoader: StandaloneClassLoader; +} + +export class ModuleLoadUnitInitializer { + readonly #globalGraph: GlobalGraph; + readonly #classLoader: StandaloneClassLoader; + + constructor(init: ModuleLoadUnitInitializerInit) { + this.#globalGraph = init.globalGraph || new GlobalGraph(); + this.#classLoader = init.classLoader; + } + + addModule(moduleReference: ModuleReference) { + const descriptor = this.#classLoader.loadModule(moduleReference); + const moduleNode = new GlobalModuleNode({ + name: descriptor.name, + unitPath: descriptor.unitPath, + optional: descriptor.optional ?? false, + }); + + for (const clazz of descriptor.clazzList) { + moduleNode.addProtoByClazz(clazz); + } + + this.#globalGraph.addModuleNode(moduleNode); + } + + #buildMultiInstanceProtos() { + const multiInstanceClassDefinitions = this.#classLoader.getMultiInstanceClassDefinitions(); + for (const definition of multiInstanceClassDefinitions) { + for (const moduleNode of this.#globalGraph.moduleGraph.nodes.values()) { + const added = moduleNode.val.addProtoByMultiInstanceClazz(definition.clazz, definition.defineModuleName, definition.defineUnitPath); + + for (const protoNode of added) { + this.#globalGraph.addProtoNode(protoNode); + } + } + } + } + + #buildGlobalGraph() { + this.#buildMultiInstanceProtos(); + this.#globalGraph.build(); + this.#globalGraph.sort(); + return this.#globalGraph.moduleConfigList; + } + + async createModuleLoadUnits() { + const moduleReferences = Timing.profile(() => this.#buildGlobalGraph(), 'buildGlobalGraph'); + + const loadUnits: LoadUnit[] = []; + for (const reference of moduleReferences) { + const modulePath = reference.path; + const loader = LoaderFactory.createLoader(modulePath, EggLoadUnitType.MODULE); + const loadUnit = await LoadUnitFactory.createLoadUnit(modulePath, EggLoadUnitType.MODULE, loader); + loadUnits.push(loadUnit); + } + + return loadUnits; + } +} diff --git a/standalone/standalone/src/initializer/StandaloneLoadUnitInitializer.ts b/standalone/standalone/src/initializer/StandaloneLoadUnitInitializer.ts new file mode 100644 index 00000000..b6b45911 --- /dev/null +++ b/standalone/standalone/src/initializer/StandaloneLoadUnitInitializer.ts @@ -0,0 +1,77 @@ +import { EggProtoImplClass } from '@eggjs/tegg-types'; +import { Graph, GraphNode, ModuleReference } from '@eggjs/tegg-common-util'; +import { + LoadUnitFactory, + ProtoDependencyMeta, + ProtoDescriptorHelper, + ProtoGraphUtils, + ProtoNode, +} from '@eggjs/tegg-metadata'; +import { StandaloneClassLoader } from '../StandaloneClassLoader'; +import { InnerObject } from '../common/types'; +import { StandaloneLoadUnitName, StandaloneLoadUnitPath, StandaloneLoadUnitType } from '../common/constant'; +import { StandaloneLoadUnit } from '../loadUnit/StandaloneLoadUnit'; +import { Timing } from '../common/utils/Timing'; + +export interface StandaloneLoadUnitInitializerOptions { + classLoader: StandaloneClassLoader; +} + +export interface CreateStandaloneLoadUnitOptions { + innerObjects: Record; +} + +export class StandaloneLoadUnitInitializer { + readonly #protoGraph: Graph; + readonly #classLoader: StandaloneClassLoader; + + constructor(opts: StandaloneLoadUnitInitializerOptions) { + this.#protoGraph = new Graph(); + this.#classLoader = opts.classLoader; + } + + addInnerObjectProto(moduleReference: ModuleReference) { + const classList = this.#classLoader.getInnerObjectClass(moduleReference); + for (const clazz of classList) { + const descriptor = ProtoDescriptorHelper.createByInstanceClazz(clazz, { + moduleName: StandaloneLoadUnitName, + unitPath: StandaloneLoadUnitPath, + defineModuleName: moduleReference.name, + defineUnitPath: moduleReference.path, + }); + const protoGraphNode = new GraphNode(new ProtoNode(descriptor)); + this.#protoGraph.addVertex(protoGraphNode); + } + } + + #buildProtoGraph() { + for (const protoNode of this.#protoGraph.nodes.values()) { + for (const injectObj of protoNode.val.proto.injectObjects) { + const injectProto = ProtoGraphUtils.findDependencyProtoNode(this.#protoGraph, protoNode.val.proto, injectObj); + if (!injectProto) { + continue; + } + this.#protoGraph.addEdge(protoNode, injectProto, new ProtoDependencyMeta({ injectObj: injectObj.objName })); + } + } + const loopPath = this.#protoGraph.loopPath(); + if (loopPath) { + throw new Error('innerObjectProto has recursive deps: ' + loopPath); + } + + return this.#protoGraph.sort(); + } + + async createLoadUnit(opts: CreateStandaloneLoadUnitOptions) { + const protos = Timing.profile(() => this.#buildProtoGraph(), 'buildInnerObjectProtoGraph').map(n => n.val.proto); + LoadUnitFactory.registerLoadUnitCreator(StandaloneLoadUnitType, () => { + return new StandaloneLoadUnit(opts.innerObjects, protos); + }); + + return await LoadUnitFactory.createLoadUnit(StandaloneLoadUnitPath, StandaloneLoadUnitType, { + load(): EggProtoImplClass[] { + return []; + }, + }); + } +} diff --git a/standalone/standalone/src/loadUnit/StandaloneLoadUnit.ts b/standalone/standalone/src/loadUnit/StandaloneLoadUnit.ts new file mode 100644 index 00000000..29c35867 --- /dev/null +++ b/standalone/standalone/src/loadUnit/StandaloneLoadUnit.ts @@ -0,0 +1,99 @@ +import { + ClassProtoDescriptor, + EggPrototype, + EggPrototypeCreatorFactory, + EggPrototypeFactory, + LoadUnit, + ProtoDescriptor, +} from '@eggjs/tegg-metadata'; +import { MapUtil } from '@eggjs/tegg-common-util'; +import { IdenticalUtil } from '@eggjs/tegg-lifecycle'; +import { EggPrototypeName, ObjectInitType, QualifierInfo } from '@eggjs/tegg-types'; +import { StandaloneInnerObjectProto } from '../StandaloneInnerObjectProto'; +import { InnerObject } from '../common/types'; +import { + StandaloneLoadUnitId, + StandaloneLoadUnitName, + StandaloneLoadUnitPath, + StandaloneLoadUnitType, +} from '../common/constant'; + +export class StandaloneLoadUnit implements LoadUnit { + readonly id: string = StandaloneLoadUnitId; + readonly name: string = StandaloneLoadUnitName; + readonly unitPath: string = StandaloneLoadUnitPath; + readonly type = StandaloneLoadUnitType; + + #innerObject: Record; + #protos: ProtoDescriptor[]; + #protoMap: Map = new Map(); + + constructor(innerObject: Record, protos?: ProtoDescriptor[]) { + this.#innerObject = innerObject; + this.#protos = protos || []; + } + + async init() { + for (const [ name, objs ] of Object.entries(this.#innerObject)) { + for (const { obj, qualifiers } of objs) { + const proto = new StandaloneInnerObjectProto( + IdenticalUtil.createProtoId(this.id, name), + name, + (() => obj) as any, + ObjectInitType.SINGLETON, + this.id, + qualifiers || [], + ); + EggPrototypeFactory.instance.registerPrototype(proto, this); + } + } + + const protos = this.#protos.filter(t => ClassProtoDescriptor.isClassProtoDescriptor(t)); + for (const protoDescriptor of protos) { + const proto = await EggPrototypeCreatorFactory.createProtoByDescriptor(protoDescriptor, this); + EggPrototypeFactory.instance.registerPrototype(proto, this); + } + } + + containPrototype(proto: EggPrototype): boolean { + return !!(this.#protoMap.get(proto.name)?.find(t => t === proto)); + } + + getEggPrototype(name: string, qualifiers: QualifierInfo[]): EggPrototype[] { + const protos = this.#protoMap.get(name); + return protos?.filter(proto => proto.verifyQualifiers(qualifiers)) || []; + } + + registerEggPrototype(proto: EggPrototype) { + const protoList = MapUtil.getOrStore(this.#protoMap, proto.name, []); + protoList.push(proto); + } + + deletePrototype(proto: EggPrototype) { + const protos = this.#protoMap.get(proto.name); + if (protos) { + const index = protos.indexOf(proto); + if (index !== -1) { + protos.splice(index, 1); + } + } + } + + async destroy() { + for (const namedProtoMap of this.#protoMap.values()) { + for (const proto of Array.from(namedProtoMap)) { + EggPrototypeFactory.instance.deletePrototype(proto, this); + } + } + this.#protoMap.clear(); + } + + iterateEggPrototype(): IterableIterator { + const protos: EggPrototype[] = Array.from(this.#protoMap.values()) + .reduce((p, c) => { + p = p.concat(c); + return p; + }, []); + return protos.values(); + } +} diff --git a/standalone/standalone/src/loadUnit/StandaloneLoadUnitInstance.ts b/standalone/standalone/src/loadUnit/StandaloneLoadUnitInstance.ts new file mode 100644 index 00000000..e4e45cd3 --- /dev/null +++ b/standalone/standalone/src/loadUnit/StandaloneLoadUnitInstance.ts @@ -0,0 +1,60 @@ +import { EggLifecycleInfo, PrototypeUtil } from '@eggjs/core-decorator'; +import { EggPrototypeLifecycleUtil, LoadUnitLifecycleUtil } from '@eggjs/tegg-metadata'; +import { + EggContextLifecycleUtil, + EggObjectLifecycleUtil, + type LoadUnitInstance, + LoadUnitInstanceFactory, + type LoadUnitInstanceLifecycleContext, + LoadUnitInstanceLifecycleUtil, + ModuleLoadUnitInstance, +} from '@eggjs/tegg-runtime'; +import { StandaloneLoadUnitType } from '../common/constant'; +import { LifecycleUtil } from '@eggjs/tegg-lifecycle'; + +export class StandaloneLoadUnitInstance extends ModuleLoadUnitInstance { + static LifecycleUtils: Record> = { + LoadUnit: LoadUnitLifecycleUtil, + LoadUnitInstance: LoadUnitInstanceLifecycleUtil, + EggPrototype: EggPrototypeLifecycleUtil, + EggObject: EggObjectLifecycleUtil, + EggContext: EggContextLifecycleUtil, + }; + + readonly #lifecycleObjects: [string, object][] = []; + + async init(ctx: LoadUnitInstanceLifecycleContext): Promise { + await super.init(ctx); + + for (const [ name, proto ] of this.iterateProtoToCreate()) { + const isLifecycleProto = proto.getMetaData(PrototypeUtil.IS_EGG_LIFECYCLE_PROTOTYPE); + const lifecycleInfo = proto.getMetaData(PrototypeUtil.EGG_LIFECYCLE_PROTOTYPE_METADATA); + if (isLifecycleProto && lifecycleInfo?.type) { + const lifecycle = this.getEggObject(name, proto).obj; + const lifecycleUtil = StandaloneLoadUnitInstance.LifecycleUtils[lifecycleInfo.type]; + if (!lifecycleUtil) { + throw new Error(`register lifecycle failed, unknown type ${lifecycleInfo.type}`); + } + lifecycleUtil.registerLifecycle(lifecycle); + this.#lifecycleObjects.push([ lifecycleInfo.type, lifecycle ]); + } + } + } + + async destroy(): Promise { + let toBeDeleted = this.#lifecycleObjects.shift(); + while (toBeDeleted) { + const [ type, lifecycle ] = toBeDeleted; + StandaloneLoadUnitInstance.LifecycleUtils[type]?.deleteLifecycle(lifecycle); + toBeDeleted = this.#lifecycleObjects.shift(); + } + + await super.destroy(); + } + + static createStandaloneLoadUnitInstance(ctx: LoadUnitInstanceLifecycleContext): LoadUnitInstance { + return new StandaloneLoadUnitInstance(ctx.loadUnit); + } +} + +LoadUnitInstanceFactory.registerLoadUnitInstanceClass(StandaloneLoadUnitType, StandaloneLoadUnitInstance.createStandaloneLoadUnitInstance); diff --git a/standalone/standalone/src/main.ts b/standalone/standalone/src/main.ts index 6b6a3404..7afcf685 100644 --- a/standalone/standalone/src/main.ts +++ b/standalone/standalone/src/main.ts @@ -1,4 +1,6 @@ +import { InitStandaloneAppOptions, StandaloneApp, StandaloneAppInit } from './StandaloneApp'; import { Runner, RunnerOptions } from './Runner'; +import type { EggContext } from '@eggjs/tegg-runtime'; export async function preLoad(cwd: string, dependencies?: RunnerOptions['dependencies']) { try { @@ -26,3 +28,21 @@ export async function main(cwd: string, options?: RunnerOptions): Prom }); } } + +export async function appMain(options: InitStandaloneAppOptions, init?: StandaloneAppInit, ctx?: EggContext): Promise { + const app = new StandaloneApp(init); + try { + await app.init(options); + } catch (e) { + e.message = `[tegg/standalone] bootstrap tegg failed: ${e.message}`; + throw e; + } + try { + return await app.run(ctx); + } finally { + app.destroy().catch(e => { + e.message = `[tegg/standalone] destroy tegg failed: ${e.message}`; + console.warn(e); + }); + } +} diff --git a/standalone/standalone/test/Ajv.test.ts b/standalone/standalone/test/Ajv.test.ts new file mode 100644 index 00000000..36d8eb04 --- /dev/null +++ b/standalone/standalone/test/Ajv.test.ts @@ -0,0 +1,46 @@ +import { strict as assert } from 'node:assert'; +import path from 'node:path'; +import { StandAloneAppTest } from './Utils'; + +describe('standalone/standalone/test/Ajv.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should throw AjvInvalidParamError', async () => { + await assert.rejects( + async () => + await StandAloneAppTest.run('ajv-module', { + frameworkDeps: [ + path.dirname(require.resolve('@eggjs/tegg-ajv-plugin/package.json')), + ], + }), + (err: any) => { + assert.equal(err.name, 'AjvInvalidParamError'); + assert.equal(err.message, 'Validation Failed'); + assert.deepEqual(err.errorData, {}); + assert.equal(err.currentSchema, '{"type":"object","properties":{"fullname":{"transform":["trim"],"maxLength":100,"type":"string"},"skipDependencies":{"type":"boolean"},"registryName":{"type":"string"}},"required":["fullname","skipDependencies"]}'); + assert.deepEqual(err.errors, [ + { + instancePath: '', + schemaPath: '#/required', + keyword: 'required', + params: { + missingProperty: 'fullname', + }, + message: "must have required property 'fullname'", + }, + ]); + return true; + }); + }); + + it('should pass', async () => { + const result = await StandAloneAppTest.run('ajv-module-pass', { + frameworkDeps: [ + path.dirname(require.resolve('@eggjs/tegg-ajv-plugin/package.json')), + ], + }); + assert.equal(result, '{"body":{"fullname":"mock fullname","skipDependencies":true,"registryName":"ok"}}'); + }); +}); diff --git a/standalone/standalone/test/Aop.test.ts b/standalone/standalone/test/Aop.test.ts new file mode 100644 index 00000000..1cfaffc0 --- /dev/null +++ b/standalone/standalone/test/Aop.test.ts @@ -0,0 +1,23 @@ +import { strict as assert } from 'node:assert'; +import path from 'node:path'; +import { StandAloneAppTest } from './Utils'; + +describe('standalone/standalone/test/aop.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should work', async () => { + const msg = await StandAloneAppTest.run('aop-module'); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { crosscutAdviceParams, pointcutAdviceParams } = require(path.join(StandAloneAppTest.baseDir('aop-module'), 'Hello')); + assert.deepEqual(msg, + 'withCrossAroundResult(' + + 'withPointAroundResult(' + + `hello withPointAroundParam(withCrosscutAroundParam(aop))${JSON.stringify(pointcutAdviceParams)}` + + ')' + + `${JSON.stringify(crosscutAdviceParams)}` + + ')', + ); + }); +}); diff --git a/standalone/standalone/test/Dal.test.ts b/standalone/standalone/test/Dal.test.ts new file mode 100644 index 00000000..6a702b5d --- /dev/null +++ b/standalone/standalone/test/Dal.test.ts @@ -0,0 +1,26 @@ +import { strict as assert } from 'node:assert'; +import { StandAloneAppTest } from './Utils'; +import { Foo } from './fixtures/dal-module/src/Foo'; + +describe('standalone/standalone/test/Dal.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should work', async () => { + const foo = await StandAloneAppTest.run('dal-module', 'unittest'); + assert.equal(foo.col1, '2333'); + }); + + it('should transaction work', async () => { + const foo = await StandAloneAppTest.run>>('dal-transaction-module', 'unittest'); + // insert_succeed_transaction_1 + assert.equal(foo[0].length, 1); + // insert_succeed_transaction_2 + assert.equal(foo[1].length, 1); + // insert_failed_transaction_1 + assert.equal(foo[2].length, 0); + // insert_failed_transaction_2 + assert.equal(foo[3].length, 0); + }); +}); diff --git a/standalone/standalone/test/Inject.test.ts b/standalone/standalone/test/Inject.test.ts new file mode 100644 index 00000000..339e89b4 --- /dev/null +++ b/standalone/standalone/test/Inject.test.ts @@ -0,0 +1,40 @@ +import { strict as assert } from 'node:assert'; +import path from 'node:path'; +import { StandAloneAppTest } from './Utils'; +import { EggPrototypeNotFound } from '@eggjs/tegg-metadata'; + +describe('standalone/standalone/test/Inject.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should optional work', async () => { + const nil = await StandAloneAppTest.run('optional-inject'); + assert.equal(nil, true); + }); + + it('should throw error if no proto found', async () => { + await assert.rejects( + StandAloneAppTest.run('invalid-inject'), + (e: any) => + e instanceof EggPrototypeNotFound + && /Object doesNotExist not found in LOAD_UNIT:invalidInject/.test(e.message), + ); + }); + + describe('dynamic inject', () => { + it('should work', async () => { + const msg = await StandAloneAppTest.run('dynamic-inject-module', { + frameworkDeps: [ + { baseDir: path.join(__dirname, '..'), extraFilePattern: [ '!**/test' ] }, + ], + }); + assert.deepEqual(msg, [ + 'hello, foo(context:0)', + 'hello, bar(context:0)', + 'hello, foo(singleton:0)', + 'hello, bar(singleton:0)', + ]); + }); + }); +}); diff --git a/standalone/standalone/test/InnerObjectProto.test.ts b/standalone/standalone/test/InnerObjectProto.test.ts new file mode 100644 index 00000000..d83995e7 --- /dev/null +++ b/standalone/standalone/test/InnerObjectProto.test.ts @@ -0,0 +1,23 @@ +import { strict as assert } from 'node:assert'; +import { StandAloneAppTest } from './Utils'; +import { EggPrototypeNotFound } from '@eggjs/tegg-metadata'; + +describe('standalone/standalone/test/InnerObjectProto.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should throw error if inject innerObject by default', async () => { + await assert.rejects( + StandAloneAppTest.run('invalid-inner-object-inject'), + (e: any) => + e instanceof EggPrototypeNotFound + && /Object innerBar not found in LOAD_UNIT:invalidInnerObjectInject/.test(e.message), + ); + }); + + it('should inject innerObject work when accessLevel is public', async () => { + const message = await StandAloneAppTest.run('inner-object-proto'); + assert.equal(message, 'with inner bar and inner foo'); + }); +}); diff --git a/standalone/standalone/test/Lifecycle.test.ts b/standalone/standalone/test/Lifecycle.test.ts new file mode 100644 index 00000000..3e80754f --- /dev/null +++ b/standalone/standalone/test/Lifecycle.test.ts @@ -0,0 +1,21 @@ +import { strict as assert } from 'node:assert'; +import { StandAloneAppTest } from './Utils'; + +describe('standalone/standalone/test/Lifecycle.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should object lifecycle work', async () => { + const res = await StandAloneAppTest.run('lifecycle'); + assert.deepEqual(res, [ + 'construct', + 'postConstruct', + 'preInject', + 'postInject', + 'init', + 'preDestroy', + 'destroy', + ]); + }); +}); diff --git a/standalone/standalone/test/LifecycleProto.test.ts b/standalone/standalone/test/LifecycleProto.test.ts new file mode 100644 index 00000000..41597dfb --- /dev/null +++ b/standalone/standalone/test/LifecycleProto.test.ts @@ -0,0 +1,33 @@ +import { strict as assert } from 'node:assert'; +import { StandAloneAppTest } from './Utils'; + +describe('standalone/standalone/test/lifecycleProto.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should LoadUnitLifecycleProto work', async () => { + const msg: string = await StandAloneAppTest.run('load-unit-lifecycle-proto'); + assert.equal(msg, 'dynamic bar name|foo fake name'); + }); + + it('should LoadUnitInstanceLifecycleProto work', async () => { + const count: number = await StandAloneAppTest.run('load-unit-instance-lifecycle-proto'); + assert.equal(count, 66); + }); + + it('should EggObjectLifecycleProto work', async () => { + const msg: string = await StandAloneAppTest.run('egg-object-lifecycle-proto'); + assert.equal(msg, 'foo message from FooEggObjectHook'); + }); + + it('should EggPrototypeLifecycleProto work', async () => { + const msg: string = await StandAloneAppTest.run('egg-prototype-lifecycle-proto'); + assert.equal(msg, 'class name is Foo'); + }); + + it('should EggContextLifecycleProto work', async () => { + const msg: string = await StandAloneAppTest.run('egg-context-lifecycle-proto'); + assert.equal(msg, 'Y'); + }); +}); diff --git a/standalone/standalone/test/ModuleConfig.test.ts b/standalone/standalone/test/ModuleConfig.test.ts new file mode 100644 index 00000000..0b17a584 --- /dev/null +++ b/standalone/standalone/test/ModuleConfig.test.ts @@ -0,0 +1,73 @@ +import { strict as assert } from 'node:assert'; +import { ModuleConfig, ModuleConfigs } from '@eggjs/tegg/helper'; +import { StandAloneAppTest } from './Utils'; + +describe('standalone/standalone/test/ModuleConfig.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should work', async () => { + const config: object = await StandAloneAppTest.run('module-with-config'); + assert.deepEqual(config, { + features: { + dynamic: { + foo: 'bar', + }, + }, + }); + }); + + it('should work with env', async () => { + const config: object = await StandAloneAppTest.run('module-with-env-config', 'dev'); + assert.deepEqual(config, { + features: { + dynamic: { + foo: 'foo', + }, + }, + }); + }); + + describe('@ConfigSourceQualifier', () => { + type ConfigResult = { + configs: ModuleConfigs, + foo: ModuleConfig, + bar: ModuleConfig, + configFromBar: ModuleConfig, + }; + + it('should set by default', async () => { + const { configs, foo, configFromBar } = await StandAloneAppTest.run('multi-modules'); + + assert.deepEqual(foo, { + features: { + dynamic: { + foo: 'bar', + }, + }, + }); + assert.deepEqual(configFromBar, { + features: { + dynamic: { + bar: 'bar', + }, + }, + }); + assert.deepEqual(configs.get('foo'), foo); + assert.deepEqual(configs.get('bar'), configFromBar); + }); + + it('should use @ConfigSourceQualifier manually work', async () => { + const { configs, bar } = await StandAloneAppTest.run('multi-modules'); + assert.deepEqual(bar, { + features: { + dynamic: { + bar: 'bar', + }, + }, + }); + assert.deepEqual(configs.get('bar'), bar); + }); + }); +}); diff --git a/standalone/standalone/test/MultiInstanceProto.test.ts b/standalone/standalone/test/MultiInstanceProto.test.ts new file mode 100644 index 00000000..2aa45aae --- /dev/null +++ b/standalone/standalone/test/MultiInstanceProto.test.ts @@ -0,0 +1,31 @@ +import { strict as assert } from 'node:assert'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { StandAloneAppTest } from './Utils'; + +describe('standalone/standalone/test/MultiInstanceProto.test.ts', () => { + const name = 'multi-callback-instance-module'; + const fixturePath = StandAloneAppTest.baseDir(name); + + afterEach(async () => { + await fs.unlink(path.join(fixturePath, 'main', 'foo.log')); + await fs.unlink(path.join(fixturePath, 'main', 'bar.log')); + await fs.unlink(path.join(fixturePath, 'biz', 'fooBiz.log')); + await fs.unlink(path.join(fixturePath, 'biz', 'barBiz.log')); + + await StandAloneAppTest.removeFixtureTmp(); + }); + + it('should work', async () => { + await StandAloneAppTest.run(name); + const fooContent = await fs.readFile(path.join(fixturePath, 'main', 'foo.log'), 'utf8'); + const barContent = await fs.readFile(path.join(fixturePath, 'main', 'bar.log'), 'utf8'); + assert(fooContent.includes('hello, foo')); + assert(barContent.includes('hello, bar')); + + const fooBizContent = await fs.readFile(path.join(fixturePath, 'biz', 'fooBiz.log'), 'utf8'); + const barBizContent = await fs.readFile(path.join(fixturePath, 'biz', 'barBiz.log'), 'utf8'); + assert(fooBizContent.includes('hello, foo biz')); + assert(barBizContent.includes('hello, bar biz')); + }); +}); diff --git a/standalone/standalone/test/index.test.ts b/standalone/standalone/test/Runner.test.ts similarity index 99% rename from standalone/standalone/test/index.test.ts rename to standalone/standalone/test/Runner.test.ts index 00e73494..670a1995 100644 --- a/standalone/standalone/test/index.test.ts +++ b/standalone/standalone/test/Runner.test.ts @@ -8,11 +8,11 @@ import { main, StandaloneContext, Runner, preLoad } from '..'; import { crosscutAdviceParams, pointcutAdviceParams } from './fixtures/aop-module/Hello'; import { Foo } from './fixtures/dal-module/src/Foo'; -describe('standalone/standalone/test/index.test.ts', () => { +describe('standalone/standalone/test/Runner.test.ts', () => { describe('simple runner', () => { const fixture = path.join(__dirname, './fixtures/simple'); - beforeEach(() => { + beforeEach(async () => { mm.restore(); mm.spy(ModuleDescriptorDumper, 'dump'); }); diff --git a/standalone/standalone/test/StandaloneApp.test.ts b/standalone/standalone/test/StandaloneApp.test.ts new file mode 100644 index 00000000..20d05e95 --- /dev/null +++ b/standalone/standalone/test/StandaloneApp.test.ts @@ -0,0 +1,82 @@ +import { strict as assert } from 'node:assert'; +import path from 'node:path'; +import { setTimeout as sleep } from 'node:timers/promises'; +import mm from 'mm'; +import { ModuleDescriptorDumper } from '@eggjs/tegg-metadata'; +import { appMain } from '../src/main'; +import { StandaloneContext } from '../src/StandaloneContext'; +import { StandAloneAppTest } from './Utils'; + +describe('standalone/standalone/test/StandaloneApp.test.ts', () => { + afterEach(async () => { + await StandAloneAppTest.removeFixtureTmp(); + }); + + describe('simple runner', () => { + beforeEach(() => { + mm.restore(); + mm.spy(ModuleDescriptorDumper, 'dump'); + }); + + it('should work', async () => { + const msg: string = await StandAloneAppTest.run('simple'); + assert.equal(msg, 'hello!hello from ctx'); + await sleep(500); + assert.equal((ModuleDescriptorDumper.dump as any).called, 1); + }); + + it('should not dump', async () => { + await StandAloneAppTest.run('simple', { dump: false }); + await sleep(500); + assert.equal((ModuleDescriptorDumper.dump as any).called, undefined); + }); + }); + + describe('StandaloneAppInit', () => { + it('should frameworkDeps work', async () => { + const baseDir = StandAloneAppTest.baseDir('dependency'); + const msg: string = await StandAloneAppTest.run('dependency', { + frameworkDeps: [ + path.join(baseDir, './node_modules/dependency-1'), + ], + }); + assert.equal(msg, 'hello!{"features":{"dynamic":{"foo":"bar"}}}'); + }); + + it('should innerObjects work', async () => { + const obj = { + hello() { + return 'hello, inner'; + }, + }; + const msg: string = await StandAloneAppTest.run('inner-object', { + innerObjects: { hello: [{ obj }] }, + }); + assert.equal(msg, 'hello, inner'); + }); + }); + + describe('run', () => { + it('should work with custom context', async () => { + await StandAloneAppTest.copyFixture('custom-context'); + + const value = 'foo' + Date.now(); + const ctx = new StandaloneContext(); + ctx.set('foo', value); + + const msg: string = await appMain(StandAloneAppTest.initOpts('custom-context'), {}, ctx); + assert.equal(msg, value); + }); + }); + + describe('runtimeConfig', () => { + it('should work', async () => { + const res: object = await StandAloneAppTest.run('runtime-config', 'unittest'); + assert.deepEqual(res, { + baseDir: StandAloneAppTest.baseDir('runtime-config'), + name: 'runtime-config', + env: 'unittest', + }); + }); + }); +}); diff --git a/standalone/standalone/test/Utils.ts b/standalone/standalone/test/Utils.ts new file mode 100644 index 00000000..90adc132 --- /dev/null +++ b/standalone/standalone/test/Utils.ts @@ -0,0 +1,86 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { StandaloneApp, StandaloneAppInit } from '../src/StandaloneApp'; + +export class StandAloneAppTest { + static async fileExists(filePath: string): Promise { + try { + return !!await fs.stat(filePath); + } catch (err: any) { + return false; + } + } + + static async copyFixture(name: string) { + const tmpPath = await StandAloneAppTest.emptyFixtureTmp(); + const fixturePath = path.join(__dirname, 'fixtures', name); + const targetFixturePath = path.join(tmpPath, name); + await fs.cp(fixturePath, targetFixturePath, { recursive: true }); + return targetFixturePath; + } + + static async emptyFixtureTmp() { + const tmpPath = await StandAloneAppTest.removeFixtureTmp(); + await fs.mkdir(tmpPath); + return tmpPath; + } + + static async removeFixtureTmp() { + const tmpPath = path.join(__dirname, 'fixtures', 'tmp'); + if (await StandAloneAppTest.fileExists(tmpPath)) { + await fs.rm(tmpPath, { recursive: true, force: true }); + } + return tmpPath; + } + + static baseDir(name: string) { + return path.join(__dirname, 'fixtures', 'tmp', name); + } + + static initOpts(name: string, env?: string) { + return { + baseDir: StandAloneAppTest.baseDir(name), + env, + name, + }; + } + + static async createApp(name: string, init?: StandaloneAppInit): Promise; + static async createApp(name: string, env?: string, init?: StandaloneAppInit): Promise; + static async createApp(name: string, envOrInit?: StandaloneAppInit | string, init?: StandaloneAppInit): Promise { + if (typeof envOrInit === 'string') { + const app = new StandaloneApp(init); + await app.init(StandAloneAppTest.initOpts(name, envOrInit)); + return app; + } + const app = new StandaloneApp(envOrInit); + try { + await app.init(StandAloneAppTest.initOpts(name)); + } catch (e) { + await app.destroy().catch(e => { + e.message = `[tegg/standalone] destroy tegg failed: ${e.message}`; + console.warn(e); + }); + throw e; + } + return app; + } + + static async run(name: string, init?: StandaloneAppInit): Promise; + static async run(name: string, env?: string, init?: StandaloneAppInit): Promise; + static async run(name: string, env?: StandaloneAppInit | string, init?: StandaloneAppInit): Promise { + await StandAloneAppTest.copyFixture(name); + + const app = typeof env === 'string' + ? await StandAloneAppTest.createApp(name, env, init) + : await StandAloneAppTest.createApp(name, env); + try { + return await app.run(); + } finally { + await app.destroy().catch(e => { + e.message = `[tegg/standalone] destroy tegg failed: ${e.message}`; + console.warn(e); + }); + } + } +} diff --git a/standalone/standalone/test/fixtures/dal-module/src/main.ts b/standalone/standalone/test/fixtures/dal-module/src/main.ts index 4b693350..5954cd4d 100644 --- a/standalone/standalone/test/fixtures/dal-module/src/main.ts +++ b/standalone/standalone/test/fixtures/dal-module/src/main.ts @@ -3,7 +3,6 @@ import { Runner, MainRunner } from '@eggjs/tegg/standalone'; import FooDAO from './dal/dao/FooDAO'; import { Foo } from './Foo'; - @Runner() @ContextProto() export class FooRunner implements MainRunner { @@ -88,6 +87,10 @@ export class FooRunner implements MainRunner { hello: 'json', }; await this.fooDAO.insert(foo); - return this.fooDAO.findOneByCol1('2333'); + const res = await this.fooDAO.findOneByCol1('2333'); + if (res) { + await this.fooDAO.delete(res.id); + } + return res; } } diff --git a/standalone/standalone/test/fixtures/dal-transaction-module/src/FooService.ts b/standalone/standalone/test/fixtures/dal-transaction-module/src/FooService.ts index 303d53ac..cb8a0438 100644 --- a/standalone/standalone/test/fixtures/dal-transaction-module/src/FooService.ts +++ b/standalone/standalone/test/fixtures/dal-transaction-module/src/FooService.ts @@ -30,4 +30,20 @@ export class FooService { await this.fooDAO.insert(foo2); throw new Error('mock error'); } + + async clear() { + await Promise.all( + [ + 'insert_succeed_transaction_1', + 'insert_succeed_transaction_2', + 'insert_failed_transaction_1', + 'insert_failed_transaction_2', + ].map(async name => { + const res = await this.fooDAO.findByName(name); + if (res.length === 1) { + await this.fooDAO.delete(res[0].id); + } + }), + ); + } } diff --git a/standalone/standalone/test/fixtures/dal-transaction-module/src/main.ts b/standalone/standalone/test/fixtures/dal-transaction-module/src/main.ts index 8b495392..2cbd3e16 100644 --- a/standalone/standalone/test/fixtures/dal-transaction-module/src/main.ts +++ b/standalone/standalone/test/fixtures/dal-transaction-module/src/main.ts @@ -19,11 +19,13 @@ export class FooRunner implements MainRunner>> { this.fooService.succeedTransaction(), this.fooService.failedTransaction(), ]); - return await Promise.all([ + const res = await Promise.all([ this.fooDAO.findByName('insert_succeed_transaction_1'), this.fooDAO.findByName('insert_succeed_transaction_2'), this.fooDAO.findByName('insert_failed_transaction_1'), this.fooDAO.findByName('insert_failed_transaction_2'), ]); + await this.fooService.clear(); + return res; } } diff --git a/standalone/standalone/test/fixtures/dependency/foo.ts b/standalone/standalone/test/fixtures/dependency/foo.ts index 64d20a57..f9eaf5b0 100644 --- a/standalone/standalone/test/fixtures/dependency/foo.ts +++ b/standalone/standalone/test/fixtures/dependency/foo.ts @@ -1,7 +1,6 @@ -import { ContextProto, Inject } from '@eggjs/tegg'; +import { ContextProto, Inject, ConfigSourceQualifier } from '@eggjs/tegg'; import { Runner, MainRunner } from '@eggjs/tegg/standalone'; import { Hello } from 'dependency-2/foo'; -import { ConfigSourceQualifier } from '../../../../../core/core-decorator/src/decorator/ConfigSource'; @ContextProto() @Runner() diff --git a/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/Foo.ts b/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/Foo.ts new file mode 100644 index 00000000..dea256c2 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/Foo.ts @@ -0,0 +1,11 @@ +import { SingletonProto } from '@eggjs/tegg'; +import { ContextHandler } from '@eggjs/tegg/helper'; +import { MainRunner, Runner } from '@eggjs/tegg/standalone'; + +@Runner() +@SingletonProto() +export class Foo implements MainRunner { + async main(): Promise { + return ContextHandler.getContext()?.get('initialized'); + } +} diff --git a/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/FooEggContextHook.ts b/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/FooEggContextHook.ts new file mode 100644 index 00000000..1af817c0 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/FooEggContextHook.ts @@ -0,0 +1,10 @@ +import { EggContextLifecycleProto } from '@eggjs/tegg'; +import { EggContext } from '@eggjs/tegg-runtime'; +import { LifecycleHook, EggContextLifecycleContext } from '@eggjs/tegg-types'; + +@EggContextLifecycleProto() +export class FooEggContextHook implements LifecycleHook { + async postCreate(_: EggContextLifecycleContext, ctx: EggContext): Promise { + ctx.set('initialized', 'Y'); + } +} diff --git a/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/package.json b/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/package.json new file mode 100644 index 00000000..856bfb20 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-context-lifecycle-proto/package.json @@ -0,0 +1,6 @@ +{ + "name": "egg-object-lifecycle-app", + "eggModule": { + "name": "eggObjectLifecycleApp" + } +} diff --git a/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/Foo.ts b/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/Foo.ts new file mode 100644 index 00000000..22b136a3 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/Foo.ts @@ -0,0 +1,12 @@ +import { SingletonProto } from '@eggjs/tegg'; +import { MainRunner, Runner } from '@eggjs/tegg/standalone'; + +@Runner() +@SingletonProto() +export class Foo implements MainRunner { + message: string; + + async main(): Promise { + return this.message; + } +} diff --git a/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/FooEggObjectHook.ts b/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/FooEggObjectHook.ts new file mode 100644 index 00000000..de053822 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/FooEggObjectHook.ts @@ -0,0 +1,12 @@ +import { EggObjectLifecycleProto } from '@eggjs/tegg'; +import { LifecycleHook, EggObject, EggObjectLifeCycleContext } from '@eggjs/tegg-types'; + +@EggObjectLifecycleProto() +export class FooEggObjectHook implements LifecycleHook { + async postCreate(_: EggObjectLifeCycleContext, eggObject: EggObject): Promise { + if (eggObject.name !== 'foo') { + return; + } + (eggObject.obj as any).message = 'foo message from FooEggObjectHook'; + } +} diff --git a/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/package.json b/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/package.json new file mode 100644 index 00000000..856bfb20 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-object-lifecycle-proto/package.json @@ -0,0 +1,6 @@ +{ + "name": "egg-object-lifecycle-app", + "eggModule": { + "name": "eggObjectLifecycleApp" + } +} diff --git a/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/Foo.ts b/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/Foo.ts new file mode 100644 index 00000000..02807627 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/Foo.ts @@ -0,0 +1,12 @@ +import { SingletonProto } from '@eggjs/tegg'; +import { MainRunner, Runner } from '@eggjs/tegg/standalone'; + +@Runner() +@SingletonProto({ name: 'FooRunner' }) +export class Foo implements MainRunner { + static message: string; + + async main(): Promise { + return Foo.message; + } +} diff --git a/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/FooEggPrototypeHook.ts b/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/FooEggPrototypeHook.ts new file mode 100644 index 00000000..f839bff4 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/FooEggPrototypeHook.ts @@ -0,0 +1,13 @@ +import { EggPrototypeLifecycleProto } from '@eggjs/tegg'; +import { LifecycleHook, EggPrototype, EggPrototypeLifecycleContext } from '@eggjs/tegg-types'; +import { Foo } from './Foo'; + +@EggPrototypeLifecycleProto() +export class FooEggPrototypeHook implements LifecycleHook { + async postCreate(_: EggPrototypeLifecycleContext, proto: EggPrototype): Promise { + if (proto.name !== 'FooRunner') { + return; + } + Foo.message = 'class name is ' + proto.className; + } +} diff --git a/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/package.json b/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/package.json new file mode 100644 index 00000000..b109ba12 --- /dev/null +++ b/standalone/standalone/test/fixtures/egg-prototype-lifecycle-proto/package.json @@ -0,0 +1,6 @@ +{ + "name": "egg-prototype-lifecycle-app", + "eggModule": { + "name": "eggPrototypeLifecycleApp" + } +} diff --git a/standalone/standalone/test/fixtures/inner-object-proto/foo.ts b/standalone/standalone/test/fixtures/inner-object-proto/foo.ts new file mode 100644 index 00000000..5de90667 --- /dev/null +++ b/standalone/standalone/test/fixtures/inner-object-proto/foo.ts @@ -0,0 +1,14 @@ +import { Inject, SingletonProto } from '@eggjs/tegg'; +import { MainRunner, Runner } from '@eggjs/tegg/standalone'; +import { InnerBar } from './innerBar'; + +@Runner() +@SingletonProto() +export class Foo implements MainRunner { + @Inject() + innerBar: InnerBar; + + async main(): Promise { + return this.innerBar.message(); + } +} diff --git a/standalone/standalone/test/fixtures/inner-object-proto/innerBar.ts b/standalone/standalone/test/fixtures/inner-object-proto/innerBar.ts new file mode 100644 index 00000000..0d03bd6e --- /dev/null +++ b/standalone/standalone/test/fixtures/inner-object-proto/innerBar.ts @@ -0,0 +1,16 @@ +import { AccessLevel, Inject, InnerObjectProto } from '@eggjs/tegg'; + +@InnerObjectProto() +export class InnerFoo { + message = 'inner foo'; +} + +@InnerObjectProto({ accessLevel: AccessLevel.PUBLIC }) +export class InnerBar { + @Inject() + innerFoo: InnerFoo; + + message() { + return 'with inner bar and ' + this.innerFoo.message; + } +} diff --git a/standalone/standalone/test/fixtures/inner-object-proto/package.json b/standalone/standalone/test/fixtures/inner-object-proto/package.json new file mode 100644 index 00000000..e8f314ab --- /dev/null +++ b/standalone/standalone/test/fixtures/inner-object-proto/package.json @@ -0,0 +1,6 @@ +{ + "name": "invalid-inner-object-inject", + "eggModule": { + "name": "invalidInnerObjectInject" + } +} diff --git a/standalone/standalone/test/fixtures/invalid-inner-object-inject/foo.ts b/standalone/standalone/test/fixtures/invalid-inner-object-inject/foo.ts new file mode 100644 index 00000000..cbdb4368 --- /dev/null +++ b/standalone/standalone/test/fixtures/invalid-inner-object-inject/foo.ts @@ -0,0 +1,14 @@ +import { Inject, SingletonProto } from '@eggjs/tegg'; +import { MainRunner, Runner } from '@eggjs/tegg/standalone'; +import { InnerBar } from './innerBar'; + +@Runner() +@SingletonProto() +export class Foo implements MainRunner { + @Inject() + innerBar: InnerBar; + + async main(): Promise { + return !!this.innerBar; + } +} diff --git a/standalone/standalone/test/fixtures/invalid-inner-object-inject/innerBar.ts b/standalone/standalone/test/fixtures/invalid-inner-object-inject/innerBar.ts new file mode 100644 index 00000000..b58c3eed --- /dev/null +++ b/standalone/standalone/test/fixtures/invalid-inner-object-inject/innerBar.ts @@ -0,0 +1,4 @@ +import { InnerObjectProto } from '@eggjs/tegg'; + +@InnerObjectProto() +export class InnerBar {} diff --git a/standalone/standalone/test/fixtures/invalid-inner-object-inject/package.json b/standalone/standalone/test/fixtures/invalid-inner-object-inject/package.json new file mode 100644 index 00000000..e8f314ab --- /dev/null +++ b/standalone/standalone/test/fixtures/invalid-inner-object-inject/package.json @@ -0,0 +1,6 @@ +{ + "name": "invalid-inner-object-inject", + "eggModule": { + "name": "invalidInnerObjectInject" + } +} diff --git a/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/Foo.ts b/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/Foo.ts new file mode 100644 index 00000000..ecccd592 --- /dev/null +++ b/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/Foo.ts @@ -0,0 +1,12 @@ +import { SingletonProto } from '@eggjs/tegg'; +import { MainRunner, Runner } from '@eggjs/tegg/standalone'; + +@Runner() +@SingletonProto() +export class Foo implements MainRunner { + count: number; + + async main(): Promise { + return this.count; + } +} diff --git a/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/FooLoadUnitInstanceHook.ts b/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/FooLoadUnitInstanceHook.ts new file mode 100644 index 00000000..aee1809c --- /dev/null +++ b/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/FooLoadUnitInstanceHook.ts @@ -0,0 +1,14 @@ +import { LoadUnitInstanceLifecycleProto } from '@eggjs/tegg'; +import { LifecycleHook, LoadUnitInstance, LoadUnitInstanceLifecycleContext } from '@eggjs/tegg-types'; + +@LoadUnitInstanceLifecycleProto() +export class FooLoadUnitInstanceHook implements LifecycleHook { + async postCreate(_: LoadUnitInstanceLifecycleContext, loadUnitInstance: LoadUnitInstance): Promise { + if (loadUnitInstance.name !== 'loadUnitInstanceLifecycleApp') { + return; + } + const proto = loadUnitInstance.loadUnit.getEggPrototype('foo', []); + const foo = loadUnitInstance.getEggObject('foo', proto[0]); + (foo.obj as any).count = 66; + } +} diff --git a/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/package.json b/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/package.json new file mode 100644 index 00000000..63fc7474 --- /dev/null +++ b/standalone/standalone/test/fixtures/load-unit-instance-lifecycle-proto/package.json @@ -0,0 +1,6 @@ +{ + "name": "load-unit-instance-lifecycle-app", + "eggModule": { + "name": "loadUnitInstanceLifecycleApp" + } +} diff --git a/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Foo.ts b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Foo.ts new file mode 100644 index 00000000..a2bc6e4b --- /dev/null +++ b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Foo.ts @@ -0,0 +1,8 @@ +import { InnerObjectProto } from '@eggjs/tegg'; + +@InnerObjectProto() +export class Foo { + getName() { + return 'foo fake name'; + } +} diff --git a/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/FooLoadUnitHook.ts b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/FooLoadUnitHook.ts new file mode 100644 index 00000000..f2d0451a --- /dev/null +++ b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/FooLoadUnitHook.ts @@ -0,0 +1,27 @@ +import { Inject, LoadUnitLifecycleProto, SingletonProto } from '@eggjs/tegg'; +import { LifecycleHook, LoadUnit, LoadUnitLifecycleContext } from '@eggjs/tegg-types'; +import { EggPrototypeCreatorFactory, EggPrototypeFactory } from '@eggjs/tegg-metadata'; +import { Foo } from './Foo'; + +@LoadUnitLifecycleProto() +export class FooLoadUnitHook implements LifecycleHook { + @Inject() + foo: Foo; + + async preCreate(_: LoadUnitLifecycleContext, loadUnit: LoadUnit): Promise { + if (loadUnit.name !== 'loadUnitLifecycleApp') { + return; + } + const fooName = this.foo.getName(); + class DynamicBar { + getName() { + return 'dynamic bar name|' + fooName; + } + } + SingletonProto()(DynamicBar); + const protos = await EggPrototypeCreatorFactory.createProto(DynamicBar, loadUnit); + for (const proto of protos) { + EggPrototypeFactory.instance.registerPrototype(proto, loadUnit); + } + } +} diff --git a/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Runner.ts b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Runner.ts new file mode 100644 index 00000000..3f026177 --- /dev/null +++ b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/Runner.ts @@ -0,0 +1,13 @@ +import { ContextProto, Inject } from '@eggjs/tegg'; +import { MainRunner, Runner } from '@eggjs/tegg/standalone'; + +@ContextProto() +@Runner() +export class FooRunner implements MainRunner { + @Inject() + dynamicBar: any; + + async main(): Promise { + return this.dynamicBar.getName(); + } +} diff --git a/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/package.json b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/package.json new file mode 100644 index 00000000..b586d7f1 --- /dev/null +++ b/standalone/standalone/test/fixtures/load-unit-lifecycle-proto/package.json @@ -0,0 +1,6 @@ +{ + "name": "load-unit-lifecycle-app", + "eggModule": { + "name": "loadUnitLifecycleApp" + } +} diff --git a/standalone/standalone/test/fixtures/multi-callback-instance-module/logger/DynamicLogger.ts b/standalone/standalone/test/fixtures/multi-callback-instance-module/logger/DynamicLogger.ts index 7189888a..03b0c8e4 100644 --- a/standalone/standalone/test/fixtures/multi-callback-instance-module/logger/DynamicLogger.ts +++ b/standalone/standalone/test/fixtures/multi-callback-instance-module/logger/DynamicLogger.ts @@ -21,7 +21,6 @@ export function LogPath(name: string) { }; } - @MultiInstanceProto({ accessLevel: AccessLevel.PUBLIC, getObjects(ctx: MultiInstancePrototypeGetObjectsContext) { diff --git a/standalone/standalone/test/fixtures/multi-modules/bar/bar.ts b/standalone/standalone/test/fixtures/multi-modules/bar/bar.ts new file mode 100644 index 00000000..242900e6 --- /dev/null +++ b/standalone/standalone/test/fixtures/multi-modules/bar/bar.ts @@ -0,0 +1,8 @@ +import { AccessLevel, SingletonProto, Inject } from '@eggjs/tegg'; +import { ModuleConfig } from '@eggjs/tegg/helper'; + +@SingletonProto({ accessLevel: AccessLevel.PUBLIC }) +export class Bar { + @Inject() + moduleConfig: ModuleConfig; +} diff --git a/standalone/standalone/test/fixtures/multi-modules/foo/foo.ts b/standalone/standalone/test/fixtures/multi-modules/foo/foo.ts index 95265b87..6e449cca 100644 --- a/standalone/standalone/test/fixtures/multi-modules/foo/foo.ts +++ b/standalone/standalone/test/fixtures/multi-modules/foo/foo.ts @@ -1,6 +1,7 @@ import { ContextProto, Inject, SingletonProto, ModuleConfigs, ConfigSourceQualifier } from '@eggjs/tegg'; import { Runner, MainRunner } from '@eggjs/tegg/standalone'; import { ModuleConfig } from 'egg'; +import { Bar } from '../bar/bar'; @SingletonProto() export class Hello { @@ -31,11 +32,15 @@ export class Foo implements MainRunner { @ConfigSourceQualifier('bar') barModuleConfig: ModuleConfig; + @Inject() + bar: Bar; + async main(): Promise { return { configs: this.moduleConfigs, foo: this.moduleConfig, bar: this.barModuleConfig, + configFromBar: this.bar.moduleConfig, }; } } From 8f936aaf7bde96a924f3ed7ca4b4e0c6a076f335 Mon Sep 17 00:00:00 2001 From: gxkl Date: Mon, 23 Jun 2025 06:49:12 +0800 Subject: [PATCH 2/8] f --- .../controller/test/fixtures/http-params/ParamController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standalone/controller/test/fixtures/http-params/ParamController.ts b/standalone/controller/test/fixtures/http-params/ParamController.ts index 7ba50d4d..b12f2b28 100644 --- a/standalone/controller/test/fixtures/http-params/ParamController.ts +++ b/standalone/controller/test/fixtures/http-params/ParamController.ts @@ -8,7 +8,7 @@ import { HTTPQueries, HTTPQuery, HTTPRequest, - Request + Request, } from '@eggjs/tegg'; @HTTPController() From 11a88bd6feac3de17de0a244b561cabd62373034 Mon Sep 17 00:00:00 2001 From: gxkl Date: Mon, 23 Jun 2025 06:58:59 +0800 Subject: [PATCH 3/8] chore: version --- core/standalone-decorator/package.json | 2 +- standalone/controller/package.json | 8 ++++---- standalone/service-worker-runtime/package.json | 6 +++--- standalone/service-worker/package.json | 18 +++++++++--------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/standalone-decorator/package.json b/core/standalone-decorator/package.json index 112664bb..29377e38 100644 --- a/core/standalone-decorator/package.json +++ b/core/standalone-decorator/package.json @@ -52,7 +52,7 @@ "mocha": "^10.2.0", "ts-node": "^10.9.1", "typescript": "^5.0.4", - "@eggjs/tegg": "^3.57.12" + "@eggjs/tegg": "^3.57.14" }, "gitHead": "b49e4c70e7f09a073e989493b995f8dd3ce482e9" } diff --git a/standalone/controller/package.json b/standalone/controller/package.json index 8f7fd02b..5fc08164 100644 --- a/standalone/controller/package.json +++ b/standalone/controller/package.json @@ -4,7 +4,7 @@ "eggModule": { "name": "standaloneController" }, - "version": "3.57.12", + "version": "3.57.14", "keywords": [ "egg", "typescript", @@ -54,9 +54,9 @@ "@eggjs/tegg-service-worker": "^3" }, "devDependencies": { - "@eggjs/tegg": "^3.57.12", - "@eggjs/tegg-service-worker": "^3.57.12", - "@eggjs/module-test-util": "^3.57.12", + "@eggjs/tegg": "^3.57.14", + "@eggjs/tegg-service-worker": "^3.57.14", + "@eggjs/module-test-util": "^3.57.14", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "@types/type-is": "^1.6.0", diff --git a/standalone/service-worker-runtime/package.json b/standalone/service-worker-runtime/package.json index d28c3b85..44d09d7c 100644 --- a/standalone/service-worker-runtime/package.json +++ b/standalone/service-worker-runtime/package.json @@ -4,7 +4,7 @@ "eggModule": { "name": "serviceWorkerRuntime" }, - "version": "3.57.12", + "version": "3.57.14", "keywords": [ "egg", "typescript", @@ -48,8 +48,8 @@ "@eggjs/tegg": "^3" }, "devDependencies": { - "@eggjs/tegg": "^3.57.12", - "@eggjs/tegg-standalone": "^3.57.12", + "@eggjs/tegg": "^3.57.14", + "@eggjs/tegg-standalone": "^3.57.14", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/standalone/service-worker/package.json b/standalone/service-worker/package.json index c0139e38..78719f1c 100644 --- a/standalone/service-worker/package.json +++ b/standalone/service-worker/package.json @@ -1,7 +1,7 @@ { "name": "@eggjs/tegg-service-worker", "description": "tegg service worker", - "version": "3.57.12", + "version": "3.57.14", "keywords": [ "egg", "typescript", @@ -42,19 +42,19 @@ "access": "public" }, "dependencies": { - "@eggjs/tegg-standalone": "^3.57.12", - "@eggjs/tegg-dynamic-inject-runtime": "^3.57.12", - "@eggjs/tegg-ajv-plugin": "^3.57.12", - "@eggjs/tegg-dal-plugin": "^3.57.12", - "@eggjs/tegg-aop-runtime": "^3.57.12", - "@eggjs/tegg-service-worker-runtime": "^3.57.12", - "@eggjs/tegg-standalone-controller": "^3.57.12" + "@eggjs/tegg-standalone": "^3.57.14", + "@eggjs/tegg-dynamic-inject-runtime": "^3.57.14", + "@eggjs/tegg-ajv-plugin": "^3.57.14", + "@eggjs/tegg-dal-plugin": "^3.57.14", + "@eggjs/tegg-aop-runtime": "^3.57.14", + "@eggjs/tegg-service-worker-runtime": "^3.57.14", + "@eggjs/tegg-standalone-controller": "^3.57.14" }, "peerDependencies": { "@eggjs/tegg": "^3" }, "devDependencies": { - "@eggjs/tegg": "^3.57.12", + "@eggjs/tegg": "^3.57.14", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", From cf781919d38ec50feeb88350e011d4cb9425acff Mon Sep 17 00:00:00 2001 From: Gxkl Date: Mon, 23 Jun 2025 14:26:54 +0800 Subject: [PATCH 4/8] fix/test (#333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ##### Checklist - [x] `npm test` passes - [x] tests and/or benchmarks are included - [x] documentation is changed or added - [x] commit message follows commit guidelines ##### Affected core subsystem(s) ##### Description of change --- core/core-decorator/test/decorators.test.ts | 9 +++++---- core/test-util/StandaloneTestUtil.ts | 5 +++++ standalone/controller/package.json | 2 +- .../controller/src/impl/http/FetchEventHandler.ts | 15 ++++++++++++++- .../test/fixtures/http-priority/package.json | 4 ++-- standalone/controller/test/http/params.test.ts | 12 ++++++++---- standalone/controller/test/http/priority.test.ts | 8 ++++++-- standalone/controller/test/http/response.test.ts | 12 ++++++++---- standalone/controller/test/http/router.test.ts | 8 ++++++-- standalone/service-worker-runtime/package.json | 3 ++- .../service-worker-runtime/test/index.test.ts | 7 +++++++ standalone/service-worker/package.json | 3 ++- standalone/service-worker/test/http.test.ts | 7 +++++++ 13 files changed, 73 insertions(+), 22 deletions(-) diff --git a/core/core-decorator/test/decorators.test.ts b/core/core-decorator/test/decorators.test.ts index 633886b0..1ee1e48e 100644 --- a/core/core-decorator/test/decorators.test.ts +++ b/core/core-decorator/test/decorators.test.ts @@ -7,6 +7,7 @@ import { DEFAULT_PROTO_IMPL_TYPE, MultiInstanceType, EggProtoImplClass, + EGG_INNER_OBJECT_PROTO_IMPL_TYPE, } from '@eggjs/tegg-types'; import type { EggPrototypeInfo, EggMultiInstancePrototypeInfo, InjectObjectInfo } from '@eggjs/tegg-types'; @@ -210,7 +211,7 @@ describe('test/decorator.test.ts', () => { name: 'router', initType: ObjectInitType.SINGLETON, accessLevel: AccessLevel.PRIVATE, - protoImplType: DEFAULT_PROTO_IMPL_TYPE, + protoImplType: EGG_INNER_OBJECT_PROTO_IMPL_TYPE, className: 'Router', }; assert.deepStrictEqual(PrototypeUtil.getProperty(Router), expectObjectProperty); @@ -221,7 +222,7 @@ describe('test/decorator.test.ts', () => { name: 'customRouter', initType: ObjectInitType.SINGLETON, accessLevel: AccessLevel.PUBLIC, - protoImplType: DEFAULT_PROTO_IMPL_TYPE, + protoImplType: EGG_INNER_OBJECT_PROTO_IMPL_TYPE, className: 'OtherRouter', }; assert.deepStrictEqual(PrototypeUtil.getProperty(OtherRouter), expectObjectProperty); @@ -236,7 +237,7 @@ describe('test/decorator.test.ts', () => { name: clazz.name.replace(/^./, c => c.toLowerCase()), initType: ObjectInitType.SINGLETON, accessLevel: AccessLevel.PRIVATE, - protoImplType: DEFAULT_PROTO_IMPL_TYPE, + protoImplType: EGG_INNER_OBJECT_PROTO_IMPL_TYPE, className: clazz.name, }; assert.deepStrictEqual(PrototypeUtil.getProperty(clazz), expectObjectProperty); @@ -256,7 +257,7 @@ describe('test/decorator.test.ts', () => { name: 'customName', initType: ObjectInitType.SINGLETON, accessLevel: AccessLevel.PUBLIC, - protoImplType: DEFAULT_PROTO_IMPL_TYPE, + protoImplType: EGG_INNER_OBJECT_PROTO_IMPL_TYPE, className: 'ControllerOtherLifecycle', }; assert.deepStrictEqual(PrototypeUtil.getProperty(ControllerOtherLifecycle), expectObjectProperty); diff --git a/core/test-util/StandaloneTestUtil.ts b/core/test-util/StandaloneTestUtil.ts index 8e6524a3..83e013ee 100644 --- a/core/test-util/StandaloneTestUtil.ts +++ b/core/test-util/StandaloneTestUtil.ts @@ -10,6 +10,11 @@ export interface StartHTTPServerOptions extends ServerOptions { } export class StandaloneTestUtil { + static skipOnNode(minVersion = 18) { + const version = parseInt(process.versions.node.split('.')[0], 10); + return version < minVersion; + } + static #buildRequest(req: IncomingMessage): Request { const origin = `http://${req.headers.host ?? 'localhost'}`; const url = new URL(req.url ?? '', origin); diff --git a/standalone/controller/package.json b/standalone/controller/package.json index 5fc08164..5e06e202 100644 --- a/standalone/controller/package.json +++ b/standalone/controller/package.json @@ -37,7 +37,7 @@ "directory": "standalone/standalone" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" }, "author": "killagu ", "license": "MIT", diff --git a/standalone/controller/src/impl/http/FetchEventHandler.ts b/standalone/controller/src/impl/http/FetchEventHandler.ts index b1f73f1a..1bf9ca22 100644 --- a/standalone/controller/src/impl/http/FetchEventHandler.ts +++ b/standalone/controller/src/impl/http/FetchEventHandler.ts @@ -1,6 +1,14 @@ import { MiddlewareFuncWithRouter } from '@eggjs/router'; import { FetchEvent } from '@eggjs/tegg-types/standalone'; -import { AccessLevel, Inject, InjectOptional, LifecycleInit, LifecyclePostInject, Logger } from '@eggjs/tegg'; +import { + AccessLevel, + Inject, + InjectOptional, + LifecycleDestroy, + LifecycleInit, + LifecyclePostInject, + Logger +} from '@eggjs/tegg'; import { AbstractEventHandler, EventHandlerProto } from '@eggjs/tegg/standalone'; import { FetchRouter } from './FetchRouter'; import { ServiceWorkerFetchContext } from './ServiceWorkerFetchContext'; @@ -30,6 +38,11 @@ export class FetchEventHandler extends AbstractEventHandler { const ctx = new ServiceWorkerFetchContext({ event }); try { diff --git a/standalone/controller/test/fixtures/http-priority/package.json b/standalone/controller/test/fixtures/http-priority/package.json index d53116ee..67f59ae2 100644 --- a/standalone/controller/test/fixtures/http-priority/package.json +++ b/standalone/controller/test/fixtures/http-priority/package.json @@ -1,6 +1,6 @@ { - "name": "http-params-app", + "name": "http-priority-app", "eggModule": { - "name": "httpParamsApp" + "name": "httpPriorityApp" } } diff --git a/standalone/controller/test/http/params.test.ts b/standalone/controller/test/http/params.test.ts index 4d6b2823..e1a55931 100644 --- a/standalone/controller/test/http/params.test.ts +++ b/standalone/controller/test/http/params.test.ts @@ -1,14 +1,18 @@ +import assert from 'node:assert'; import { Server } from 'node:http'; +import httpRequest from 'supertest'; import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; import { TestUtils } from '../Utils'; -import httpRequest from 'supertest'; -import assert from 'node:assert'; +import { StandaloneTestUtil } from '@eggjs/module-test-util/StandaloneTestUtil'; -describe('standalone/service-worker-runtime/test/http/params.test.ts', () => { +describe('standalone/controller/test/http/params.test.ts', () => { let app: ServiceWorkerApp; let server: Server; - before(async () => { + before(async function() { + if (StandaloneTestUtil.skipOnNode()) { + return this.skip(); + } ({ app, server } = await TestUtils.createFetchApp('http-params')); }); diff --git a/standalone/controller/test/http/priority.test.ts b/standalone/controller/test/http/priority.test.ts index 1089eebf..6daa2d49 100644 --- a/standalone/controller/test/http/priority.test.ts +++ b/standalone/controller/test/http/priority.test.ts @@ -1,13 +1,17 @@ import { Server } from 'node:http'; import httpRequest from 'supertest'; import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; +import { StandaloneTestUtil } from '@eggjs/module-test-util/StandaloneTestUtil'; import { TestUtils } from '../Utils'; -describe('standalone/service-worker-runtime/test/http/priority.test.ts', () => { +describe('standalone/controller/test/http/priority.test.ts', () => { let app: ServiceWorkerApp; let server: Server; - before(async () => { + before(async function() { + if (StandaloneTestUtil.skipOnNode()) { + return this.skip(); + } ({ app, server } = await TestUtils.createFetchApp('http-priority')); }); diff --git a/standalone/controller/test/http/response.test.ts b/standalone/controller/test/http/response.test.ts index 33e5a034..22bb336e 100644 --- a/standalone/controller/test/http/response.test.ts +++ b/standalone/controller/test/http/response.test.ts @@ -1,13 +1,17 @@ -import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; import { Server } from 'node:http'; -import { TestUtils } from '../Utils'; import httpRequest from 'supertest'; +import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; +import { StandaloneTestUtil } from '@eggjs/module-test-util/StandaloneTestUtil'; +import { TestUtils } from '../Utils'; -describe('standalone/service-worker-runtime/test/http/response.test.ts', () => { +describe('standalone/controller/test/http/response.test.ts', () => { let app: ServiceWorkerApp; let server: Server; - before(async () => { + before(async function() { + if (StandaloneTestUtil.skipOnNode()) { + return this.skip(); + } ({ app, server } = await TestUtils.createFetchApp('http')); }); diff --git a/standalone/controller/test/http/router.test.ts b/standalone/controller/test/http/router.test.ts index 4f3958df..30f6063e 100644 --- a/standalone/controller/test/http/router.test.ts +++ b/standalone/controller/test/http/router.test.ts @@ -1,13 +1,17 @@ import { Server } from 'node:http'; import httpRequest from 'supertest'; import { ServiceWorkerApp } from '@eggjs/tegg-service-worker'; +import { StandaloneTestUtil } from '@eggjs/module-test-util/StandaloneTestUtil'; import { TestUtils } from '../Utils'; -describe('standalone/service-worker-runtime/test/http/router.test.ts', () => { +describe('standalone/controller/test/http/router.test.ts', () => { let app: ServiceWorkerApp; let server: Server; - before(async () => { + before(async function() { + if (StandaloneTestUtil.skipOnNode()) { + return this.skip(); + } ({ app, server } = await TestUtils.createFetchApp('http')); }); diff --git a/standalone/service-worker-runtime/package.json b/standalone/service-worker-runtime/package.json index 44d09d7c..98056f4e 100644 --- a/standalone/service-worker-runtime/package.json +++ b/standalone/service-worker-runtime/package.json @@ -37,7 +37,7 @@ "directory": "standalone/standalone" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" }, "author": "killagu ", "license": "MIT", @@ -50,6 +50,7 @@ "devDependencies": { "@eggjs/tegg": "^3.57.14", "@eggjs/tegg-standalone": "^3.57.14", + "@eggjs/module-test-util": "^3.57.14", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/standalone/service-worker-runtime/test/index.test.ts b/standalone/service-worker-runtime/test/index.test.ts index fffefa01..4157f686 100644 --- a/standalone/service-worker-runtime/test/index.test.ts +++ b/standalone/service-worker-runtime/test/index.test.ts @@ -1,9 +1,16 @@ import { strict as assert } from 'node:assert'; +import { StandaloneTestUtil } from '@eggjs/module-test-util/StandaloneTestUtil'; import { StandAloneAppTest } from './Utils'; import { CustomEvent } from './fixtures/simple/Event'; describe('standalone/service-worker-runtime/test/index.test.ts', () => { describe('simple', () => { + before(async function() { + if (StandaloneTestUtil.skipOnNode()) { + return this.skip(); + } + }); + it('should work', async () => { const event = new CustomEvent('custom', { foo: 'bar' }); const msg = await StandAloneAppTest.run('simple', event); diff --git a/standalone/service-worker/package.json b/standalone/service-worker/package.json index 78719f1c..72198b24 100644 --- a/standalone/service-worker/package.json +++ b/standalone/service-worker/package.json @@ -34,7 +34,7 @@ "directory": "standalone/standalone" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" }, "author": "killagu ", "license": "MIT", @@ -55,6 +55,7 @@ }, "devDependencies": { "@eggjs/tegg": "^3.57.14", + "@eggjs/module-test-util": "^3.57.14", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/standalone/service-worker/test/http.test.ts b/standalone/service-worker/test/http.test.ts index 5373816a..1117880f 100644 --- a/standalone/service-worker/test/http.test.ts +++ b/standalone/service-worker/test/http.test.ts @@ -1,10 +1,17 @@ import { strict as assert } from 'node:assert'; +import { StandaloneTestUtil } from '@eggjs/module-test-util/StandaloneTestUtil'; import { ServiceWorkerApp } from '../src/ServiceWorkerApp'; import { TestUtils } from './Utils'; describe('standalone/service-worker/test/http.test.ts', () => { let app: ServiceWorkerApp; + before(async function() { + if (StandaloneTestUtil.skipOnNode()) { + return this.skip(); + } + }); + afterEach(async () => { await app?.destroy(); }); From 01fccecd74a1229e1f52e557e5fc6547702fa34c Mon Sep 17 00:00:00 2001 From: gxkl Date: Mon, 23 Jun 2025 14:39:16 +0800 Subject: [PATCH 5/8] f --- standalone/controller/src/impl/http/FetchEventHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standalone/controller/src/impl/http/FetchEventHandler.ts b/standalone/controller/src/impl/http/FetchEventHandler.ts index 1bf9ca22..1cc975ed 100644 --- a/standalone/controller/src/impl/http/FetchEventHandler.ts +++ b/standalone/controller/src/impl/http/FetchEventHandler.ts @@ -7,7 +7,7 @@ import { LifecycleDestroy, LifecycleInit, LifecyclePostInject, - Logger + Logger, } from '@eggjs/tegg'; import { AbstractEventHandler, EventHandlerProto } from '@eggjs/tegg/standalone'; import { FetchRouter } from './FetchRouter'; From b1f4923cef0096883b300ba2b7f235a27a335772 Mon Sep 17 00:00:00 2001 From: gxkl Date: Wed, 25 Jun 2025 01:10:53 +0800 Subject: [PATCH 6/8] f --- plugin/controller/test/mcp/helper.test.ts | 2 +- standalone/standalone/test/StandaloneApp.test.ts | 2 +- standalone/standalone/test/Utils.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/controller/test/mcp/helper.test.ts b/plugin/controller/test/mcp/helper.test.ts index d6ba0ab3..1911b25e 100644 --- a/plugin/controller/test/mcp/helper.test.ts +++ b/plugin/controller/test/mcp/helper.test.ts @@ -146,7 +146,7 @@ describe('plugin/controller/test/mcp/mcp.test.ts', () => { const prompts = await client.listPrompts(); assert.deepEqual(prompts, { prompts: [ - { name: 'testPrompt', arguments: [{ name: 'name', required: true, description: undefined }], description: undefined }, + { name: 'testPrompt', arguments: [{ name: 'name', required: true, description: undefined }], description: undefined, title: undefined }, ], }); diff --git a/standalone/standalone/test/StandaloneApp.test.ts b/standalone/standalone/test/StandaloneApp.test.ts index 20d05e95..6433b5b9 100644 --- a/standalone/standalone/test/StandaloneApp.test.ts +++ b/standalone/standalone/test/StandaloneApp.test.ts @@ -19,7 +19,7 @@ describe('standalone/standalone/test/StandaloneApp.test.ts', () => { }); it('should work', async () => { - const msg: string = await StandAloneAppTest.run('simple'); + const msg: string = await StandAloneAppTest.run('simple', { dump: true }); assert.equal(msg, 'hello!hello from ctx'); await sleep(500); assert.equal((ModuleDescriptorDumper.dump as any).called, 1); diff --git a/standalone/standalone/test/Utils.ts b/standalone/standalone/test/Utils.ts index 90adc132..8ce457f9 100644 --- a/standalone/standalone/test/Utils.ts +++ b/standalone/standalone/test/Utils.ts @@ -72,8 +72,8 @@ export class StandAloneAppTest { await StandAloneAppTest.copyFixture(name); const app = typeof env === 'string' - ? await StandAloneAppTest.createApp(name, env, init) - : await StandAloneAppTest.createApp(name, env); + ? await StandAloneAppTest.createApp(name, env, { dump: false, ...init }) + : await StandAloneAppTest.createApp(name, { dump: false, ...env }); try { return await app.run(); } finally { From 2e7351bc62161b203f7a98a978d9a901165fb516 Mon Sep 17 00:00:00 2001 From: gxkl Date: Fri, 27 Jun 2025 15:03:34 +0800 Subject: [PATCH 7/8] fix: repo dir --- standalone/controller/package.json | 2 +- standalone/service-worker-runtime/package.json | 2 +- standalone/service-worker/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/standalone/controller/package.json b/standalone/controller/package.json index 5e06e202..042fda01 100644 --- a/standalone/controller/package.json +++ b/standalone/controller/package.json @@ -34,7 +34,7 @@ "repository": { "type": "git", "url": "git@github.com:eggjs/tegg.git", - "directory": "standalone/standalone" + "directory": "standalone/controller" }, "engines": { "node": ">=18.0.0" diff --git a/standalone/service-worker-runtime/package.json b/standalone/service-worker-runtime/package.json index 98056f4e..c58c0538 100644 --- a/standalone/service-worker-runtime/package.json +++ b/standalone/service-worker-runtime/package.json @@ -34,7 +34,7 @@ "repository": { "type": "git", "url": "git@github.com:eggjs/tegg.git", - "directory": "standalone/standalone" + "directory": "standalone/service-worker-runtime" }, "engines": { "node": ">=18.0.0" diff --git a/standalone/service-worker/package.json b/standalone/service-worker/package.json index 72198b24..3199ebe2 100644 --- a/standalone/service-worker/package.json +++ b/standalone/service-worker/package.json @@ -31,7 +31,7 @@ "repository": { "type": "git", "url": "git@github.com:eggjs/tegg.git", - "directory": "standalone/standalone" + "directory": "standalone/service-worker" }, "engines": { "node": ">=18.0.0" From 083f28b66e5b5addfbc0a5c98367f3a35e46e6d0 Mon Sep 17 00:00:00 2001 From: gxkl Date: Fri, 27 Jun 2025 16:41:18 +0800 Subject: [PATCH 8/8] v3.57.15-alpha.0 --- CHANGELOG.md | 16 ++++++++ core/ajv-decorator/CHANGELOG.md | 8 ++++ core/ajv-decorator/package.json | 2 +- core/aop-decorator/CHANGELOG.md | 8 ++++ core/aop-decorator/package.json | 10 ++--- core/aop-runtime/CHANGELOG.md | 11 ++++++ core/aop-runtime/package.json | 20 +++++----- core/background-task/CHANGELOG.md | 8 ++++ core/background-task/package.json | 12 +++--- core/common-util/CHANGELOG.md | 8 ++++ core/common-util/package.json | 4 +- core/controller-decorator/CHANGELOG.md | 8 ++++ core/controller-decorator/package.json | 12 +++--- core/core-decorator/CHANGELOG.md | 11 ++++++ core/core-decorator/package.json | 6 +-- core/dal-decorator/CHANGELOG.md | 8 ++++ core/dal-decorator/package.json | 8 ++-- core/dal-runtime/CHANGELOG.md | 8 ++++ core/dal-runtime/package.json | 6 +-- core/dynamic-inject-runtime/CHANGELOG.md | 8 ++++ core/dynamic-inject-runtime/package.json | 20 +++++----- core/dynamic-inject/CHANGELOG.md | 8 ++++ core/dynamic-inject/package.json | 6 +-- core/eventbus-decorator/CHANGELOG.md | 8 ++++ core/eventbus-decorator/package.json | 8 ++-- core/eventbus-runtime/CHANGELOG.md | 8 ++++ core/eventbus-runtime/package.json | 16 ++++---- core/lifecycle/CHANGELOG.md | 11 ++++++ core/lifecycle/package.json | 10 ++--- core/loader/CHANGELOG.md | 11 ++++++ core/loader/package.json | 10 ++--- core/metadata/CHANGELOG.md | 11 ++++++ core/metadata/package.json | 10 ++--- core/orm-decorator/CHANGELOG.md | 8 ++++ core/orm-decorator/package.json | 10 ++--- core/runtime/CHANGELOG.md | 11 ++++++ core/runtime/package.json | 14 +++---- core/schedule-decorator/CHANGELOG.md | 8 ++++ core/schedule-decorator/package.json | 10 ++--- core/standalone-decorator/CHANGELOG.md | 11 ++++++ core/standalone-decorator/package.json | 8 ++-- core/tegg/CHANGELOG.md | 8 ++++ core/tegg/package.json | 38 +++++++++---------- core/test-util/CHANGELOG.md | 11 ++++++ core/test-util/package.json | 12 +++--- core/transaction-decorator/CHANGELOG.md | 8 ++++ core/transaction-decorator/package.json | 10 ++--- core/types/CHANGELOG.md | 11 ++++++ core/types/package.json | 6 +-- lerna.json | 2 +- plugin/ajv/CHANGELOG.md | 8 ++++ plugin/ajv/package.json | 10 ++--- plugin/aop/CHANGELOG.md | 8 ++++ plugin/aop/package.json | 16 ++++---- plugin/common/CHANGELOG.md | 8 ++++ plugin/common/package.json | 2 +- plugin/config/CHANGELOG.md | 8 ++++ plugin/config/package.json | 4 +- plugin/controller/CHANGELOG.md | 8 ++++ plugin/controller/package.json | 22 +++++------ plugin/dal/CHANGELOG.md | 11 ++++++ plugin/dal/package.json | 10 ++--- plugin/eventbus/CHANGELOG.md | 8 ++++ plugin/eventbus/package.json | 18 ++++----- plugin/mcp-proxy/CHANGELOG.md | 8 ++++ plugin/mcp-proxy/package.json | 18 ++++----- plugin/orm/CHANGELOG.md | 8 ++++ plugin/orm/package.json | 24 ++++++------ plugin/schedule/CHANGELOG.md | 8 ++++ plugin/schedule/package.json | 24 ++++++------ plugin/tegg/CHANGELOG.md | 8 ++++ plugin/tegg/package.json | 20 +++++----- standalone/controller/CHANGELOG.md | 16 ++++++++ standalone/controller/package.json | 8 ++-- .../service-worker-runtime/CHANGELOG.md | 16 ++++++++ .../service-worker-runtime/package.json | 8 ++-- standalone/service-worker/CHANGELOG.md | 16 ++++++++ standalone/service-worker/package.json | 20 +++++----- standalone/standalone/CHANGELOG.md | 11 ++++++ standalone/standalone/package.json | 26 ++++++------- 80 files changed, 635 insertions(+), 250 deletions(-) create mode 100644 standalone/controller/CHANGELOG.md create mode 100644 standalone/service-worker-runtime/CHANGELOG.md create mode 100644 standalone/service-worker/CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f835fd6b..6257f82f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Bug Fixes + +* repo dir ([2e7351b](https://github.com/eggjs/tegg/commit/2e7351bc62161b203f7a98a978d9a901165fb516)) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package tegg diff --git a/core/ajv-decorator/CHANGELOG.md b/core/ajv-decorator/CHANGELOG.md index 6d568930..4d89f755 100644 --- a/core/ajv-decorator/CHANGELOG.md +++ b/core/ajv-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/ajv-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/ajv-decorator diff --git a/core/ajv-decorator/package.json b/core/ajv-decorator/package.json index 9303b404..8132f4bc 100644 --- a/core/ajv-decorator/package.json +++ b/core/ajv-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/ajv-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg ajv decorator", "keywords": [ "egg", diff --git a/core/aop-decorator/CHANGELOG.md b/core/aop-decorator/CHANGELOG.md index 21a8e914..62af7b87 100644 --- a/core/aop-decorator/CHANGELOG.md +++ b/core/aop-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/aop-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/aop-decorator diff --git a/core/aop-decorator/package.json b/core/aop-decorator/package.json index b1efbe19..a55494d8 100644 --- a/core/aop-decorator/package.json +++ b/core/aop-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/aop-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg aop decorator", "keywords": [ "tegg", @@ -16,10 +16,10 @@ "directory": "core/aop-decorator" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "scripts": { "test": "cross-env NODE_ENV=test NODE_OPTIONS='--no-deprecation' mocha", diff --git a/core/aop-runtime/CHANGELOG.md b/core/aop-runtime/CHANGELOG.md index fe8c2656..c85a5a6c 100644 --- a/core/aop-runtime/CHANGELOG.md +++ b/core/aop-runtime/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-aop-runtime diff --git a/core/aop-runtime/package.json b/core/aop-runtime/package.json index 331b9768..f5a51c65 100644 --- a/core/aop-runtime/package.json +++ b/core/aop-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-aop-runtime", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg aop", "main": "dist/index.js", "eggModule": { @@ -43,18 +43,18 @@ "access": "public" }, "dependencies": { - "@eggjs/aop-decorator": "^3.57.14", - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/aop-decorator": "^3.57.15-alpha.0", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "koa-compose": "^4.1.0" }, "devDependencies": { - "@eggjs/module-test-util": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/core/background-task/CHANGELOG.md b/core/background-task/CHANGELOG.md index 58a69054..00aaae86 100644 --- a/core/background-task/CHANGELOG.md +++ b/core/background-task/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-background-task + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-background-task diff --git a/core/background-task/package.json b/core/background-task/package.json index 67634047..dcc869f8 100644 --- a/core/background-task/package.json +++ b/core/background-task/package.json @@ -1,7 +1,7 @@ { "name": "@eggjs/tegg-background-task", "description": "background util for tegg", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "keywords": [ "egg", "typescript", @@ -37,13 +37,13 @@ "author": "killagu ", "license": "MIT", "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/tegg-common-util": "^3.57.14", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/core/common-util/CHANGELOG.md b/core/common-util/CHANGELOG.md index 5420d6f1..ed3bce63 100644 --- a/core/common-util/CHANGELOG.md +++ b/core/common-util/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-common-util + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-common-util diff --git a/core/common-util/package.json b/core/common-util/package.json index 4cfb4a7e..dd37058e 100644 --- a/core/common-util/package.json +++ b/core/common-util/package.json @@ -1,7 +1,7 @@ { "name": "@eggjs/tegg-common-util", "description": "common util for tegg", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "keywords": [ "egg", "typescript", @@ -36,7 +36,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "extend2": "^1.0.0", "globby": "^11.1.0", "js-yaml": "^3.14.0" diff --git a/core/controller-decorator/CHANGELOG.md b/core/controller-decorator/CHANGELOG.md index c5346b3d..1c3e4155 100644 --- a/core/controller-decorator/CHANGELOG.md +++ b/core/controller-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/controller-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/controller-decorator diff --git a/core/controller-decorator/package.json b/core/controller-decorator/package.json index 5da569f1..54595410 100644 --- a/core/controller-decorator/package.json +++ b/core/controller-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/controller-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg controller decorator", "keywords": [ "egg", @@ -37,12 +37,12 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/aop-decorator": "^3.57.14", + "@eggjs/aop-decorator": "^3.57.15-alpha.0", "@eggjs/cookies": "^3.0.1", - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "@modelcontextprotocol/sdk": "^1.10.0", "is-type-of": "^1.2.1", "path-to-regexp": "^1.8.0", diff --git a/core/core-decorator/CHANGELOG.md b/core/core-decorator/CHANGELOG.md index f0e8e4a3..c3a870d0 100644 --- a/core/core-decorator/CHANGELOG.md +++ b/core/core-decorator/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/core-decorator diff --git a/core/core-decorator/package.json b/core/core-decorator/package.json index 2cfdff83..9a7325fd 100644 --- a/core/core-decorator/package.json +++ b/core/core-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/core-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg core decorator", "keywords": [ "egg", @@ -36,8 +36,8 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "reflect-metadata": "^0.1.13" }, "publishConfig": { diff --git a/core/dal-decorator/CHANGELOG.md b/core/dal-decorator/CHANGELOG.md index a6e8f4f0..9e2657fa 100644 --- a/core/dal-decorator/CHANGELOG.md +++ b/core/dal-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/dal-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/dal-decorator diff --git a/core/dal-decorator/package.json b/core/dal-decorator/package.json index b81cd33e..f2145c6f 100644 --- a/core/dal-decorator/package.json +++ b/core/dal-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/dal-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg dal decorator", "keywords": [ "egg", @@ -37,9 +37,9 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "lodash.snakecase": "^4.1.1", "pluralize": "^8.0.0" }, diff --git a/core/dal-runtime/CHANGELOG.md b/core/dal-runtime/CHANGELOG.md index f185e657..6b2be5d6 100644 --- a/core/dal-runtime/CHANGELOG.md +++ b/core/dal-runtime/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/dal-runtime + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/dal-runtime diff --git a/core/dal-runtime/package.json b/core/dal-runtime/package.json index 6157aeb0..73829505 100644 --- a/core/dal-runtime/package.json +++ b/core/dal-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/dal-runtime", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg dal decorator", "keywords": [ "egg", @@ -40,8 +40,8 @@ }, "dependencies": { "@eggjs/rds": "^1.0.0", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "js-beautify": "^1.15.1", "lodash": "^4.17.21", "nunjucks": "^3.2.4", diff --git a/core/dynamic-inject-runtime/CHANGELOG.md b/core/dynamic-inject-runtime/CHANGELOG.md index a9fb235f..5593a9c9 100644 --- a/core/dynamic-inject-runtime/CHANGELOG.md +++ b/core/dynamic-inject-runtime/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-dynamic-inject-runtime + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-dynamic-inject-runtime diff --git a/core/dynamic-inject-runtime/package.json b/core/dynamic-inject-runtime/package.json index d6d827a2..eb4ff0b2 100644 --- a/core/dynamic-inject-runtime/package.json +++ b/core/dynamic-inject-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-dynamic-inject-runtime", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg dyniamic inject", "main": "dist/index.js", "eggModule": { @@ -42,17 +42,17 @@ "access": "public" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-dynamic-inject": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-dynamic-inject": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/module-test-util": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/core/dynamic-inject/CHANGELOG.md b/core/dynamic-inject/CHANGELOG.md index ed1ff34d..07ee5432 100644 --- a/core/dynamic-inject/CHANGELOG.md +++ b/core/dynamic-inject/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-dynamic-inject + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-dynamic-inject diff --git a/core/dynamic-inject/package.json b/core/dynamic-inject/package.json index 836a898b..b00cd191 100644 --- a/core/dynamic-inject/package.json +++ b/core/dynamic-inject/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-dynamic-inject", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg dyniamic inject", "main": "dist/index.js", "files": [ @@ -39,8 +39,8 @@ "access": "public" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "devDependencies": { "@types/mocha": "^10.0.1", diff --git a/core/eventbus-decorator/CHANGELOG.md b/core/eventbus-decorator/CHANGELOG.md index e3b72628..fa137260 100644 --- a/core/eventbus-decorator/CHANGELOG.md +++ b/core/eventbus-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/eventbus-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/eventbus-decorator diff --git a/core/eventbus-decorator/package.json b/core/eventbus-decorator/package.json index e71de506..f5c6b6f0 100644 --- a/core/eventbus-decorator/package.json +++ b/core/eventbus-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/eventbus-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg eventbus decorator", "keywords": [ "egg", @@ -34,9 +34,9 @@ "directory": "core/eventbus-decorator" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "typed-emitter": "^1.3.1" }, "engines": { diff --git a/core/eventbus-runtime/CHANGELOG.md b/core/eventbus-runtime/CHANGELOG.md index 42e28127..6f7c77be 100644 --- a/core/eventbus-runtime/CHANGELOG.md +++ b/core/eventbus-runtime/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-eventbus-runtime + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-eventbus-runtime diff --git a/core/eventbus-runtime/package.json b/core/eventbus-runtime/package.json index d39b07cf..da46f997 100644 --- a/core/eventbus-runtime/package.json +++ b/core/eventbus-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-eventbus-runtime", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg eventbus runtime", "keywords": [ "egg", @@ -37,11 +37,11 @@ "directory": "core/eventbus-runtime" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/eventbus-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/eventbus-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "await-event": "^2.1.0", "await-first": "^1.0.0" }, @@ -49,8 +49,8 @@ "node": ">=14.0.0" }, "devDependencies": { - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "coffee": "^5.4.0", diff --git a/core/lifecycle/CHANGELOG.md b/core/lifecycle/CHANGELOG.md index 8b5a2922..b4cbcff2 100644 --- a/core/lifecycle/CHANGELOG.md +++ b/core/lifecycle/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-lifecycle diff --git a/core/lifecycle/package.json b/core/lifecycle/package.json index db5212aa..ad1f96db 100644 --- a/core/lifecycle/package.json +++ b/core/lifecycle/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-lifecycle", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg lifecycle definition", "keywords": [ "egg", @@ -39,12 +39,12 @@ "access": "public" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/core/loader/CHANGELOG.md b/core/loader/CHANGELOG.md index d3734e71..f5433156 100644 --- a/core/loader/CHANGELOG.md +++ b/core/loader/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-loader diff --git a/core/loader/package.json b/core/loader/package.json index bea6092d..058bf068 100644 --- a/core/loader/package.json +++ b/core/loader/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-loader", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg default loader implement", "keywords": [ "egg", @@ -36,9 +36,9 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "globby": "^11.1.0", "is-type-of": "^1.2.1" }, @@ -46,7 +46,7 @@ "access": "public" }, "devDependencies": { - "@eggjs/tegg-metadata": "^3.57.14", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/core/metadata/CHANGELOG.md b/core/metadata/CHANGELOG.md index ac5e3273..bf82e764 100644 --- a/core/metadata/CHANGELOG.md +++ b/core/metadata/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-metadata diff --git a/core/metadata/package.json b/core/metadata/package.json index ae505881..d65c9830 100644 --- a/core/metadata/package.json +++ b/core/metadata/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-metadata", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg metadata", "keywords": [ "egg", @@ -35,10 +35,10 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "egg-errors": "^2.2.3" }, "devDependencies": { diff --git a/core/orm-decorator/CHANGELOG.md b/core/orm-decorator/CHANGELOG.md index e8537f43..7c7a559e 100644 --- a/core/orm-decorator/CHANGELOG.md +++ b/core/orm-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-orm-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-orm-decorator diff --git a/core/orm-decorator/package.json b/core/orm-decorator/package.json index 17987913..99437fab 100644 --- a/core/orm-decorator/package.json +++ b/core/orm-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-orm-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg orm decorator", "main": "dist/index.js", "files": [ @@ -36,10 +36,10 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "lodash": "^4.17.21", "pluralize": "^8.0.0" }, diff --git a/core/runtime/CHANGELOG.md b/core/runtime/CHANGELOG.md index 3159f1e1..91efd7e1 100644 --- a/core/runtime/CHANGELOG.md +++ b/core/runtime/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-runtime diff --git a/core/runtime/package.json b/core/runtime/package.json index 65cdad92..a73f47f1 100644 --- a/core/runtime/package.json +++ b/core/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-runtime", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg runtime", "main": "dist/index.js", "files": [ @@ -36,14 +36,14 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/tegg-loader": "^3.57.14", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/core/schedule-decorator/CHANGELOG.md b/core/schedule-decorator/CHANGELOG.md index 8ff8cc91..2b1cd623 100644 --- a/core/schedule-decorator/CHANGELOG.md +++ b/core/schedule-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-schedule-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-schedule-decorator diff --git a/core/schedule-decorator/package.json b/core/schedule-decorator/package.json index fd104328..3c406b92 100644 --- a/core/schedule-decorator/package.json +++ b/core/schedule-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-schedule-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg schedule decorator", "main": "dist/index.js", "files": [ @@ -35,10 +35,10 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "cron-parser": "^2.18.0" }, "devDependencies": { diff --git a/core/standalone-decorator/CHANGELOG.md b/core/standalone-decorator/CHANGELOG.md index 4ad4dea5..dc3137b0 100644 --- a/core/standalone-decorator/CHANGELOG.md +++ b/core/standalone-decorator/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/standalone-decorator diff --git a/core/standalone-decorator/package.json b/core/standalone-decorator/package.json index 29377e38..e4ce01ab 100644 --- a/core/standalone-decorator/package.json +++ b/core/standalone-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/standalone-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg standalone decorator", "keywords": [ "egg", @@ -36,7 +36,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/tegg-common-util": "^3.57.14", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", "reflect-metadata": "^0.1.13" }, "publishConfig": { @@ -46,13 +46,13 @@ "@eggjs/tegg": "^3" }, "devDependencies": { + "@eggjs/tegg": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", "mocha": "^10.2.0", "ts-node": "^10.9.1", - "typescript": "^5.0.4", - "@eggjs/tegg": "^3.57.14" + "typescript": "^5.0.4" }, "gitHead": "b49e4c70e7f09a073e989493b995f8dd3ce482e9" } diff --git a/core/tegg/CHANGELOG.md b/core/tegg/CHANGELOG.md index e1c85290..08fb53c4 100644 --- a/core/tegg/CHANGELOG.md +++ b/core/tegg/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg diff --git a/core/tegg/package.json b/core/tegg/package.json index 4a4340fd..4de5f5bf 100644 --- a/core/tegg/package.json +++ b/core/tegg/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg decorator packages", "keywords": [ "egg", @@ -35,24 +35,24 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/ajv-decorator": "^3.57.14", - "@eggjs/aop-decorator": "^3.57.14", - "@eggjs/controller-decorator": "^3.57.14", - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/dal-decorator": "^3.57.14", - "@eggjs/eventbus-decorator": "^3.57.14", - "@eggjs/standalone-decorator": "^3.57.14", - "@eggjs/tegg-background-task": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-dynamic-inject": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-orm-decorator": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", - "@eggjs/tegg-schedule-decorator": "^3.57.14", - "@eggjs/tegg-transaction-decorator": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/ajv-decorator": "^3.57.15-alpha.0", + "@eggjs/aop-decorator": "^3.57.15-alpha.0", + "@eggjs/controller-decorator": "^3.57.15-alpha.0", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/dal-decorator": "^3.57.15-alpha.0", + "@eggjs/eventbus-decorator": "^3.57.15-alpha.0", + "@eggjs/standalone-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-background-task": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-dynamic-inject": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-orm-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-schedule-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-transaction-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "publishConfig": { "access": "public" diff --git a/core/test-util/CHANGELOG.md b/core/test-util/CHANGELOG.md index 2e699d3a..074cc62b 100644 --- a/core/test-util/CHANGELOG.md +++ b/core/test-util/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/module-test-util diff --git a/core/test-util/package.json b/core/test-util/package.json index 59f0836c..6dd903ad 100644 --- a/core/test-util/package.json +++ b/core/test-util/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/module-test-util", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "private": true, "description": "module test util", "keywords": [ @@ -35,11 +35,11 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", "globby": "^11.1.0", "mm": "^3.2.1", "undici": "^5.26.5" diff --git a/core/transaction-decorator/CHANGELOG.md b/core/transaction-decorator/CHANGELOG.md index d2d89f85..f597bf86 100644 --- a/core/transaction-decorator/CHANGELOG.md +++ b/core/transaction-decorator/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-transaction-decorator + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-transaction-decorator diff --git a/core/transaction-decorator/package.json b/core/transaction-decorator/package.json index 649f533a..898a7026 100644 --- a/core/transaction-decorator/package.json +++ b/core/transaction-decorator/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-transaction-decorator", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg transaction decorator", "keywords": [ "egg", @@ -17,10 +17,10 @@ "directory": "core/transaction-decorator" }, "dependencies": { - "@eggjs/core-decorator": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14" + "@eggjs/core-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0" }, "scripts": { "test": "cross-env NODE_ENV=test NODE_OPTIONS='--no-deprecation' mocha", diff --git a/core/types/CHANGELOG.md b/core/types/CHANGELOG.md index 84f735f8..5c473753 100644 --- a/core/types/CHANGELOG.md +++ b/core/types/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-types diff --git a/core/types/package.json b/core/types/package.json index 911afd2f..9fde7836 100644 --- a/core/types/package.json +++ b/core/types/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-types", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "tegg types", "keywords": [ "egg", @@ -37,8 +37,8 @@ "access": "public" }, "devDependencies": { - "@eggjs/mcp-proxy": "^3.57.14", - "@eggjs/tegg-controller-plugin": "^3.57.14", + "@eggjs/mcp-proxy": "^3.57.15-alpha.0", + "@eggjs/tegg-controller-plugin": "^3.57.15-alpha.0", "@modelcontextprotocol/sdk": "^1.10.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", diff --git a/lerna.json b/lerna.json index ff71c387..adf41ece 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "useWorkspaces": true, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "npmClientArgs": [ "--package-lock=false" ], diff --git a/plugin/ajv/CHANGELOG.md b/plugin/ajv/CHANGELOG.md index aad45797..6b73dedc 100644 --- a/plugin/ajv/CHANGELOG.md +++ b/plugin/ajv/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-ajv-plugin + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-ajv-plugin diff --git a/plugin/ajv/package.json b/plugin/ajv/package.json index 0189251b..4f6fbb21 100644 --- a/plugin/ajv/package.json +++ b/plugin/ajv/package.json @@ -10,7 +10,7 @@ "eggModule": { "name": "teggAjv" }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "ajv plugin for egg and tegg", "keywords": [ "egg", @@ -48,14 +48,14 @@ "dependencies": { "@eggjs/ajv-formats": "^3.0.1", "@eggjs/ajv-keywords": "^5.1.0", - "@eggjs/tegg": "^3.57.14", + "@eggjs/tegg": "^3.57.15-alpha.0", "@sinclair/typebox": "^0.32.20", "ajv": "^8.12.0" }, "devDependencies": { - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-controller-plugin": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-controller-plugin": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/plugin/aop/CHANGELOG.md b/plugin/aop/CHANGELOG.md index 5e98cd79..ee84443d 100644 --- a/plugin/aop/CHANGELOG.md +++ b/plugin/aop/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-aop-plugin + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-aop-plugin diff --git a/plugin/aop/package.json b/plugin/aop/package.json index 44d08fa7..13d22f68 100644 --- a/plugin/aop/package.json +++ b/plugin/aop/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-aop-plugin", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "eggPlugin": { "name": "aopModule", "dependencies": [ @@ -42,15 +42,15 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/aop-decorator": "^3.57.14", - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-aop-runtime": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14" + "@eggjs/aop-decorator": "^3.57.15-alpha.0", + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-aop-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/plugin/common/CHANGELOG.md b/plugin/common/CHANGELOG.md index 45d949bd..1ed4c76f 100644 --- a/plugin/common/CHANGELOG.md +++ b/plugin/common/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/egg-module-common + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/egg-module-common diff --git a/plugin/common/package.json b/plugin/common/package.json index 336d5e07..2be7502e 100644 --- a/plugin/common/package.json +++ b/plugin/common/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/egg-module-common", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "common module", "keywords": [ "egg", diff --git a/plugin/config/CHANGELOG.md b/plugin/config/CHANGELOG.md index 8b7a9371..002db65d 100644 --- a/plugin/config/CHANGELOG.md +++ b/plugin/config/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-config + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-config diff --git a/plugin/config/package.json b/plugin/config/package.json index 3c0021c7..0ced30b8 100644 --- a/plugin/config/package.json +++ b/plugin/config/package.json @@ -3,7 +3,7 @@ "eggPlugin": { "name": "teggConfig" }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "module config plugin for egg", "keywords": [ "egg", @@ -43,7 +43,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/tegg-common-util": "^3.57.14" + "@eggjs/tegg-common-util": "^3.57.15-alpha.0" }, "devDependencies": { "@types/mocha": "^10.0.1", diff --git a/plugin/controller/CHANGELOG.md b/plugin/controller/CHANGELOG.md index b6a28339..6e561a35 100644 --- a/plugin/controller/CHANGELOG.md +++ b/plugin/controller/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-controller-plugin + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-controller-plugin diff --git a/plugin/controller/package.json b/plugin/controller/package.json index 1faf1241..965e7623 100644 --- a/plugin/controller/package.json +++ b/plugin/controller/package.json @@ -7,7 +7,7 @@ "tegg" ] }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "controller decorator for egg", "keywords": [ "egg", @@ -48,14 +48,14 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/mcp-proxy": "^3.57.14", + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/mcp-proxy": "^3.57.15-alpha.0", "@eggjs/router": "^2.0.1", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", "@modelcontextprotocol/sdk": "^1.10.0", "await-event": "^2.1.0", "content-type": "^1.0.5", @@ -68,9 +68,9 @@ "zod": "^3.24.4" }, "devDependencies": { - "@eggjs/module-test-util": "^3.57.14", - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/plugin/dal/CHANGELOG.md b/plugin/dal/CHANGELOG.md index 53dd5979..399195b9 100644 --- a/plugin/dal/CHANGELOG.md +++ b/plugin/dal/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-dal-plugin diff --git a/plugin/dal/package.json b/plugin/dal/package.json index 1e08d5b8..55d73874 100644 --- a/plugin/dal/package.json +++ b/plugin/dal/package.json @@ -10,7 +10,7 @@ "eggModule": { "name": "teggDal" }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "dal plugin for egg", "keywords": [ "egg", @@ -50,12 +50,12 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/dal-runtime": "^3.57.14" + "@eggjs/dal-runtime": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/tegg-aop-plugin": "^3.57.14", - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/tegg-aop-plugin": "^3.57.15-alpha.0", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/plugin/eventbus/CHANGELOG.md b/plugin/eventbus/CHANGELOG.md index 08320833..5004f1f0 100644 --- a/plugin/eventbus/CHANGELOG.md +++ b/plugin/eventbus/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-eventbus-plugin + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-eventbus-plugin diff --git a/plugin/eventbus/package.json b/plugin/eventbus/package.json index a02028e1..ae193b56 100644 --- a/plugin/eventbus/package.json +++ b/plugin/eventbus/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/tegg-eventbus-plugin", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "eggPlugin": { "name": "eventbusModule", "strict": false, @@ -48,16 +48,16 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-eventbus-runtime": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14" + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-eventbus-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "await-event": "^2.1.0", diff --git a/plugin/mcp-proxy/CHANGELOG.md b/plugin/mcp-proxy/CHANGELOG.md index 79f668a8..3a2fce25 100644 --- a/plugin/mcp-proxy/CHANGELOG.md +++ b/plugin/mcp-proxy/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/mcp-proxy + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/mcp-proxy diff --git a/plugin/mcp-proxy/package.json b/plugin/mcp-proxy/package.json index f7ec2275..32bba64c 100644 --- a/plugin/mcp-proxy/package.json +++ b/plugin/mcp-proxy/package.json @@ -1,6 +1,6 @@ { "name": "@eggjs/mcp-proxy", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "eggPlugin": { "name": "mcpProxy" }, @@ -51,8 +51,8 @@ }, "dependencies": { "@eggjs/core": "^6.5.0", - "@eggjs/tegg-controller-plugin": "^3.57.14", - "@eggjs/tegg-types": "^3.57.14", + "@eggjs/tegg-controller-plugin": "^3.57.15-alpha.0", + "@eggjs/tegg-types": "^3.57.15-alpha.0", "@modelcontextprotocol/sdk": "^1.10.0", "await-event": "^2.1.0", "cluster-client": "^3.7.0", @@ -63,12 +63,12 @@ "zod": "^3.24.4" }, "devDependencies": { - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-aop-runtime": "^3.57.14", - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-aop-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/plugin/orm/CHANGELOG.md b/plugin/orm/CHANGELOG.md index 66ea0563..a381eef2 100644 --- a/plugin/orm/CHANGELOG.md +++ b/plugin/orm/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-orm-plugin + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-orm-plugin diff --git a/plugin/orm/package.json b/plugin/orm/package.json index 6cd37f75..4e4534e8 100644 --- a/plugin/orm/package.json +++ b/plugin/orm/package.json @@ -6,7 +6,7 @@ "tegg" ] }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "orm decorator for egg", "keywords": [ "egg", @@ -48,24 +48,24 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-orm-decorator": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-orm-decorator": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", "@types/koa-router": "^7.0.40", "koa-compose": "^3.2.1", "leoric": "^2.12.2", "sdk-base": "^4.2.0" }, "devDependencies": { - "@eggjs/module-test-util": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", "@eggjs/router": "^2.0.0", - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/plugin/schedule/CHANGELOG.md b/plugin/schedule/CHANGELOG.md index 37383288..7c2bf2ba 100644 --- a/plugin/schedule/CHANGELOG.md +++ b/plugin/schedule/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-schedule-plugin + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-schedule-plugin diff --git a/plugin/schedule/package.json b/plugin/schedule/package.json index a65f1c01..2cdc526a 100644 --- a/plugin/schedule/package.json +++ b/plugin/schedule/package.json @@ -7,7 +7,7 @@ "schedule" ] }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "schedule decorator for egg", "keywords": [ "egg", @@ -49,19 +49,19 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", - "@eggjs/tegg-schedule-decorator": "^3.57.14" + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-schedule-decorator": "^3.57.15-alpha.0" }, "devDependencies": { - "@eggjs/module-test-util": "^3.57.14", - "@eggjs/tegg-config": "^3.57.14", - "@eggjs/tegg-plugin": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", + "@eggjs/tegg-config": "^3.57.15-alpha.0", + "@eggjs/tegg-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/plugin/tegg/CHANGELOG.md b/plugin/tegg/CHANGELOG.md index 9b77f69c..691de443 100644 --- a/plugin/tegg/CHANGELOG.md +++ b/plugin/tegg/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + +**Note:** Version bump only for package @eggjs/tegg-plugin + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-plugin diff --git a/plugin/tegg/package.json b/plugin/tegg/package.json index a3f3c0d1..afecebe8 100644 --- a/plugin/tegg/package.json +++ b/plugin/tegg/package.json @@ -6,7 +6,7 @@ "teggConfig" ] }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "description": "module plugin for egg", "keywords": [ "egg", @@ -45,21 +45,21 @@ "node": ">=14.0.0" }, "dependencies": { - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-background-task": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-dynamic-inject-runtime": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-background-task": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-dynamic-inject-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", "await-event": "^2.1.0", "await-first": "^1.0.0", "extend2": "^1.0.0", "sdk-base": "^4.2.0" }, "devDependencies": { - "@eggjs/tegg-config": "^3.57.14", + "@eggjs/tegg-config": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/standalone/controller/CHANGELOG.md b/standalone/controller/CHANGELOG.md new file mode 100644 index 00000000..7ea26b0a --- /dev/null +++ b/standalone/controller/CHANGELOG.md @@ -0,0 +1,16 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Bug Fixes + +* repo dir ([2e7351b](https://github.com/eggjs/tegg/commit/2e7351bc62161b203f7a98a978d9a901165fb516)) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) diff --git a/standalone/controller/package.json b/standalone/controller/package.json index 042fda01..bd307017 100644 --- a/standalone/controller/package.json +++ b/standalone/controller/package.json @@ -4,7 +4,7 @@ "eggModule": { "name": "standaloneController" }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "keywords": [ "egg", "typescript", @@ -54,9 +54,9 @@ "@eggjs/tegg-service-worker": "^3" }, "devDependencies": { - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-service-worker": "^3.57.14", - "@eggjs/module-test-util": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-service-worker": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "@types/type-is": "^1.6.0", diff --git a/standalone/service-worker-runtime/CHANGELOG.md b/standalone/service-worker-runtime/CHANGELOG.md new file mode 100644 index 00000000..7ea26b0a --- /dev/null +++ b/standalone/service-worker-runtime/CHANGELOG.md @@ -0,0 +1,16 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Bug Fixes + +* repo dir ([2e7351b](https://github.com/eggjs/tegg/commit/2e7351bc62161b203f7a98a978d9a901165fb516)) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) diff --git a/standalone/service-worker-runtime/package.json b/standalone/service-worker-runtime/package.json index c58c0538..8123bb68 100644 --- a/standalone/service-worker-runtime/package.json +++ b/standalone/service-worker-runtime/package.json @@ -4,7 +4,7 @@ "eggModule": { "name": "serviceWorkerRuntime" }, - "version": "3.57.14", + "version": "3.57.15-alpha.0", "keywords": [ "egg", "typescript", @@ -48,9 +48,9 @@ "@eggjs/tegg": "^3" }, "devDependencies": { - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-standalone": "^3.57.14", - "@eggjs/module-test-util": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-standalone": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/standalone/service-worker/CHANGELOG.md b/standalone/service-worker/CHANGELOG.md new file mode 100644 index 00000000..7ea26b0a --- /dev/null +++ b/standalone/service-worker/CHANGELOG.md @@ -0,0 +1,16 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Bug Fixes + +* repo dir ([2e7351b](https://github.com/eggjs/tegg/commit/2e7351bc62161b203f7a98a978d9a901165fb516)) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) diff --git a/standalone/service-worker/package.json b/standalone/service-worker/package.json index 3199ebe2..a55523a8 100644 --- a/standalone/service-worker/package.json +++ b/standalone/service-worker/package.json @@ -1,7 +1,7 @@ { "name": "@eggjs/tegg-service-worker", "description": "tegg service worker", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "keywords": [ "egg", "typescript", @@ -42,20 +42,20 @@ "access": "public" }, "dependencies": { - "@eggjs/tegg-standalone": "^3.57.14", - "@eggjs/tegg-dynamic-inject-runtime": "^3.57.14", - "@eggjs/tegg-ajv-plugin": "^3.57.14", - "@eggjs/tegg-dal-plugin": "^3.57.14", - "@eggjs/tegg-aop-runtime": "^3.57.14", - "@eggjs/tegg-service-worker-runtime": "^3.57.14", - "@eggjs/tegg-standalone-controller": "^3.57.14" + "@eggjs/tegg-ajv-plugin": "^3.57.15-alpha.0", + "@eggjs/tegg-aop-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-dal-plugin": "^3.57.15-alpha.0", + "@eggjs/tegg-dynamic-inject-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-service-worker-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-standalone": "^3.57.15-alpha.0", + "@eggjs/tegg-standalone-controller": "^3.57.15-alpha.0" }, "peerDependencies": { "@eggjs/tegg": "^3" }, "devDependencies": { - "@eggjs/tegg": "^3.57.14", - "@eggjs/module-test-util": "^3.57.14", + "@eggjs/module-test-util": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3", diff --git a/standalone/standalone/CHANGELOG.md b/standalone/standalone/CHANGELOG.md index 4d7daa45..ea929bac 100644 --- a/standalone/standalone/CHANGELOG.md +++ b/standalone/standalone/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.57.15-alpha.0](https://github.com/eggjs/tegg/compare/v3.57.14...v3.57.15-alpha.0) (2025-06-27) + + +### Features + +* module plugin ([#325](https://github.com/eggjs/tegg/issues/325)) ([d10bcb6](https://github.com/eggjs/tegg/commit/d10bcb611dbc499ae86558828f91bae3f7266766)) + + + + + ## [3.57.14](https://github.com/eggjs/tegg/compare/v3.57.13...v3.57.14) (2025-06-18) **Note:** Version bump only for package @eggjs/tegg-standalone diff --git a/standalone/standalone/package.json b/standalone/standalone/package.json index 6ce5ce50..da99c21f 100644 --- a/standalone/standalone/package.json +++ b/standalone/standalone/package.json @@ -1,7 +1,7 @@ { "name": "@eggjs/tegg-standalone", "description": "tegg standalone", - "version": "3.57.14", + "version": "3.57.15-alpha.0", "keywords": [ "egg", "typescript", @@ -38,24 +38,24 @@ "author": "killagu ", "license": "MIT", "dependencies": { - "@eggjs/egg-module-common": "^3.57.14", - "@eggjs/tegg": "^3.57.14", - "@eggjs/tegg-aop-runtime": "^3.57.14", - "@eggjs/tegg-background-task": "^3.57.14", - "@eggjs/tegg-common-util": "^3.57.14", - "@eggjs/tegg-dal-plugin": "^3.57.14", - "@eggjs/tegg-dynamic-inject-runtime": "^3.57.14", - "@eggjs/tegg-lifecycle": "^3.57.14", - "@eggjs/tegg-loader": "^3.57.14", - "@eggjs/tegg-metadata": "^3.57.14", - "@eggjs/tegg-runtime": "^3.57.14", + "@eggjs/egg-module-common": "^3.57.15-alpha.0", + "@eggjs/tegg": "^3.57.15-alpha.0", + "@eggjs/tegg-aop-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-background-task": "^3.57.15-alpha.0", + "@eggjs/tegg-common-util": "^3.57.15-alpha.0", + "@eggjs/tegg-dal-plugin": "^3.57.15-alpha.0", + "@eggjs/tegg-dynamic-inject-runtime": "^3.57.15-alpha.0", + "@eggjs/tegg-lifecycle": "^3.57.15-alpha.0", + "@eggjs/tegg-loader": "^3.57.15-alpha.0", + "@eggjs/tegg-metadata": "^3.57.15-alpha.0", + "@eggjs/tegg-runtime": "^3.57.15-alpha.0", "time-profile": "^2.0.0" }, "publishConfig": { "access": "public" }, "devDependencies": { - "@eggjs/tegg-ajv-plugin": "^3.57.14", + "@eggjs/tegg-ajv-plugin": "^3.57.15-alpha.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.4", "cross-env": "^7.0.3",