Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ catalog:
type-is: ^2.0.0
typebox: ^1.0.65
typescript: ^5.9.3
undici: ^7.10.0
unplugin-unused: ^0.5.4
urijs: ^1.19.11
urllib: ^4.8.2
Expand Down
27 changes: 27 additions & 0 deletions tegg/core/standalone-decorator/src/event/EventHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { type EggProtoImplClass, ImplDecorator, SingletonProtoParams } from '@eggjs/tegg-types';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify TS1484 risk and import style usage in this file + tsconfig flag presence.
rg -n "verbatimModuleSyntax" --iglob "tsconfig*.json"
rg -n "from '@eggjs/tegg-types'" tegg/core/standalone-decorator/src/event/EventHandler.ts

Repository: eggjs/egg

Length of output: 271


🏁 Script executed:

#!/bin/bash
# Find where ImplDecorator and SingletonProtoParams are defined in `@eggjs/tegg-types`
find . -type f -name "*.ts" -path "*tegg-types*" | head -20

Repository: eggjs/egg

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Read the EventHandler.ts file to verify all issues
cat -n tegg/core/standalone-decorator/src/event/EventHandler.ts

Repository: eggjs/egg

Length of output: 1244


🏁 Script executed:

#!/bin/bash
# Find the `@eggjs/tegg-types` package and check exports
find . -type f -name "*.ts" | xargs grep -l "export.*ImplDecorator" | grep -v node_modules | head -5

Repository: eggjs/egg

Length of output: 654


🏁 Script executed:

#!/bin/bash
# Search for SingletonProtoParams export
find . -type f -name "*.ts" | xargs grep -l "export.*SingletonProtoParams" | grep -v node_modules | head -5

Repository: eggjs/egg

Length of output: 579


🏁 Script executed:

#!/bin/bash
# Find where `@eggjs/tegg-types` is defined/exported
find . -type f -name "*.ts" -path "*tegg*" | xargs grep -l "export.*type.*ImplDecorator\|export.*interface.*ImplDecorator" | grep -v node_modules | grep -v test | head -10

Repository: eggjs/egg

Length of output: 92


🏁 Script executed:

#!/bin/bash
# List tegg packages to find tegg-types
ls -la tegg/*/package.json | grep -i types

Repository: eggjs/egg

Length of output: 119


🏁 Script executed:

#!/bin/bash
# List tegg directory structure
ls -la tegg/

Repository: eggjs/egg

Length of output: 591


🏁 Script executed:

#!/bin/bash
# Check the types package
cat tegg/core/types/src/dynamic-inject.ts | head -80

Repository: eggjs/egg

Length of output: 776


🏁 Script executed:

#!/bin/bash
# Search for SingletonProtoParams definition
rg -n "export.*SingletonProtoParams" --type ts tegg/

Repository: eggjs/egg

Length of output: 1098


🏁 Script executed:

#!/bin/bash
# Check the entire dynamic-inject.ts file for SingletonProtoParams
cat tegg/core/types/src/dynamic-inject.ts | grep -A 5 "SingletonProtoParams"

Repository: eggjs/egg

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Check the SingletonProtoParams definition
cat tegg/core/types/src/core-decorator/SingletonProto.ts

Repository: eggjs/egg

Length of output: 219


🏁 Script executed:

#!/bin/bash
# Check the full types index to see what's exported from `@eggjs/tegg-types`
find tegg/core/types -name "index.ts" -o -name "*.ts" | xargs grep -l "export.*ImplDecorator\|export.*SingletonProtoParams" | head -5

Repository: eggjs/egg

Length of output: 143


🏁 Script executed:

#!/bin/bash
# Check what tegg-types actually exports (check its index)
find tegg/core/types -name "index.ts" -exec cat {} \; | head -100

Repository: eggjs/egg

Length of output: 3523


🏁 Script executed:

#!/bin/bash
# Verify the package name in tegg/core/types
cat tegg/core/types/package.json | grep -E '"name"|"exports"' -A 5

Repository: eggjs/egg

Length of output: 841


Fix TS1484 by using type-only imports at Line 1.

ImplDecorator and SingletonProtoParams are types exported from @eggjs/tegg-types. With verbatimModuleSyntax: true in root tsconfig.json, type-only imports require the type keyword.

🔧 Proposed fix
-import { type EggProtoImplClass, ImplDecorator, SingletonProtoParams } from '@eggjs/tegg-types';
+import { type EggProtoImplClass, type ImplDecorator, type SingletonProtoParams } from '@eggjs/tegg-types';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { type EggProtoImplClass, ImplDecorator, SingletonProtoParams } from '@eggjs/tegg-types';
import { type EggProtoImplClass, type ImplDecorator, type SingletonProtoParams } from '@eggjs/tegg-types';
🧰 Tools
🪛 GitHub Check: typecheck

[failure] 1-1: typescript(TS1484)
'SingletonProtoParams' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.


[failure] 1-1: typescript(TS1484)
'ImplDecorator' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/standalone-decorator/src/event/EventHandler.ts` at line 1, The
import currently marks only EggProtoImplClass as a type, triggering TS1484 under
verbatimModuleSyntax; update the import to use type-only imports for the
exported types by marking ImplDecorator and SingletonProtoParams as type-only as
well (e.g., change the clause to import type { EggProtoImplClass, ImplDecorator,
SingletonProtoParams } from '@eggjs/tegg-types' or prefix each with type), so
adjust the import line that references EggProtoImplClass, ImplDecorator, and
SingletonProtoParams in EventHandler.ts accordingly.

import { QualifierImplDecoratorUtil, SingletonProto } from '@eggjs/tegg';

export abstract class AbstractEventHandler<E = any, R = any> {
abstract handleEvent(event: E): Promise<R>;
}

export const EVENT_HANDLER_ATTRIBUTE = Symbol('EVENT_HANDLER_ATTRIBUTE');

export type EventType = Record<string, string>;

export const EventHandler: ImplDecorator<AbstractEventHandler, EventType> =
QualifierImplDecoratorUtil.generatorDecorator(AbstractEventHandler, EVENT_HANDLER_ATTRIBUTE);

export const EventHandlerProto = (type: EventType[keyof EventType], params?: SingletonProtoParams) => {
return (clazz: EggProtoImplClass<AbstractEventHandler>) => {
EventHandler(type)(clazz);
SingletonProto(params)(clazz);
};
};
Comment on lines +4 to +20
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Tighten types on the newly exported public API.

Several guideline-level issues on this new decorator module:

  1. Line 8EVENT_HANDLER_ATTRIBUTE is declared as a bare Symbol(). Exported symbols should carry a unique symbol annotation to remain nominal across consumers. As per coding guidelines: "Use 'unique symbol' type annotation for exported symbols instead of bare Symbol() declarations".
  2. Line 4AbstractEventHandler<E = any, R = any> uses any defaults. As per coding guidelines: "Avoid 'any' type in TypeScript; use 'unknown' when type is truly unknown".
  3. Lines 15–20EventHandlerProto and its inner returned function both lack explicit return types. As per coding guidelines: "All exported functions, methods, and getters must have explicit return type annotations to support TypeScript's --isolatedDeclarations flag".
🔧 Proposed fix
-export abstract class AbstractEventHandler<E = any, R = any> {
+export abstract class AbstractEventHandler<E = unknown, R = unknown> {
   abstract handleEvent(event: E): Promise<R>;
 }

-export const EVENT_HANDLER_ATTRIBUTE = Symbol('EVENT_HANDLER_ATTRIBUTE');
+export const EVENT_HANDLER_ATTRIBUTE: unique symbol = Symbol('EVENT_HANDLER_ATTRIBUTE');

 export type EventType = Record<string, string>;

 export const EventHandler: ImplDecorator<AbstractEventHandler, EventType> =
   QualifierImplDecoratorUtil.generatorDecorator(AbstractEventHandler, EVENT_HANDLER_ATTRIBUTE);

-export const EventHandlerProto = (type: EventType[keyof EventType], params?: SingletonProtoParams) => {
-  return (clazz: EggProtoImplClass<AbstractEventHandler>) => {
+export const EventHandlerProto = (
+  type: EventType[keyof EventType],
+  params?: SingletonProtoParams,
+): ((clazz: EggProtoImplClass<AbstractEventHandler>) => void) => {
+  return (clazz: EggProtoImplClass<AbstractEventHandler>): void => {
     EventHandler(type)(clazz);
     SingletonProto(params)(clazz);
   };
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export abstract class AbstractEventHandler<E = any, R = any> {
abstract handleEvent(event: E): Promise<R>;
}
export const EVENT_HANDLER_ATTRIBUTE = Symbol('EVENT_HANDLER_ATTRIBUTE');
export type EventType = Record<string, string>;
export const EventHandler: ImplDecorator<AbstractEventHandler, EventType> =
QualifierImplDecoratorUtil.generatorDecorator(AbstractEventHandler, EVENT_HANDLER_ATTRIBUTE);
export const EventHandlerProto = (type: EventType[keyof EventType], params?: SingletonProtoParams) => {
return (clazz: EggProtoImplClass<AbstractEventHandler>) => {
EventHandler(type)(clazz);
SingletonProto(params)(clazz);
};
};
export abstract class AbstractEventHandler<E = unknown, R = unknown> {
abstract handleEvent(event: E): Promise<R>;
}
export const EVENT_HANDLER_ATTRIBUTE: unique symbol = Symbol('EVENT_HANDLER_ATTRIBUTE');
export type EventType = Record<string, string>;
export const EventHandler: ImplDecorator<AbstractEventHandler, EventType> =
QualifierImplDecoratorUtil.generatorDecorator(AbstractEventHandler, EVENT_HANDLER_ATTRIBUTE);
export const EventHandlerProto = (
type: EventType[keyof EventType],
params?: SingletonProtoParams,
): ((clazz: EggProtoImplClass<AbstractEventHandler>) => void) => {
return (clazz: EggProtoImplClass<AbstractEventHandler>): void => {
EventHandler(type)(clazz);
SingletonProto(params)(clazz);
};
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/standalone-decorator/src/event/EventHandler.ts` around lines 4 -
20, The exported API needs stronger TypeScript typing: change
AbstractEventHandler's generic defaults from "any" to "unknown" (update
AbstractEventHandler<E = unknown, R = unknown>), annotate
EVENT_HANDLER_ATTRIBUTE as a unique symbol (use "export const
EVENT_HANDLER_ATTRIBUTE: unique symbol = Symbol('EVENT_HANDLER_ATTRIBUTE')"),
and add explicit return type annotations for EventHandlerProto and its returned
decorator function (declare the return type of EventHandlerProto and the inner
function explicitly to match EggProtoImplClass<AbstractEventHandler> -> void or
the appropriate decorator signature). Ensure you update references to these
symbols/types in the file to match the new signatures.


export interface FetchEventLike {
type: string;
request: Request;
respondWith(response: Response | Promise<Response>): void;
waitUntil?(promise: Promise<unknown>): void;
}
1 change: 1 addition & 0 deletions tegg/core/standalone-decorator/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './typing.ts';
export * from './util/index.ts';
export * from './decorator/index.ts';
export * from './event/EventHandler.ts';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and look at the content around line 4
fd -t f "index.ts" tegg/core/standalone-decorator/src/ -x cat -n {}

Repository: eggjs/egg

Length of output: 301


🏁 Script executed:

# Also check the EventHandler.ts file to see the actual exports
fd -t f "EventHandler.ts" tegg/core/standalone-decorator/ -x cat -n {}

Repository: eggjs/egg

Length of output: 1014


Update re-export specifier and exposed public API to meet strict TypeScript guidelines.

Line 4 uses .ts extension which violates ESM requirements. Additionally, the re-exported EventHandler.ts module contains several strict mode violations that must be fixed before exposure:

  • AbstractEventHandler uses any defaults instead of unknown
  • EVENT_HANDLER_ATTRIBUTE is a bare Symbol() without unique symbol annotation
  • EventHandlerProto lacks explicit return type annotation
  • EventType uses type alias instead of interface
  • Exported symbols lack JSDoc documentation
Required changes

Update line 4 in tegg/core/standalone-decorator/src/index.ts:

-export * from './event/EventHandler.ts';
+export * from './event/EventHandler.js';

Update tegg/core/standalone-decorator/src/event/EventHandler.ts:

/**
 * Abstract base class for event handlers
 */
export abstract class AbstractEventHandler<E = unknown, R = unknown> {
  abstract handleEvent(event: E): Promise<R>;
}

/** Attribute key for event handler qualifiers */
export const EVENT_HANDLER_ATTRIBUTE: unique symbol = Symbol('EVENT_HANDLER_ATTRIBUTE');

/** Event type mapping */
export interface EventType {
  readonly [key: string]: string;
}

/**
 * Decorator to create an event handler prototype scoped as singleton
 */
export const EventHandlerProto = (type: EventType[keyof EventType], params?: SingletonProtoParams): ((clazz: EggProtoImplClass<AbstractEventHandler>) => void) => {
  return (clazz: EggProtoImplClass<AbstractEventHandler>) => {
    EventHandler(type)(clazz);
    SingletonProto(params)(clazz);
  };
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export * from './event/EventHandler.ts';
export * from './event/EventHandler.js';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/standalone-decorator/src/index.ts` at line 4, Update the public
re-export to drop the .ts extension (export * from './event/EventHandler') and
modify the EventHandler module: change AbstractEventHandler generic defaults
from any to unknown and make handleEvent return Promise<R>, declare
EVENT_HANDLER_ATTRIBUTE as const EVENT_HANDLER_ATTRIBUTE: unique symbol =
Symbol('EVENT_HANDLER_ATTRIBUTE'), convert EventType to an interface using
readonly index signature, give EventHandlerProto an explicit function return
type ((type: EventType[keyof EventType], params?: SingletonProtoParams) =>
(clazz: EggProtoImplClass<AbstractEventHandler>) => void) and ensure
EventHandlerProto calls EventHandler(type)(clazz) and
SingletonProto(params)(clazz); add concise JSDoc comments for exported symbols
(AbstractEventHandler, EVENT_HANDLER_ATTRIBUTE, EventType, EventHandlerProto) to
meet strict TypeScript guidelines.

6 changes: 5 additions & 1 deletion tegg/core/test-util/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@
"types": "./dist/index.d.ts",
"exports": {
".": "./src/index.ts",
"./StandaloneTestUtil": "./src/StandaloneTestUtil.ts",
"./package.json": "./package.json"
},
"publishConfig": {
"exports": {
".": "./dist/index.js",
"./StandaloneTestUtil": "./dist/StandaloneTestUtil.js",
"./package.json": "./package.json"
}
},
Expand All @@ -47,7 +49,9 @@
"@eggjs/tegg-common-util": "workspace:*",
"@eggjs/tegg-loader": "workspace:*",
"@eggjs/tegg-runtime": "workspace:*",
"globby": "catalog:"
"@eggjs/tegg-types": "workspace:*",
"globby": "catalog:",
"undici": "catalog:"
},
"devDependencies": {
"@types/node": "catalog:",
Expand Down
81 changes: 81 additions & 0 deletions tegg/core/test-util/src/StandaloneTestUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { createServer, IncomingMessage, OutgoingHttpHeaders, Server, ServerOptions, ServerResponse } from 'node:http';

Check failure on line 1 in tegg/core/test-util/src/StandaloneTestUtil.ts

View workflow job for this annotation

GitHub Actions / typecheck

typescript(TS1484)

'ServerOptions' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.

Check failure on line 1 in tegg/core/test-util/src/StandaloneTestUtil.ts

View workflow job for this annotation

GitHub Actions / typecheck

typescript(TS1484)

'OutgoingHttpHeaders' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
import { pipeline } from 'node:stream';
import { Headers, BodyInit, Request, Response } from 'undici';

Check failure on line 3 in tegg/core/test-util/src/StandaloneTestUtil.ts

View workflow job for this annotation

GitHub Actions / typecheck

typescript(TS1484)

'BodyInit' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
import { FetchEvent } from '@eggjs/tegg-types/standalone';

Check failure on line 4 in tegg/core/test-util/src/StandaloneTestUtil.ts

View workflow job for this annotation

GitHub Actions / typecheck

typescript(TS1484)

'FetchEvent' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
Comment on lines +1 to +4
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Convert type-only imports (TS1484).

♻️ Proposed fix
-import { createServer, IncomingMessage, OutgoingHttpHeaders, Server, ServerOptions, ServerResponse } from 'node:http';
+import { createServer, IncomingMessage, Server, ServerResponse } from 'node:http';
+import type { OutgoingHttpHeaders, ServerOptions } from 'node:http';
 import { pipeline } from 'node:stream';
-import { Headers, BodyInit, Request, Response } from 'undici';
-import { FetchEvent } from '@eggjs/tegg-types/standalone';
+import { Headers, Request, Response } from 'undici';
+import type { BodyInit } from 'undici';
+import type { FetchEvent } from '@eggjs/tegg-types/standalone';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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';
import { createServer, IncomingMessage, Server, ServerResponse } from 'node:http';
import type { OutgoingHttpHeaders, ServerOptions } from 'node:http';
import { pipeline } from 'node:stream';
import { Headers, Request, Response } from 'undici';
import type { BodyInit } from 'undici';
import type { FetchEvent } from '@eggjs/tegg-types/standalone';
🧰 Tools
🪛 GitHub Check: typecheck

[failure] 4-4: typescript(TS1484)
'FetchEvent' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.


[failure] 3-3: typescript(TS1484)
'BodyInit' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.


[failure] 1-1: typescript(TS1484)
'ServerOptions' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.


[failure] 1-1: typescript(TS1484)
'OutgoingHttpHeaders' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/test-util/src/StandaloneTestUtil.ts` around lines 1 - 4, Convert
the type-only imports to "import type" to satisfy TS1484: keep value imports for
runtime symbols (createServer, pipeline) but change all pure types to type-only
imports — specifically change IncomingMessage, OutgoingHttpHeaders, Server,
ServerOptions, ServerResponse (from 'node:http') and Headers, BodyInit, Request,
Response (from 'undici') and FetchEvent (from '@eggjs/tegg-types/standalone') to
use "import type" while leaving createServer and pipeline as regular imports so
runtime behavior is unchanged.


export type FetchEventListener = (event: FetchEvent) => Promise<Response>;

export interface StartHTTPServerOptions extends ServerOptions {
listener: FetchEventListener;
}

export class StandaloneTestUtil {
static skipOnNode(minVersion = 18) {
const version = parseInt(process.versions.node.split('.')[0], 10);
return version < minVersion;
}
Comment on lines +13 to +16
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add explicit return types for public static methods.

skipOnNode and startHTTPServer are exported public APIs and need explicit return type annotations per coding guidelines. Also consider typing #buildRequest and #createHTTPServerListener for consistency.

♻️ Proposed fix
-  static skipOnNode(minVersion = 18) {
+  static skipOnNode(minVersion = 18): boolean {
     ...
-  static startHTTPServer(host: string, port: number, { listener, ...options }: StartHTTPServerOptions) {
+  static startHTTPServer(host: string, port: number, { listener, ...options }: StartHTTPServerOptions): Promise<Server> {

As per coding guidelines: "All exported functions, methods, and getters must have explicit return type annotations to support TypeScript's --isolatedDeclarations flag".

Also applies to: 73-80

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/test-util/src/StandaloneTestUtil.ts` around lines 13 - 16, Add
explicit return type annotations for the exported public static methods and type
the private helpers: change skipOnNode to have a boolean return type
(skipOnNode(minVersion = 18): boolean), annotate startHTTPServer with an
explicit Promise return (e.g. startHTTPServer(...):
Promise<import("http").Server> or the project's Server type), and add types for
the private helpers `#buildRequest` (e.g. (req: import("http").IncomingMessage) =>
SomeRequestType) and `#createHTTPServerListener` (e.g. (req:
import("http").IncomingMessage, res: import("http").ServerResponse) => void) so
the signatures are explicit and satisfy --isolatedDeclarations.


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();
}
});
};
}
Comment on lines +45 to +71
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Client-disconnect / listener error paths swallow errors and may leave response hanging.

A couple of robustness concerns in the per-request listener:

  1. If listener(event) throws, the exception bubbles out of the async handler and Node's http server emits 'clientError' / leaves the socket without a written response. Wrap the body in try/catch and res.writeHead(500).end() as a fallback.
  2. Inside pipeline, console.error is used for logging — OK for a test util, but note that if the client disconnects early (ECONNRESET/ERR_STREAM_PREMATURE_CLOSE), you'll get spurious errors. Consider filtering those.
  3. req.headers.host = url.host; mutates the incoming request headers object as a side effect before copying — harmless but non-obvious; it should be documented or done only on the copied Headers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/test-util/src/StandaloneTestUtil.ts` around lines 45 - 71, In
StandaloneTestUtil.#createHTTPServerListener, wrap the call to listener(event)
and all response writing in a try/catch so any thrown error results in a safe
fallback (writeHead(500) and res.end()) rather than bubbling to the http server;
ensure the catch also ends the response when headers/body may already be
partially written. In the pipeline callback, filter/ignore expected client
disconnect errors (e.g. ECONNRESET, ERR_STREAM_PREMATURE_CLOSE) and only log
unexpected errors, then ensure res.end() is called on error paths. Finally stop
mutating the incoming req.headers.host directly in
`#createHTTPServerListener/`#buildRequest — set host on the copied Headers (from
StandaloneTestUtil.#buildRequest) or document the side effect so the original
request object is not modified unexpectedly.


static startHTTPServer(host: string, port: number, { listener, ...options }: StartHTTPServerOptions) {
const serverListener = StandaloneTestUtil.#createHTTPServerListener(listener);
const server = createServer(options ?? {}, serverListener);

return new Promise<Server>(resolve => {
server.listen(port, host, () => resolve(server));
});
}
}
6 changes: 6 additions & 0 deletions tegg/core/types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@
"./runtime/model/EggObject": "./src/runtime/model/EggObject.ts",
"./runtime/model/LoadUnitInstance": "./src/runtime/model/LoadUnitInstance.ts",
"./schedule": "./src/schedule.ts",
"./standalone": "./standalone/index.ts",
"./standalone/fetch": "./standalone/fetch.ts",
"./standalone/ServiceWorkerContext": "./standalone/ServiceWorkerContext.ts",
Comment on lines +127 to +129
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -a -t f . tegg/core/types/standalone tegg/core/types/src/standalone 2>/dev/null
fd -a 'tsdown.config*' tegg/core/types
cat tegg/core/types/tsconfig.json 2>/dev/null

Repository: eggjs/egg

Length of output: 274


🏁 Script executed:

cat tegg/core/types/package.json

Repository: eggjs/egg

Length of output: 15242


🏁 Script executed:

#!/bin/bash
# Look for tsdown.config in parent directories
find tegg -name 'tsdown.config*' -type f
# Also check if there's a build script in package.json
fd -a 'tsdown.config*' . 2>/dev/null | head -20

Repository: eggjs/egg

Length of output: 2267


🏁 Script executed:

#!/bin/bash
# Check the structure and understand the pattern
ls -la tegg/core/types/
ls -la tegg/core/types/dist/ 2>/dev/null || echo "No dist directory yet"

Repository: eggjs/egg

Length of output: 617


🏁 Script executed:

#!/bin/bash
# Check what's in the standalone directory
ls -la tegg/core/types/standalone/
head -20 tegg/core/types/standalone/index.ts

Repository: eggjs/egg

Length of output: 419


🏁 Script executed:

#!/bin/bash
# Compare with another tegg/core package to see the pattern
cat tegg/core/metadata/tsdown.config.ts 2>/dev/null | head -20

Repository: eggjs/egg

Length of output: 169


🏁 Script executed:

#!/bin/bash
# Check if there's a root tsdown or build script handling all packages
cat pnpm-workspace.yaml 2>/dev/null | grep -A 10 "tegg/core"
ls -la tegg/ | grep -i build
cat tegg/package.json 2>/dev/null | jq '.scripts' 2>/dev/null || echo "No tegg/package.json"

Repository: eggjs/egg

Length of output: 275


🏁 Script executed:

#!/bin/bash
# Check root tsdown or build configuration
cat package.json | jq '.scripts' 2>/dev/null | head -30
# Check if tegg/core/types is mentioned anywhere special
rg "tegg/core/types" --type yaml --type json pnpm-workspace.yaml package.json

Repository: eggjs/egg

Length of output: 1629


🏁 Script executed:

#!/bin/bash
# Look for any build or documentation about how types package is built
rg "tsdown.config" tegg/core/types
rg "types package" tegg/CLAUDE.md 2>/dev/null | head -5
rg "type-only\|types-only" tegg/ 2>/dev/null | head -5

Repository: eggjs/egg

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Check the git history or if this is a new file
git log --oneline -n 20 -- tegg/core/types/package.json 2>/dev/null || echo "No git history available"
git status tegg/core/types/ 2>/dev/null | head -20

Repository: eggjs/egg

Length of output: 153


Add missing tsdown.config.ts and reconsider the ./standalone/* convention.

The ./standalone/* entries break from the ./src/* convention used throughout the package. Additionally, tegg/core/types is the only tegg/core package without a tsdown.config.ts file. While other tegg/core packages configure tsdown.config.ts with entry: { index: 'src/index.ts' }, this package has none.

The published exports declare ./dist/standalone/index.js, but without a tsdown config, the build won't generate the dist/standalone/ directory. Either add tsdown.config.ts to configure the standalone directory build, or move the files to src/standalone/ to follow the established pattern used by all other tegg/core packages.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/types/package.json` around lines 127 - 129, This package declares
exports like "./standalone" and references files ./standalone/index.ts,
./standalone/fetch.ts, and ./standalone/ServiceWorkerContext.ts but lacks a
tsdown.config.ts and therefore the dist/standalone/ artifacts won't be built;
either add a tsdown.config.ts that adds entry mappings for the standalone
outputs (pointing each standalone path to its source .ts file) so tsdown will
emit dist/standalone/*, or move the standalone sources into src/standalone/ and
update package.json exports to follow the ./src/* convention used across other
tegg/core packages.

"./transaction": "./src/transaction.ts",
"./package.json": "./package.json"
},
Expand Down Expand Up @@ -227,6 +230,9 @@
"./runtime/model/EggObject": "./dist/runtime/model/EggObject.js",
"./runtime/model/LoadUnitInstance": "./dist/runtime/model/LoadUnitInstance.js",
"./schedule": "./dist/schedule.js",
"./standalone": "./dist/standalone/index.js",
"./standalone/fetch": "./dist/standalone/fetch.js",
"./standalone/ServiceWorkerContext": "./dist/standalone/ServiceWorkerContext.js",
"./transaction": "./dist/transaction.js",
"./package.json": "./package.json"
}
Expand Down
16 changes: 16 additions & 0 deletions tegg/core/types/standalone/ServiceWorkerContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FetchEvent } from './fetch.ts';

Check failure on line 1 in tegg/core/types/standalone/ServiceWorkerContext.ts

View workflow job for this annotation

GitHub Actions / typecheck

typescript(TS1484)

'FetchEvent' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.

export interface ServiceWorkerContextInit<T> {
event: T;
}

export interface ServiceWorkerContext<Event, Response> {
event: Event;
get response(): Response | undefined;
set response(response: Response);

get body(): any | undefined;
set body(body: any);
}

export type ServiceWorkerFetchContext = ServiceWorkerContext<FetchEvent, Response>;
Comment on lines +1 to +16
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Type-only import + generic param names shadow DOM globals.

  1. FetchEvent should be a type-only import (TS1484).
  2. The generic parameters Event and Response shadow the DOM globals with the same names, which makes ServiceWorkerFetchContext = ServiceWorkerContext<FetchEvent, Response> ambiguous when reading the file and leaks into editor tooling. Prefer distinct names (e.g. TEvent, TResponse).
♻️ Proposed fix
-import { FetchEvent } from './fetch.ts';
+import type { FetchEvent } from './fetch.ts';

-export interface ServiceWorkerContext<Event, Response> {
-  event: Event;
-  get response(): Response | undefined;
-  set response(response: Response);
-
-  get body(): any | undefined;
-  set body(body: any);
-}
-
-export type ServiceWorkerFetchContext = ServiceWorkerContext<FetchEvent, Response>;
+export interface ServiceWorkerContext<TEvent, TResponse> {
+  event: TEvent;
+  get response(): TResponse | undefined;
+  set response(response: TResponse);
+
+  get body(): unknown | undefined;
+  set body(body: unknown);
+}
+
+export type ServiceWorkerFetchContext = ServiceWorkerContext<FetchEvent, Response>;

Also note the any on body — coding guidelines call for unknown when the type is truly unknown.

🧰 Tools
🪛 GitHub Check: typecheck

[failure] 1-1: typescript(TS1484)
'FetchEvent' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/core/types/standalone/ServiceWorkerContext.ts` around lines 1 - 16,
Change the import of FetchEvent to a type-only import and rename the generic
parameters on ServiceWorkerContext and ServiceWorkerContextInit from
Event/Response to non-shadowing names (e.g. TEvent, TResponse) so
ServiceWorkerFetchContext = ServiceWorkerContext<FetchEvent, Response> is
unambiguous; update the ServiceWorkerContext signature (get/set response) to use
TResponse and TEvent accordingly and replace the body property type from any to
unknown to follow guidelines. Ensure FetchEvent is imported with the "type"
modifier and all references to Event/Response in ServiceWorkerContext,
ServiceWorkerContextInit, and ServiceWorkerFetchContext are updated to the new
identifiers.

5 changes: 5 additions & 0 deletions tegg/core/types/standalone/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface FetchEvent extends Event {
request: Request;
waitUntil(f: Promise<any>): void;
respondWith(r: Response | PromiseLike<Response>): void;
}
2 changes: 2 additions & 0 deletions tegg/core/types/standalone/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './fetch.ts';
export * from './ServiceWorkerContext.ts';
74 changes: 74 additions & 0 deletions tegg/standalone/service-worker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"name": "@eggjs/tegg-service-worker",
"version": "4.0.0-beta.29",
"private": true,
"description": "tegg service worker",
"keywords": [
"egg",
"typescript",
"tegg",
"standalone",
"service worker"
],
"homepage": "https://github.com/eggjs/egg/tree/next/tegg/standalone/service-worker",
"bugs": {
"url": "https://github.com/eggjs/egg/issues"
},
"license": "MIT",
"author": "killagu <killa123@126.com>",
"repository": {
"type": "git",
"url": "git+https://github.com/eggjs/egg.git",
"directory": "tegg/standalone/service-worker"
},
"files": [
"dist"
],
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": "./src/index.ts",
"./package.json": "./package.json"
},
"publishConfig": {
"exports": {
".": "./dist/index.js",
"./package.json": "./package.json"
}
},
"scripts": {
"typecheck": "tsgo --noEmit"
},
"dependencies": {
"@eggjs/router": "workspace:*",
"@eggjs/ajv-plugin": "workspace:*",
"@eggjs/tegg-aop-runtime": "workspace:*",
"@eggjs/tegg-dal-plugin": "workspace:*",
"@eggjs/tegg-dynamic-inject-runtime": "workspace:*",
"@eggjs/tegg-lifecycle": "workspace:*",
"@eggjs/tegg-metadata": "workspace:*",
"@eggjs/tegg-standalone": "workspace:*",
"@eggjs/tegg-types": "workspace:*",
"@modelcontextprotocol/sdk": "1.24.3",
"egg-errors": "catalog:",
"path-to-regexp": "catalog:path-to-regexp1",
"type-is": "catalog:",
"urllib": "catalog:"
},
"peerDependencies": {
"@eggjs/tegg": "workspace:*"
},
"devDependencies": {
"@eggjs/module-test-util": "workspace:*",
"@eggjs/tegg": "workspace:*",
"@types/node": "catalog:",
"@types/type-is": "catalog:",
"typescript": "catalog:",
"undici": "catalog:"
},
"engines": {
"node": ">=22.18.0"
}
}
116 changes: 116 additions & 0 deletions tegg/standalone/service-worker/src/ServiceWorkerApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import path from 'node:path';
import {
EggPrototypeLifecycleUtil,
LoadUnitLifecycleUtil,
} from '@eggjs/tegg-metadata';
import { Runner, RunnerOptions, StandaloneContext } from '@eggjs/tegg-standalone';
import type { Logger } from '@eggjs/tegg-types';
import { getDefaultHttpClient } from 'urllib';
import { ContextProtoProperty } from './constants.ts';
import { FetchRouter } from './http/FetchRouter.ts';
import { RootProtoManager } from './controller/RootProtoManager.ts';
import { ControllerMetadataManager } from './controller/ControllerMetadataManager.ts';
import { ControllerRegisterFactory } from './controller/ControllerRegisterFactory.ts';
import { ContextProtoLoadUnitHook } from './hook/ContextProtoLoadUnitHook.ts';
import { ControllerPrototypeHook } from './hook/ControllerPrototypeHook.ts';
import { ControllerLoadUnitHook } from './hook/ControllerLoadUnitHook.ts';
import { HTTPControllerRegister } from './http/HTTPControllerRegister.ts';
import { MCPControllerRegister } from './mcp/MCPControllerRegister.ts';
import { LoadUnitInnerClassHook } from './hook/LoadUnitInnerClassHook.ts';
import { ServiceWorkerRunner } from './ServiceWorkerRunner.ts';
import { StandaloneEggObjectFactory } from './StandaloneEggObjectFactory.ts';
import { FetchEventHandler } from './http/FetchEventHandler.ts';

export interface ServiceWorkerAppOptions {
innerObjectHandlers?: RunnerOptions['innerObjectHandlers'];
logger?: Logger;
}

export class ServiceWorkerApp {
private readonly runner: Runner;
private readonly contextProtoLoadUnitHook: ContextProtoLoadUnitHook;
private readonly controllerPrototypeHook: ControllerPrototypeHook;
private readonly controllerLoadUnitHook: ControllerLoadUnitHook;
private readonly fetchRouter: FetchRouter;
private readonly rootProtoManager: RootProtoManager;
private readonly controllerMetadataManager: ControllerMetadataManager;
private readonly controllerRegisterFactory: ControllerRegisterFactory;
private readonly loadUnitInnerClassHook: LoadUnitInnerClassHook;

constructor(cwd: string, options?: ServiceWorkerAppOptions & RunnerOptions) {
// Create shared objects
this.fetchRouter = new FetchRouter();
this.rootProtoManager = new RootProtoManager();
this.controllerMetadataManager = new ControllerMetadataManager();
this.controllerRegisterFactory = new ControllerRegisterFactory();

// Create lifecycle hooks
this.contextProtoLoadUnitHook = new ContextProtoLoadUnitHook('serviceWorker');
this.controllerPrototypeHook = new ControllerPrototypeHook();
this.controllerLoadUnitHook = new ControllerLoadUnitHook(
this.controllerRegisterFactory,
this.rootProtoManager,
this.controllerMetadataManager,
this.fetchRouter,
);

// Register lifecycle hooks
LoadUnitLifecycleUtil.registerLifecycle(this.contextProtoLoadUnitHook);
LoadUnitLifecycleUtil.registerLifecycle(this.controllerLoadUnitHook);
EggPrototypeLifecycleUtil.registerLifecycle(this.controllerPrototypeHook);

// Build dependencies list - include this package as a framework dependency
const frameworkDep = { baseDir: path.join(__dirname, '..'), extraFilePattern: [ '!**/test' ] };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether the package is configured as ESM and whether __dirname is polyfilled anywhere
fd -H package.json tegg/standalone/service-worker --exec cat {}
echo '---'
fd -H tsconfig.json tegg/standalone/service-worker --exec cat {}
echo '---'
rg -nP '__dirname|fileURLToPath' tegg/standalone/service-worker

Repository: eggjs/egg

Length of output: 2755


🏁 Script executed:

#!/bin/bash
# Find all imports of ServiceWorkerApp and related usage
rg -nP 'ServiceWorkerApp|from.*ServiceWorkerApp' tegg/standalone/service-worker
echo '---'
# Check the full ServiceWorkerApp.ts file structure
cat -n tegg/standalone/service-worker/src/ServiceWorkerApp.ts | head -80

Repository: eggjs/egg

Length of output: 6684


Use fileURLToPath(import.meta.url) instead of __dirname to support native ESM.

In native ESM, __dirname is undefined and will cause a ReferenceError when the ServiceWorkerApp constructor runs. The coding guidelines mandate ESM-only for tegg/**, and this package is configured as "type": "module". Fix by importing fileURLToPath from node:url and computing __dirname at the module level:

import path from 'node:path';
+import { fileURLToPath } from 'node:url';
import {
  EggPrototypeLifecycleUtil,
  LoadUnitLifecycleUtil,
} from '@eggjs/tegg-metadata';
import { Runner, RunnerOptions, StandaloneContext } from '@eggjs/tegg-standalone';
import type { Logger } from '@eggjs/tegg-types';
import { getDefaultHttpClient } from 'urllib';
import { ContextProtoProperty } from './constants.ts';
import { FetchRouter } from './http/FetchRouter.ts';
import { RootProtoManager } from './controller/RootProtoManager.ts';
import { ControllerMetadataManager } from './controller/ControllerMetadataManager.ts';
import { ControllerRegisterFactory } from './controller/ControllerRegisterFactory.ts';
import { ContextProtoLoadUnitHook } from './hook/ContextProtoLoadUnitHook.ts';
import { ControllerPrototypeHook } from './hook/ControllerPrototypeHook.ts';
import { ControllerLoadUnitHook } from './hook/ControllerLoadUnitHook.ts';
import { HTTPControllerRegister } from './http/HTTPControllerRegister.ts';
import { MCPControllerRegister } from './mcp/MCPControllerRegister.ts';

+const __dirname = path.dirname(fileURLToPath(import.meta.url));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const frameworkDep = { baseDir: path.join(__dirname, '..'), extraFilePattern: [ '!**/test' ] };
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import {
EggPrototypeLifecycleUtil,
LoadUnitLifecycleUtil,
} from '@eggjs/tegg-metadata';
import { Runner, RunnerOptions, StandaloneContext } from '@eggjs/tegg-standalone';
import type { Logger } from '@eggjs/tegg-types';
import { getDefaultHttpClient } from 'urllib';
import { ContextProtoProperty } from './constants.ts';
import { FetchRouter } from './http/FetchRouter.ts';
import { RootProtoManager } from './controller/RootProtoManager.ts';
import { ControllerMetadataManager } from './controller/ControllerMetadataManager.ts';
import { ControllerRegisterFactory } from './controller/ControllerRegisterFactory.ts';
import { ContextProtoLoadUnitHook } from './hook/ContextProtoLoadUnitHook.ts';
import { ControllerPrototypeHook } from './hook/ControllerPrototypeHook.ts';
import { ControllerLoadUnitHook } from './hook/ControllerLoadUnitHook.ts';
import { HTTPControllerRegister } from './http/HTTPControllerRegister.ts';
import { MCPControllerRegister } from './mcp/MCPControllerRegister.ts';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const frameworkDep = { baseDir: path.join(__dirname, '..'), extraFilePattern: [ '!**/test' ] };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/standalone/service-worker/src/ServiceWorkerApp.ts` at line 58, The code
uses __dirname when constructing frameworkDep in ServiceWorkerApp which breaks
in native ESM; import fileURLToPath from 'node:url' and compute a module-level
dirname via const __dirname = path.dirname(fileURLToPath(import.meta.url)), then
update the frameworkDep assignment (the variable named frameworkDep in
ServiceWorkerApp) to use that computed __dirname (path.join(__dirname, '..')) so
the constructor works under ESM.

const deps = [ ...(options?.dependencies || []), frameworkDep ];

// Register FetchRouter and RootProtoManager as inner objects so they can be @Inject()-ed
const innerObjectHandlers: RunnerOptions['innerObjectHandlers'] = {
...options?.innerObjectHandlers,
fetchRouter: [{ obj: this.fetchRouter }],
rootProtoManager: [{ obj: this.rootProtoManager }],
};

// Provide default logger (fallback to console) and httpclient (urllib singleton)
if (!innerObjectHandlers.logger) {
innerObjectHandlers.logger = [{ obj: options?.logger || console }];
}
if (!innerObjectHandlers.httpclient) {
innerObjectHandlers.httpclient = [{ obj: getDefaultHttpClient() }];
}

this.loadUnitInnerClassHook = new LoadUnitInnerClassHook([ StandaloneEggObjectFactory, ServiceWorkerRunner, FetchEventHandler ]);

LoadUnitLifecycleUtil.registerLifecycle(this.loadUnitInnerClassHook);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

this.runner = new Runner(cwd, {
...options,
dependencies: deps,
innerObjectHandlers,
});
}

async init() {
await this.runner.init();
}

async handleEvent<T = unknown>(event: Event) {
const context = new StandaloneContext();
context.set(ContextProtoProperty.Event.contextKey, event);

return await this.runner.run<T>(context);
}

async destroy() {
Comment on lines +92 to +103
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add public return types and narrow the event parameter.

init, handleEvent, and destroy are public methods on an exported class, but they rely on inferred return types. Also, handleEvent(event: Event) is broader than the FetchEventLike shape consumed by ServiceWorkerRunner and FetchEventHandler.

🔧 Proposed typing fix
 import { FetchEventHandler } from './http/FetchEventHandler.ts';
+import type { FetchEventLike } from '@eggjs/tegg/standalone';
@@
-  async init() {
+  async init(): Promise<void> {
     await this.runner.init();
   }
 
-  async handleEvent<T = unknown>(event: Event) {
+  async handleEvent<T = unknown>(event: FetchEventLike): Promise<T> {
     const context = new StandaloneContext();
     context.set(ContextProtoProperty.Event.contextKey, event);
 
     return await this.runner.run<T>(context);
   }
 
-  async destroy() {
+  async destroy(): Promise<void> {

As per coding guidelines, all exported functions, methods, and getters must have explicit return type annotations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async init() {
await this.runner.init();
}
async handleEvent<T = unknown>(event: Event) {
const context = new StandaloneContext();
context.set(ContextProtoProperty.Event.contextKey, event);
return await this.runner.run<T>(context);
}
async destroy() {
async init(): Promise<void> {
await this.runner.init();
}
async handleEvent<T = unknown>(event: FetchEventLike): Promise<T> {
const context = new StandaloneContext();
context.set(ContextProtoProperty.Event.contextKey, event);
return await this.runner.run<T>(context);
}
async destroy(): Promise<void> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tegg/standalone/service-worker/src/ServiceWorkerApp.ts` around lines 92 -
103, The public methods on ServiceWorkerApp need explicit return types and the
handleEvent parameter should be narrowed to the FetchEventLike shape used by
ServiceWorkerRunner/FetchEventHandler: update ServiceWorkerApp.init to declare
an explicit Promise<void> return type, change
ServiceWorkerApp.handleEvent(event: Event) to accept event: FetchEventLike and
declare its return type as Promise<T | undefined> (or another appropriate
generic Promise<T>), and add an explicit Promise<void> return type to
ServiceWorkerApp.destroy; keep the existing logic that creates StandaloneContext
and sets ContextProtoProperty.Event.contextKey before calling
this.runner.run<T>(context).

// Clean up static singletons
HTTPControllerRegister.clean();
MCPControllerRegister.clean();

// Unregister lifecycle hooks
LoadUnitLifecycleUtil.deleteLifecycle(this.contextProtoLoadUnitHook);
LoadUnitLifecycleUtil.deleteLifecycle(this.controllerLoadUnitHook);
LoadUnitLifecycleUtil.deleteLifecycle(this.loadUnitInnerClassHook);
EggPrototypeLifecycleUtil.deleteLifecycle(this.controllerPrototypeHook);

await this.runner.destroy();
}
}
Loading
Loading