@webtypen/webframez-core 0.3.33 → 0.3.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +59 -0
  2. package/agents/webframez_rules.md +236 -0
  3. package/dist/Router/Request.d.ts +2 -0
  4. package/dist/Router/Request.js +2 -0
  5. package/dist/Router/Route.d.ts +2 -0
  6. package/dist/Router/Route.js +40 -11
  7. package/dist/Router/Router.d.ts +17 -25
  8. package/dist/Router/Router.js +148 -15
  9. package/dist/info.js +1 -1
  10. package/package.json +6 -1
  11. package/.github/workflows/npm-publish.yml +0 -37
  12. package/.prettierrc +0 -1
  13. package/dev/.env.example +0 -1
  14. package/dev/MongoDBDriver.ts +0 -173
  15. package/dev/README.md +0 -6
  16. package/dev/app.ts +0 -84
  17. package/dev/commands/TestCommand.ts +0 -13
  18. package/dev/config/database.ts +0 -17
  19. package/dev/config/queue.ts +0 -29
  20. package/dev/console.ts +0 -37
  21. package/dev/jobs/TestJob.ts +0 -11
  22. package/dev/modules/index.ts +0 -3
  23. package/dev/modules/test-module/Controller/TestModuleController.ts +0 -8
  24. package/dev/modules/test-module/TestModuleProvider.ts +0 -30
  25. package/dev/storage/queue/log_worker_1.log +0 -198
  26. package/dev/storage/queue/log_worker_2.log +0 -88
  27. package/dev/storage/queue/log_worker_3.log +0 -88
  28. package/dev/storage/queue/worker_worker_1.json +0 -1
  29. package/dev/storage/queue/worker_worker_2.json +0 -1
  30. package/dev/storage/queue/worker_worker_3.json +0 -1
  31. package/dev/storage/test-storage-check/a.txt +0 -1
  32. package/src/BaseKernelConsole.ts +0 -3
  33. package/src/BaseKernelWeb.ts +0 -6
  34. package/src/Commands/BuildFinishCommand.ts +0 -38
  35. package/src/Commands/ConsoleCommand.ts +0 -128
  36. package/src/Commands/ConsoleOutputHelper.ts +0 -233
  37. package/src/Commands/ConsoleProgressBar.ts +0 -47
  38. package/src/Commands/QueueLogCommand.ts +0 -93
  39. package/src/Commands/QueueStartCommand.ts +0 -121
  40. package/src/Commands/QueueStatusCommand.ts +0 -82
  41. package/src/Commands/QueueStopCommand.ts +0 -105
  42. package/src/Commands/QueueWorkerAutorestartCommand.ts +0 -97
  43. package/src/Commands/QueueWorkerCommand.ts +0 -684
  44. package/src/Config.ts +0 -37
  45. package/src/ConsoleApplication.ts +0 -232
  46. package/src/Controller/Controller.ts +0 -1
  47. package/src/DataBuilder/DataBuilder.ts +0 -792
  48. package/src/DataBuilder/DataBuilderController.ts +0 -36
  49. package/src/Database/BaseDBDriver.ts +0 -22
  50. package/src/Database/DBConnection.ts +0 -128
  51. package/src/Database/DBDrivers.ts +0 -13
  52. package/src/Database/Model.ts +0 -355
  53. package/src/Database/QueryBuilder.ts +0 -120
  54. package/src/Datatable/Datatable.ts +0 -646
  55. package/src/Datatable/DatatableController.ts +0 -132
  56. package/src/Datatable/DatatableRegistry.ts +0 -22
  57. package/src/ErrorHandling/ErrorHandler.ts +0 -109
  58. package/src/Facades/Storage.ts +0 -217
  59. package/src/Facades/StorageDrivers/BaseStorageDriver.ts +0 -31
  60. package/src/Facades/StorageDrivers/LocalStorageDriver.ts +0 -225
  61. package/src/Functions/DateFunctions.ts +0 -96
  62. package/src/Functions/FileFunctions.ts +0 -49
  63. package/src/Functions/NumericFunctions.ts +0 -57
  64. package/src/Functions/PaginationFunctions.ts +0 -58
  65. package/src/Functions/StringFunctions.ts +0 -49
  66. package/src/LambdaApplication.ts +0 -44
  67. package/src/Modules/ModuleProvider.ts +0 -15
  68. package/src/Modules/ModulesLoader.ts +0 -34
  69. package/src/Queue/BaseQueueJob.ts +0 -90
  70. package/src/Queue/QueueJob.ts +0 -5
  71. package/src/Queue/QueueJobsRegisty.ts +0 -61
  72. package/src/Router/Request.ts +0 -28
  73. package/src/Router/Response.ts +0 -259
  74. package/src/Router/Route.ts +0 -129
  75. package/src/Router/Router.ts +0 -614
  76. package/src/WebApplication.ts +0 -87
  77. package/src/index.ts +0 -35
  78. package/src/info.ts +0 -3
  79. package/tsconfig.json +0 -18
package/README.md CHANGED
@@ -20,6 +20,45 @@ This README reflects the current API in this repository and focuses on:
20
20
  npm i @webtypen/webframez-core
21
21
  ```
22
22
 
23
+ ## Agent-Regeln fuer Codex und Copilot
24
+
25
+ Das Paket enthaelt unter agents/webframez_rules.md empfohlene Arbeitsregeln fuer AI-Coding-Agents in Webframez-Projekten.
26
+
27
+ Nach der Installation liegt die Datei im Paket unter:
28
+
29
+ ```text
30
+ node_modules/@webtypen/webframez-core/agents/webframez_rules.md
31
+ ```
32
+
33
+ Die Regeln beschreiben unter anderem:
34
+ - bevorzugte Nutzung von Model.objectId(...) statt eigener ObjectId-Resolver
35
+ - bevorzugte Nutzung der vorhandenen Helper wie StringFunctions, NumericFunctions und DateFunctions
36
+ - Verwendung der Webframez-Abstraktionen fuer Request, Response, Middleware, Storage, Datatables und Routes
37
+
38
+ Wichtig: AGENTS.md-Dateien haben keine universell standardisierte Import-Funktion. Die praktikable Variante ist deshalb, die Regeldatei aus dem Paket in der AGENTS.md des eigenen Projekts explizit zu referenzieren und projektspezifische Regeln lokal zu ergaenzen.
39
+
40
+ Beispiel fuer eine eigene AGENTS.md im Consumer-Projekt:
41
+
42
+ ```md
43
+ # AGENTS.md
44
+
45
+ Dieses Projekt verwendet @webtypen/webframez-core.
46
+
47
+ Uebernimm fuer alle Webframez-bezogenen Implementierungen die Konventionen aus:
48
+ ./node_modules/@webtypen/webframez-core/agents/webframez_rules.md
49
+
50
+ Insbesondere gilt:
51
+ - fuer ObjectId-Konvertierungen Model.objectId(...) oder die passende Model-Instanzmethode verwenden
52
+ - vorhandene Webframez-Helper und Facades bevorzugen statt neue Utilities oder Resolver anzulegen
53
+ - fuer HTTP-, Routing-, Middleware-, Storage- und Datatable-Code die Webframez-APIs und Konventionen beibehalten
54
+
55
+ Projektspezifische Ergaenzung:
56
+ - dieses Projekt verwendet fuer Admin-Routen zusaetzlich die Middleware "admin-auth"
57
+ - Antworten im Backoffice sollen das Format { status, message, data } einhalten
58
+ ```
59
+
60
+ Wenn eine Regel aus der lokalen Projekt-AGENTS.md einer Regel aus der Paketdatei widerspricht, sollte die lokale Projektregel Vorrang haben.
61
+
23
62
  ## Basic Web Setup
24
63
 
25
64
  ```ts
@@ -117,6 +156,25 @@ Attach middleware by key via route options:
117
156
  Route.get("/me", "AccountController@me", { middleware: ["auth"] });
118
157
  ```
119
158
 
159
+ ### Route Domain Filter
160
+
161
+ You can restrict routes (or groups) to specific domains:
162
+
163
+ ```ts
164
+ Route.group({ domains: ["websites.simplebis.com", "*.local.dev"] }, () => {
165
+ Route.get("/", "HomeController@index");
166
+ });
167
+
168
+ Route.get("/api/health", "HealthController@index", {
169
+ domains: ["api.example.com"]
170
+ });
171
+ ```
172
+
173
+ Domain matching also works behind reverse proxies (`x-forwarded-host` is respected).
174
+ If a wildcard domain matches, the extracted wildcard value is available in
175
+ `req.routeDomainWildcard`. The matched request hostname is available in
176
+ `req.routeDomainMatch`.
177
+
120
178
  Middleware signature:
121
179
 
122
180
  ```ts
@@ -155,6 +213,7 @@ Route.extend("jsonGet", (route) => {
155
213
  - `body`, `bodyPlain`
156
214
  - `query`, `queryRaw`
157
215
  - `params`
216
+ - `routeDomainMatch`, `routeDomainWildcard`
158
217
  - `files`
159
218
  - `message` (native `IncomingMessage`)
160
219
 
@@ -0,0 +1,236 @@
1
+ # AGENTS.md
2
+
3
+ Diese Datei definiert die Arbeitsregeln fuer Codex in Projekten, die @webtypen/webframez-core verwenden.
4
+
5
+ ## Ziel
6
+
7
+ Codex soll in Webframez-Projekten bevorzugt bestehende Framework-Abstraktionen nutzen statt neue, redundante Hilfsstrukturen zu erzeugen. Wenn das Framework bereits eine Funktion, Facade, Basisklasse oder einen klaren Konventionspfad bereitstellt, ist dieser zu verwenden.
8
+
9
+ ## Grundsatzregeln
10
+
11
+ 1. Immer zuerst pruefen, ob @webtypen/webframez-core die benoetigte Funktion bereits exportiert.
12
+ 2. Keine projektlokalen Wrapper, Resolver, Normalizer oder Utility-Dateien erzeugen, wenn das Framework die Aufgabe schon abdeckt.
13
+ 3. Keine internen Framework-Pfade importieren. In Consumer-Projekten immer aus @webtypen/webframez-core importieren.
14
+ 4. Bestehende Webframez-Konventionen haben Vorrang vor generischen Node.js-, Express- oder Eigenbau-Mustern.
15
+ 5. Neue Abstraktionen nur dann erzeugen, wenn die Framework-API die Anforderung nachweislich nicht abbildet.
16
+ 6. Controller-, Route-, Middleware-, Datatable- und Storage-Loesungen sollen idiomatisch fuer Webframez sein und nicht wie portierter Express-Code aussehen.
17
+
18
+ ## Imports
19
+
20
+ Bevorzuge immer dieses Muster:
21
+
22
+ ```ts
23
+ import {
24
+ BaseKernelWeb,
25
+ Controller,
26
+ Request,
27
+ Response,
28
+ Route,
29
+ Model,
30
+ Storage,
31
+ Datatable,
32
+ DatatableController,
33
+ NumericFunctions,
34
+ StringFunctions,
35
+ DateFunctions,
36
+ } from "@webtypen/webframez-core";
37
+ ```
38
+
39
+ Vermeide Importe aus internen Pfaden wie src/..., dist/... oder einzelnen Deep-Imports aus dem Paket, sofern nicht ausdruecklich anders vorgegeben.
40
+
41
+ ## Models und Datenbank
42
+
43
+ 1. Fuer ObjectId-Konvertierungen immer Model.objectId(...) oder die Instanzmethode objectId(...) verwenden, wenn man sich im Kontext eines Models befindet.
44
+ 2. Keine redundanten resolveObjectId, parseObjectId, normalizeObjectId, toObjectId oder aehnlichen Hilfsmethoden erzeugen, wenn objectId(...) ausreicht.
45
+ 3. Wenn kein konkretes Model passt, ist DBConnection.objectId(...) die zweite Wahl. Ein projektspezifischer Resolver ist nicht die erste Wahl.
46
+ 4. Fuer Standardabfragen bevorzugt die vorhandenen Model-Methoden verwenden: where(...), orderBy(...), first(), get(), paginate(), aggregate().
47
+ 5. Beziehungen ueber hasOne(...), hasMany(...) und hasManyArray(...) abbilden statt manuelle Lade- oder Resolve-Methoden pro Beziehung zu schreiben.
48
+ 6. Model-Klassen sollen die Webframez-Konventionen fuer __table, __primaryKey und Mapping respektieren.
49
+
50
+ Bevorzugt:
51
+
52
+ ```ts
53
+ const userId = await User.objectId(req.params.id);
54
+ const user = await User.where("_id", "=", userId).first();
55
+ ```
56
+
57
+ Nicht bevorzugt:
58
+
59
+ ```ts
60
+ const userId = resolveObjectId(req.params.id);
61
+ const user = await userRepository.findById(userId);
62
+ ```
63
+
64
+ ## Helper und Functions
65
+
66
+ 1. Vor dem Schreiben eigener Utilities immer die vorhandenen Functions pruefen.
67
+ 2. Fuer Zahlenformatierung NumericFunctions verwenden, z. B. numberFormat(...) oder bytesFormat(...).
68
+ 3. Fuer Strings StringFunctions verwenden, z. B. slug(...), random(...), nl2br(...).
69
+ 4. Fuer Datumslogik DateFunctions verwenden, z. B. formatDateRange(...).
70
+ 5. Weitere vorhandene Helper wie FileFunctions oder PaginationFunctions ebenfalls bevorzugen, bevor neue Projekt-Utilities angelegt werden.
71
+ 6. Keine neuen util.ts-, helpers.ts-, format.ts- oder string.ts-Dateien anlegen, wenn die Logik bereits in Webframez vorhanden ist.
72
+
73
+ Bevorzugt:
74
+
75
+ ```ts
76
+ const slug = StringFunctions.slug(title);
77
+ const filesize = NumericFunctions.bytesFormat(file.size);
78
+ ```
79
+
80
+ Nicht bevorzugt:
81
+
82
+ ```ts
83
+ const slug = title.toLowerCase().replace(/\s+/g, "-");
84
+ const filesize = formatBytes(file.size);
85
+ ```
86
+
87
+ ## Request und Response
88
+
89
+ 1. Controller- und Route-Handler sollen mit Request und Response aus Webframez arbeiten.
90
+ 2. Uebliche Signatur ist async method(req: Request, res: Response).
91
+ 3. Werte aus req.params, req.query, req.body, req.files, req.headers und req.routeDomainWildcard lesen statt parallele Request-Abstraktionen einzufuehren.
92
+ 4. Antworten ueber res.status(...), res.header(...), res.send(...), res.sendCsv(...), res.download(...) oder res.stream(...) aufbauen.
93
+ 5. Native Node-Objekte nur nutzen, wenn eine Low-Level-Anforderung besteht. Standardfaelle sollen ueber Request und Response abgewickelt werden.
94
+ 6. JSON-Antworten nicht manuell serialisieren, wenn res.send(...) verwendet werden kann.
95
+
96
+ Bevorzugt:
97
+
98
+ ```ts
99
+ export class UserController extends Controller {
100
+ async details(req: Request, res: Response) {
101
+ const user = await User.where("_id", "=", await User.objectId(req.params.id)).first();
102
+
103
+ if (!user) {
104
+ return res.status(404).send({ status: "error", message: "User not found" });
105
+ }
106
+
107
+ return res.send({ status: "success", data: user });
108
+ }
109
+ }
110
+ ```
111
+
112
+ Nicht bevorzugt:
113
+
114
+ ```ts
115
+ async show(req: any, res: any) {
116
+ res.setHeader("Content-Type", "application/json");
117
+ res.end(JSON.stringify(data));
118
+ }
119
+ ```
120
+
121
+ ## Middleware
122
+
123
+ 1. Middleware in der Kernel-Konfiguration registrieren, nicht als ad-hoc Inline-System rund um einzelne Controller neu erfinden.
124
+ 2. Middleware-Signatur in Webframez ist next, reject, req, res.
125
+ 3. Erfolgsfall ueber next(true) oder resolve-artiges Fortsetzen behandeln.
126
+ 4. Ablehnung ueber reject(reason) abbilden, statt eigene Middleware-Fehlerprotokolle oder Express-next(error)-Nachbauten einzubauen.
127
+ 5. Middleware per Route-Option middleware: ["auth"] oder ueber Route.group(...) anbinden.
128
+ 6. Middleware soll Request und Response direkt weiterverwenden und keine zweite Context-Struktur einfuehren.
129
+
130
+ Bevorzugt:
131
+
132
+ ```ts
133
+ static middleware = {
134
+ auth: async (next: Function, reject: Function, req: Request, res: Response) => {
135
+ if (!req.headers.authorization) {
136
+ return reject("Unauthorized");
137
+ }
138
+
139
+ next(true);
140
+ },
141
+ };
142
+ ```
143
+
144
+ ## Routes
145
+
146
+ 1. Routen ueber die Route-Facade registrieren, nicht direkt ueber interne Router-Implementierungen.
147
+ 2. Bevorzuge Route.get(...), Route.post(...), Route.put(...), Route.delete(...).
148
+ 3. Controller-Routen im Format ControllerName@method registrieren, wenn keine zwingenden Gruende fuer Inline-Handler sprechen.
149
+ 4. Gemeinsame Prefixe, Domains und Middleware ueber Route.group(...) kapseln statt zu duplizieren.
150
+ 5. Route-Optionen wie middleware und domains verwenden, statt separate Routing-Metadaten-Systeme einzubauen.
151
+ 6. Eigene Route-Helper nur ueber Route.extend(...) ergaenzen, nicht durch parallele Routing-Facades.
152
+
153
+ Bevorzugt:
154
+
155
+ ```ts
156
+ Route.group({ prefix: "/admin", middleware: ["auth"] }, () => {
157
+ Route.get("/users/:id", "AdminUserController@show");
158
+ });
159
+ ```
160
+
161
+ Nicht bevorzugt:
162
+
163
+ ```ts
164
+ Router.register("GET", "/admin/users/:id", handler, customMeta);
165
+ ```
166
+
167
+ ## Controller
168
+
169
+ 1. Business-Logik fuer HTTP-Endpunkte gehoert in Controller-Methoden oder klar abgegrenzte Domain-Services, nicht in routes.ts.
170
+ 2. Controller sollen von Controller erben, wenn im Projekt Webframez-Controller-Konventionen genutzt werden.
171
+ 3. Controller sollen Request/Response und Model-/Helper-Abstraktionen direkt verwenden.
172
+ 4. Keine Express-typischen Patterns wie req, res, next in Controller-Signaturen einfuehren, wenn kein echter Express-Adapter verwendet wird.
173
+
174
+ ## Storage
175
+
176
+ 1. Fuer Dateioperationen bevorzugt Storage oder Storage.disk(...) verwenden.
177
+ 2. Keine direkten fs-Zugriffe fuer Standardfaelle erzeugen, wenn dieselbe Aufgabe ueber Storage moeglich ist.
178
+ 3. Disk-Auswahl ueber Storage.disk("name") und nicht ueber hart codierte Basisverzeichnisse loesen.
179
+ 4. Vorhandene Operationen wie put, copy, move, delete, mkdir, isDir, isFile, file, readDir und upload verwenden.
180
+ 5. Datei-Metadaten bevorzugt ueber Storage.file(...).exists(), mime(), extension() usw. lesen.
181
+
182
+ Bevorzugt:
183
+
184
+ ```ts
185
+ const filepath = await Storage.disk("public").put(buffer, "exports/report.csv");
186
+ const file = await Storage.disk("public").file(filepath);
187
+ const exists = await file.exists();
188
+ ```
189
+
190
+ Nicht bevorzugt:
191
+
192
+ ```ts
193
+ await fs.promises.writeFile(path.join(process.cwd(), "storage", "exports", "report.csv"), buffer);
194
+ ```
195
+
196
+ ## Datatables
197
+
198
+ 1. Tabellen als Klassen auf Basis von Datatable implementieren.
199
+ 2. Registrierung ueber DatatableRegistry.register(...) oder registerMany(...), nicht ueber projektspezifische Table-Resolver.
200
+ 3. Standard-Endpunkte nach Moeglichkeit ueber DatatableController@restApi und DatatableController@tableExport anbinden.
201
+ 4. Tabellenkonfiguration ueber collection, columns, filter, aggregation, subAggregation, exports, selectableFunctions und Hooks wie onInit, onData, onRow definieren.
202
+ 5. Paginierung, Filterung und Exporte sollen die eingebauten Datatable-Mechanismen verwenden und nicht in jedem Projekt neu implementiert werden.
203
+ 6. Selektierbare Sammelaktionen ueber selectableFunctions definieren, nicht ueber getrennte Ad-hoc-Endpunkte ohne Bezug zur Tabelle.
204
+
205
+ Bevorzugt:
206
+
207
+ ```ts
208
+ Route.post("/api/datatable", "DatatableController@restApi");
209
+ Route.post("/api/datatable/export", "DatatableController@tableExport");
210
+ ```
211
+
212
+ ## Response- und Fehlerstil
213
+
214
+ 1. Bestehende Response-Helfer verwenden und Antworten konsistent strukturieren.
215
+ 2. Bei typischen API-Endpunkten bevorzugt status, message und data klar trennen.
216
+ 3. Fehler nicht mit neuen, parallelen API-Response-Buildern abstrahieren, solange Response ausreicht.
217
+ 4. Middleware-Fehler ueber reject(...), Controller-Fehler ueber klare Statuscodes und res.send(...).
218
+
219
+ ## Was Codex vermeiden soll
220
+
221
+ 1. Keine neuen Resolver wie resolveObjectId, resolveUserId, parseMongoId oder ensureObjectId erzeugen, wenn Model.objectId(...) reicht.
222
+ 2. Keine neuen Utility-Sammlungen fuer String-, Zahl-, Datei- oder Datumslogik erzeugen, wenn Webframez bereits passende Functions exportiert.
223
+ 3. Keine Express-, Fastify- oder Next.js-Muster in Webframez-Controller und -Routen uebertragen.
224
+ 4. Keine direkten Router-, Storage- oder HTTP-Low-Level-Implementierungen bauen, wenn eine Framework-Facade existiert.
225
+ 5. Keine duplizierten CRUD-, Datatable- oder Export-Grundgerueste bauen, wenn DatatableController oder andere Kernbausteine bereits passen.
226
+ 6. Keine Deep-Imports oder interne Framework-Hacks in Consumer-Projekten verwenden.
227
+
228
+ ## Entscheidungsregel bei Unsicherheit
229
+
230
+ Wenn Codex zwischen Eigenbau und Framework-Funktion waehlen muss, gilt standardmaessig:
231
+
232
+ 1. Bestehende Webframez-API verwenden.
233
+ 2. Vorhandene Konvention erweitern.
234
+ 3. Erst zuletzt eine neue Abstraktion einfuehren.
235
+
236
+ Wenn eine neue Abstraktion doch noetig ist, muss im Code klar erkennbar sein, warum die vorhandene Webframez-Funktion nicht ausreicht.
@@ -11,6 +11,8 @@ export declare class Request {
11
11
  query: any;
12
12
  queryRaw: any;
13
13
  params: any;
14
+ routeDomainMatch: string | null;
15
+ routeDomainWildcard: string | null;
14
16
  files: any;
15
17
  socket: any;
16
18
  message: IncomingMessage | null;
@@ -12,6 +12,8 @@ class Request {
12
12
  this.query = {};
13
13
  this.queryRaw = "";
14
14
  this.params = {};
15
+ this.routeDomainMatch = null;
16
+ this.routeDomainWildcard = null;
15
17
  this.files = {};
16
18
  this.socket = undefined;
17
19
  this.message = null;
@@ -5,6 +5,8 @@ type RouteExtensionFactory = (route: RouteFacade) => (...args: any[]) => any;
5
5
  export declare class RouteFacade {
6
6
  tempGroupPrefix: string | null;
7
7
  tempGroupMiddleware: string[] | null;
8
+ tempGroupDomains: string[] | null;
9
+ private normalizeStringArray;
8
10
  private registerWithGroupContext;
9
11
  /**
10
12
  * Register a custom route-method on the Route facade.
@@ -6,16 +6,32 @@ class RouteFacade {
6
6
  constructor() {
7
7
  this.tempGroupPrefix = null;
8
8
  this.tempGroupMiddleware = null;
9
+ this.tempGroupDomains = null;
9
10
  this.registerWithGroupContext = (method, path, component, options) => {
10
- Router_1.Router.register(method, (this.tempGroupPrefix ? this.tempGroupPrefix : "") + path, component, options || this.tempGroupMiddleware
11
- ? Object.assign(Object.assign({}, (options ? options : {})), { middleware: this.tempGroupMiddleware || (options && options.middleware)
12
- ? [
13
- ...(this.tempGroupMiddleware ? this.tempGroupMiddleware : []),
14
- ...(options && options.middleware ? options.middleware : []),
15
- ]
16
- : null }) : {});
11
+ const mergedOptions = Object.assign({}, (options ? options : {}));
12
+ const middlewareFromGroup = this.normalizeStringArray(this.tempGroupMiddleware);
13
+ const middlewareFromRoute = this.normalizeStringArray(options && options.middleware ? options.middleware : []);
14
+ const domainsFromGroup = this.normalizeStringArray(this.tempGroupDomains);
15
+ const domainsFromRoute = this.normalizeStringArray(options && options.domains ? options.domains : []);
16
+ const mergedMiddleware = [...middlewareFromGroup, ...middlewareFromRoute];
17
+ if (mergedMiddleware.length > 0) {
18
+ mergedOptions.middleware = Array.from(new Set(mergedMiddleware));
19
+ }
20
+ const mergedDomains = [...domainsFromGroup, ...domainsFromRoute];
21
+ if (mergedDomains.length > 0) {
22
+ mergedOptions.domains = Array.from(new Set(mergedDomains));
23
+ }
24
+ Router_1.Router.register(method, (this.tempGroupPrefix ? this.tempGroupPrefix : "") + path, component, mergedOptions);
17
25
  };
18
26
  }
27
+ normalizeStringArray(values) {
28
+ if (!Array.isArray(values)) {
29
+ return [];
30
+ }
31
+ return values
32
+ .filter((value) => typeof value === "string" && value.trim() !== "")
33
+ .map((value) => value.trim());
34
+ }
19
35
  /**
20
36
  * Register a custom route-method on the Route facade.
21
37
  * Allows optional packages to add framework-specific route helpers.
@@ -76,17 +92,29 @@ class RouteFacade {
76
92
  group(config, children) {
77
93
  // Handle group prefix
78
94
  const tempGroupPrefixBefore = this.tempGroupPrefix ? this.tempGroupPrefix + "" : null;
79
- const tempGroupMiddlewareBefore = this.tempGroupMiddleware && this.tempGroupMiddleware.length > 0 ? this.tempGroupMiddleware : null;
95
+ const tempGroupMiddlewareBefore = this.tempGroupMiddleware && this.tempGroupMiddleware.length > 0 ? [...this.tempGroupMiddleware] : null;
96
+ const tempGroupDomainsBefore = this.tempGroupDomains && this.tempGroupDomains.length > 0 ? [...this.tempGroupDomains] : null;
80
97
  if (config && config.prefix && config.prefix.trim() !== "") {
81
98
  this.tempGroupPrefix = (this.tempGroupPrefix ? this.tempGroupPrefix : "") + config.prefix;
82
99
  }
83
100
  // Handle group middleware
84
- if (config && config.middleware && config.middleware.length > 0) {
101
+ const groupMiddleware = this.normalizeStringArray(config && config.middleware ? config.middleware : []);
102
+ if (groupMiddleware.length > 0) {
85
103
  if (!this.tempGroupMiddleware || this.tempGroupMiddleware.length === 0) {
86
- this.tempGroupMiddleware = config.middleware;
104
+ this.tempGroupMiddleware = [...groupMiddleware];
105
+ }
106
+ else {
107
+ this.tempGroupMiddleware = [...new Set([...this.tempGroupMiddleware, ...groupMiddleware])];
108
+ }
109
+ }
110
+ // Handle group domains
111
+ const groupDomains = this.normalizeStringArray(config && config.domains ? config.domains : []);
112
+ if (groupDomains.length > 0) {
113
+ if (!this.tempGroupDomains || this.tempGroupDomains.length === 0) {
114
+ this.tempGroupDomains = [...groupDomains];
87
115
  }
88
116
  else {
89
- this.tempGroupMiddleware = [...this.tempGroupMiddleware, ...config.middleware];
117
+ this.tempGroupDomains = [...new Set([...this.tempGroupDomains, ...groupDomains])];
90
118
  }
91
119
  }
92
120
  // Handle children / group body
@@ -94,6 +122,7 @@ class RouteFacade {
94
122
  // Reset temp-group data
95
123
  this.tempGroupPrefix = tempGroupPrefixBefore;
96
124
  this.tempGroupMiddleware = tempGroupMiddlewareBefore;
125
+ this.tempGroupDomains = tempGroupDomainsBefore;
97
126
  }
98
127
  }
99
128
  exports.RouteFacade = RouteFacade;
@@ -10,12 +10,17 @@ type RouteObject = {
10
10
  options: {
11
11
  [key: string]: any;
12
12
  };
13
- params: object;
13
+ params?: object;
14
14
  };
15
15
  type MiddlewareRejectSignal = {
16
16
  __middlewareReject: true;
17
17
  reason?: any;
18
18
  };
19
+ type RouteDomainMatchResult = {
20
+ matches: boolean;
21
+ matchedDomain: string | null;
22
+ wildcard: string | null;
23
+ };
19
24
  declare class RouterFacade {
20
25
  /**
21
26
  * Basename
@@ -34,45 +39,25 @@ declare class RouterFacade {
34
39
  * GET Route Store
35
40
  */
36
41
  routesGET: {
37
- [key: string]: {
38
- path: string;
39
- component: any;
40
- options: object;
41
- params?: object;
42
- };
42
+ [key: string]: RouteObject[];
43
43
  };
44
44
  /**
45
45
  * POST Route Store
46
46
  */
47
47
  routesPOST: {
48
- [key: string]: {
49
- path: string;
50
- component: any;
51
- options: object;
52
- params?: object;
53
- };
48
+ [key: string]: RouteObject[];
54
49
  };
55
50
  /**
56
51
  * PUT Route Store
57
52
  */
58
53
  routesPUT: {
59
- [key: string]: {
60
- path: string;
61
- component: any;
62
- options: object;
63
- params?: object;
64
- };
54
+ [key: string]: RouteObject[];
65
55
  };
66
56
  /**
67
57
  * DELETE Route Store
68
58
  */
69
59
  routesDELETE: {
70
- [key: string]: {
71
- path: string;
72
- component: any;
73
- options: object;
74
- params?: object;
75
- };
60
+ [key: string]: RouteObject[];
76
61
  };
77
62
  /**
78
63
  * Load the application-routes
@@ -112,6 +97,13 @@ declare class RouterFacade {
112
97
  extractParams(path: string, match: any): any;
113
98
  escapeRegexPart(value: string): string;
114
99
  buildRouteRegex(path: string): RegExp;
100
+ normalizeDomainString(value: string): string | null;
101
+ getRequestHostCandidates(request?: Request): string[];
102
+ getRouteDomainFilters(routeObj: RouteObject): string[];
103
+ buildDomainRegex(domainFilter: string): RegExp;
104
+ matchDomainFilter(hostname: string, domainFilter: string): RouteDomainMatchResult;
105
+ resolveDomainMatch(routeObj: RouteObject, request?: Request): RouteDomainMatchResult;
106
+ applyDomainMatchToRequest(request: Request, domainMatch: RouteDomainMatchResult): void;
115
107
  createMiddlewareRejectSignal(reason?: any): MiddlewareRejectSignal;
116
108
  isMiddlewareRejectSignal(error: any): error is MiddlewareRejectSignal;
117
109
  /**