-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
pick: tegg service worker #5875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,27 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { type EggProtoImplClass, ImplDecorator, SingletonProtoParams } from '@eggjs/tegg-types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
🔧 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface FetchEventLike { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request: Request; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| respondWith(response: Response | Promise<Response>): void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| waitUntil?(promise: Promise<unknown>): void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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'; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 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
Required changesUpdate line 4 in -export * from './event/EventHandler.ts';
+export * from './event/EventHandler.js';Update /**
* 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
Suggested change
🤖 Prompt for AI Agents |
||||||
| 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
|
||||||||||||||||||||||
| import { pipeline } from 'node:stream'; | ||||||||||||||||||||||
| import { Headers, BodyInit, Request, Response } from 'undici'; | ||||||||||||||||||||||
| import { FetchEvent } from '@eggjs/tegg-types/standalone'; | ||||||||||||||||||||||
|
Comment on lines
+1
to
+4
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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
Suggested change
🧰 Tools🪛 GitHub Check: typecheck[failure] 4-4: typescript(TS1484) [failure] 3-3: typescript(TS1484) [failure] 1-1: typescript(TS1484) [failure] 1-1: typescript(TS1484) 🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add explicit return types for public static methods.
♻️ 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 |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Client-disconnect / listener error paths swallow errors and may leave response hanging. A couple of robustness concerns in the per-request listener:
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| 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)); | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 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/nullRepository: eggjs/egg Length of output: 274 🏁 Script executed: cat tegg/core/types/package.jsonRepository: 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 -20Repository: 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.tsRepository: 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 -20Repository: 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.jsonRepository: 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 -5Repository: 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 -20Repository: eggjs/egg Length of output: 153 Add missing The The published exports declare 🤖 Prompt for AI Agents |
||
| "./transaction": "./src/transaction.ts", | ||
| "./package.json": "./package.json" | ||
| }, | ||
|
|
@@ -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" | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { FetchEvent } from './fetch.ts'; | ||
|
|
||
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Type-only import + generic param names shadow DOM globals.
♻️ 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 🧰 Tools🪛 GitHub Check: typecheck[failure] 1-1: typescript(TS1484) 🤖 Prompt for AI Agents |
||
| 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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export * from './fetch.ts'; | ||
| export * from './ServiceWorkerContext.ts'; |
| 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" | ||
| } | ||
| } |
| 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' ] }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 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-workerRepository: 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 -80Repository: eggjs/egg Length of output: 6684 Use In native ESM, 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
| 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); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Add public return types and narrow the event parameter.
🔧 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
| // 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(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: eggjs/egg
Length of output: 271
🏁 Script executed:
Repository: eggjs/egg
Length of output: 35
🏁 Script executed:
Repository: eggjs/egg
Length of output: 1244
🏁 Script executed:
Repository: eggjs/egg
Length of output: 654
🏁 Script executed:
Repository: eggjs/egg
Length of output: 579
🏁 Script executed:
Repository: eggjs/egg
Length of output: 92
🏁 Script executed:
Repository: eggjs/egg
Length of output: 119
🏁 Script executed:
Repository: eggjs/egg
Length of output: 591
🏁 Script executed:
Repository: eggjs/egg
Length of output: 776
🏁 Script executed:
Repository: eggjs/egg
Length of output: 1098
🏁 Script executed:
Repository: eggjs/egg
Length of output: 35
🏁 Script executed:
Repository: eggjs/egg
Length of output: 219
🏁 Script executed:
Repository: eggjs/egg
Length of output: 143
🏁 Script executed:
Repository: eggjs/egg
Length of output: 3523
🏁 Script executed:
Repository: eggjs/egg
Length of output: 841
Fix TS1484 by using type-only imports at Line 1.
ImplDecoratorandSingletonProtoParamsare types exported from@eggjs/tegg-types. WithverbatimModuleSyntax: truein root tsconfig.json, type-only imports require thetypekeyword.🔧 Proposed fix
📝 Committable suggestion
🧰 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