stratal 0.0.6 → 0.0.7
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.
- package/dist/application.d.ts +10 -42
- package/dist/application.d.ts.map +1 -1
- package/dist/application.js +36 -77
- package/dist/application.js.map +1 -1
- package/dist/config/config.module.d.ts.map +1 -1
- package/dist/config/config.module.js +2 -1
- package/dist/config/config.module.js.map +1 -1
- package/dist/config/errors/config-module-not-initialized.error.d.ts +10 -0
- package/dist/config/errors/config-module-not-initialized.error.d.ts.map +1 -0
- package/dist/config/errors/config-module-not-initialized.error.js +12 -0
- package/dist/config/errors/config-module-not-initialized.error.js.map +1 -0
- package/dist/config/errors/index.d.ts +1 -0
- package/dist/config/errors/index.d.ts.map +1 -1
- package/dist/config/errors/index.js +1 -0
- package/dist/config/errors/index.js.map +1 -1
- package/dist/di/container.d.ts +5 -267
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/container.js +13 -288
- package/dist/di/container.js.map +1 -1
- package/dist/di/errors/request-scope-operation-not-allowed.error.d.ts +0 -1
- package/dist/di/errors/request-scope-operation-not-allowed.error.d.ts.map +1 -1
- package/dist/di/errors/request-scope-operation-not-allowed.error.js +0 -1
- package/dist/di/errors/request-scope-operation-not-allowed.error.js.map +1 -1
- package/dist/di/index.d.ts +0 -1
- package/dist/di/index.d.ts.map +1 -1
- package/dist/di/index.js +0 -1
- package/dist/di/index.js.map +1 -1
- package/dist/errors/error-codes.d.ts +2 -0
- package/dist/errors/error-codes.d.ts.map +1 -1
- package/dist/errors/error-codes.js +2 -0
- package/dist/errors/error-codes.js.map +1 -1
- package/dist/events/types.d.ts +1 -1
- package/dist/execution-context.d.ts +4 -0
- package/dist/execution-context.d.ts.map +1 -0
- package/dist/execution-context.js +2 -0
- package/dist/execution-context.js.map +1 -0
- package/dist/i18n/messages/en/errors.d.ts +2 -2
- package/dist/i18n/messages/en/errors.js +2 -2
- package/dist/i18n/messages/en/errors.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/logger/services/logger.service.d.ts +2 -15
- package/dist/logger/services/logger.service.d.ts.map +1 -1
- package/dist/logger/services/logger.service.js +11 -16
- package/dist/logger/services/logger.service.js.map +1 -1
- package/dist/router/errors/hono-app-already-configured.error.d.ts +10 -0
- package/dist/router/errors/hono-app-already-configured.error.d.ts.map +1 -0
- package/dist/router/errors/hono-app-already-configured.error.js +12 -0
- package/dist/router/errors/hono-app-already-configured.error.js.map +1 -0
- package/dist/router/errors/index.d.ts +1 -2
- package/dist/router/errors/index.d.ts.map +1 -1
- package/dist/router/errors/index.js +1 -2
- package/dist/router/errors/index.js.map +1 -1
- package/dist/router/hono-app.d.ts +38 -0
- package/dist/router/hono-app.d.ts.map +1 -0
- package/dist/router/hono-app.js +128 -0
- package/dist/router/hono-app.js.map +1 -0
- package/dist/router/index.d.ts +3 -3
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +6 -4
- package/dist/router/index.js.map +1 -1
- package/dist/router/router.tokens.d.ts +0 -28
- package/dist/router/router.tokens.d.ts.map +1 -1
- package/dist/router/router.tokens.js +0 -28
- package/dist/router/router.tokens.js.map +1 -1
- package/dist/router/services/index.d.ts +0 -1
- package/dist/router/services/index.d.ts.map +1 -1
- package/dist/router/services/index.js +0 -1
- package/dist/router/services/index.js.map +1 -1
- package/dist/stratal.d.ts +9 -26
- package/dist/stratal.d.ts.map +1 -1
- package/dist/stratal.js +22 -50
- package/dist/stratal.js.map +1 -1
- package/package.json +8 -8
- package/dist/di/request-context-store.d.ts +0 -122
- package/dist/di/request-context-store.d.ts.map +0 -1
- package/dist/di/request-context-store.js +0 -135
- package/dist/di/request-context-store.js.map +0 -1
- package/dist/router/errors/router-already-configured.error.d.ts +0 -5
- package/dist/router/errors/router-already-configured.error.d.ts.map +0 -1
- package/dist/router/errors/router-already-configured.error.js +0 -8
- package/dist/router/errors/router-already-configured.error.js.map +0 -1
- package/dist/router/errors/router-not-configured.error.d.ts +0 -5
- package/dist/router/errors/router-not-configured.error.d.ts.map +0 -1
- package/dist/router/errors/router-not-configured.error.js +0 -8
- package/dist/router/errors/router-not-configured.error.js.map +0 -1
- package/dist/router/router.service.d.ts +0 -62
- package/dist/router/router.service.d.ts.map +0 -1
- package/dist/router/router.service.js +0 -166
- package/dist/router/router.service.js.map +0 -1
- package/dist/router/services/request-scope.service.d.ts +0 -42
- package/dist/router/services/request-scope.service.d.ts.map +0 -1
- package/dist/router/services/request-scope.service.js +0 -76
- package/dist/router/services/request-scope.service.js.map +0 -1
package/dist/stratal.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
import { Application } from './application';
|
|
3
|
-
import { ROUTER_TOKENS } from './router';
|
|
4
3
|
/**
|
|
5
4
|
* Stratal — Hono-style entry point for Cloudflare Workers.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
* for
|
|
9
|
-
* initialization from simultaneous requests.
|
|
6
|
+
* Eagerly bootstraps the Application at construction time, dynamically
|
|
7
|
+
* importing `cloudflare:workers` for env and waitUntil.
|
|
10
8
|
*
|
|
11
9
|
* @example
|
|
12
10
|
* ```typescript
|
|
@@ -17,72 +15,46 @@ import { ROUTER_TOKENS } from './router';
|
|
|
17
15
|
* ```
|
|
18
16
|
*/
|
|
19
17
|
export class Stratal {
|
|
20
|
-
config;
|
|
21
18
|
app = null;
|
|
22
|
-
initPromise
|
|
19
|
+
initPromise;
|
|
23
20
|
constructor(config) {
|
|
24
|
-
this.config = config;
|
|
25
21
|
this.fetch = this.fetch.bind(this);
|
|
26
22
|
this.queue = this.queue.bind(this);
|
|
27
23
|
this.scheduled = this.scheduled.bind(this);
|
|
24
|
+
this.initPromise = this.prepareApp(config);
|
|
28
25
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Handle HTTP requests via RouterService.
|
|
31
|
-
*/
|
|
32
26
|
async fetch(request, env, ctx) {
|
|
33
|
-
const app = await this.
|
|
34
|
-
|
|
35
|
-
return router.fetch(request, env, ctx);
|
|
27
|
+
const app = await this.ensureReady();
|
|
28
|
+
return app.hono.fetch(request, env, ctx);
|
|
36
29
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
*/
|
|
40
|
-
async queue(batch, env, ctx) {
|
|
41
|
-
const app = await this.getApplication(env, ctx);
|
|
30
|
+
async queue(batch) {
|
|
31
|
+
const app = await this.ensureReady();
|
|
42
32
|
return app.handleQueue(batch, batch.queue);
|
|
43
33
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*/
|
|
47
|
-
async scheduled(controller, env, ctx) {
|
|
48
|
-
const app = await this.getApplication(env, ctx);
|
|
34
|
+
async scheduled(controller) {
|
|
35
|
+
const app = await this.ensureReady();
|
|
49
36
|
return app.handleScheduled(controller);
|
|
50
37
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
*/
|
|
56
|
-
async getApplication(env, ctx) {
|
|
57
|
-
// Fast path: already initialized
|
|
58
|
-
if (this.app) {
|
|
59
|
-
return this.app;
|
|
60
|
-
}
|
|
61
|
-
// Concurrent initialization guard
|
|
62
|
-
if (this.initPromise) {
|
|
63
|
-
return this.initPromise;
|
|
64
|
-
}
|
|
65
|
-
// Start initialization
|
|
66
|
-
this.initPromise = this.initializeApp(env, ctx);
|
|
38
|
+
get hono() {
|
|
39
|
+
return this.initPromise.then(app => app.hono);
|
|
40
|
+
}
|
|
41
|
+
async shutdown() {
|
|
67
42
|
try {
|
|
68
43
|
this.app = await this.initPromise;
|
|
69
|
-
return this.app;
|
|
70
44
|
}
|
|
71
|
-
|
|
72
|
-
this.initPromise = null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Shut down the application and release all resources.
|
|
77
|
-
*/
|
|
78
|
-
async shutdown() {
|
|
45
|
+
catch { /* ignore */ }
|
|
79
46
|
if (this.app) {
|
|
80
47
|
await this.app.shutdown();
|
|
81
48
|
this.app = null;
|
|
82
49
|
}
|
|
83
50
|
}
|
|
84
|
-
async
|
|
85
|
-
|
|
51
|
+
async ensureReady() {
|
|
52
|
+
this.app ??= await this.initPromise;
|
|
53
|
+
return this.app;
|
|
54
|
+
}
|
|
55
|
+
async prepareApp(config) {
|
|
56
|
+
const { env, waitUntil } = await import('cloudflare:workers');
|
|
57
|
+
const app = new Application({ ...config, env: env, ctx: { waitUntil } });
|
|
86
58
|
await app.initialize();
|
|
87
59
|
return app;
|
|
88
60
|
}
|
package/dist/stratal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stratal.js","sourceRoot":"","sources":["../src/stratal.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAA;AAEzB,OAAO,EAAE,WAAW,EAA0B,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"stratal.js","sourceRoot":"","sources":["../src/stratal.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAA;AAEzB,OAAO,EAAE,WAAW,EAA0B,MAAM,eAAe,CAAA;AAInE;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,OAAO;IACV,GAAG,GAAuB,IAAI,CAAA;IAC9B,WAAW,CAAsB;IAEzC,YAAY,MAAyB;QACnC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAE1C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAgB,EAAE,GAAQ,EAAE,GAAqB;QAC3D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;QACpC,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;IAC1C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAmB;QAC7B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;QACpC,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAA+B;QAC7C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;QACpC,OAAO,GAAG,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC;YAAC,IAAI,CAAC,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAChE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;YACzB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAA;QACjB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,WAAW,CAAC;QACpC,OAAO,IAAI,CAAC,GAAG,CAAA;IACjB,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,MAAyB;QAChD,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAA;QAC7D,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAU,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,CAAA;QAC/E,MAAM,GAAG,CAAC,UAAU,EAAE,CAAA;QACtB,OAAO,GAAG,CAAA;IACZ,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stratal",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "A modular Cloudflare Workers framework with dependency injection, queue-based events, and type-safe configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"@intlify/message-compiler": "^11.2.8",
|
|
86
86
|
"@scalar/hono-api-reference": "^0.10.0",
|
|
87
87
|
"@xmldom/xmldom": "^0.8.11",
|
|
88
|
-
"hono": "^4.12.
|
|
88
|
+
"hono": "^4.12.5",
|
|
89
89
|
"reflect-metadata": "^0.2.2",
|
|
90
90
|
"tsyringe": "^4.10.0",
|
|
91
91
|
"zod": "^4.3.6"
|
|
@@ -131,15 +131,15 @@
|
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
133
|
"devDependencies": {
|
|
134
|
-
"@aws-sdk/client-s3": "3.
|
|
135
|
-
"@aws-sdk/lib-storage": "^3.
|
|
136
|
-
"@aws-sdk/s3-request-presigner": "3.
|
|
137
|
-
"@cloudflare/vitest-pool-workers": "^0.12.
|
|
138
|
-
"@cloudflare/workers-types": "4.
|
|
134
|
+
"@aws-sdk/client-s3": "3.1004.0",
|
|
135
|
+
"@aws-sdk/lib-storage": "^3.1004.0",
|
|
136
|
+
"@aws-sdk/s3-request-presigner": "3.1004.0",
|
|
137
|
+
"@cloudflare/vitest-pool-workers": "^0.12.20",
|
|
138
|
+
"@cloudflare/workers-types": "4.20260307.1",
|
|
139
139
|
"@react-email/components": "^1.0.8",
|
|
140
140
|
"@stratal/testing": "workspace:*",
|
|
141
141
|
"@tus/server": "^2.3.0",
|
|
142
|
-
"@types/node": "^25.3.
|
|
142
|
+
"@types/node": "^25.3.5",
|
|
143
143
|
"@types/nodemailer": "^7.0.11",
|
|
144
144
|
"@types/react": "^19.2.14",
|
|
145
145
|
"@types/react-dom": "^19.2.3",
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import type { DependencyContainer } from 'tsyringe';
|
|
2
|
-
/**
|
|
3
|
-
* Request context store using AsyncLocalStorage
|
|
4
|
-
*
|
|
5
|
-
* Stores and propagates request container across async operations without manual context passing.
|
|
6
|
-
* This enables transparent access to request-scoped services from any part of the application
|
|
7
|
-
* during request handling.
|
|
8
|
-
*
|
|
9
|
-
* **Cloudflare Workers Compatibility**:
|
|
10
|
-
* - Requires `nodejs_als` compatibility flag in wrangler.jsonc
|
|
11
|
-
* - Uses V8's SetContinuationPreservedEmbedderData API (efficient)
|
|
12
|
-
* - Performance overhead: ~3-4% in typical scenarios
|
|
13
|
-
*
|
|
14
|
-
* **Thread Safety**:
|
|
15
|
-
* - Singleton instance shared across application
|
|
16
|
-
* - Each request gets isolated storage context
|
|
17
|
-
* - No context leakage between concurrent requests
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* // In router middleware
|
|
22
|
-
* const store = RequestContextStore.getInstance()
|
|
23
|
-
* await store.run(requestContainer, async () => {
|
|
24
|
-
* // All async operations within this callback have access to requestContainer
|
|
25
|
-
* await handleRequest()
|
|
26
|
-
* })
|
|
27
|
-
*
|
|
28
|
-
* // In service (anywhere in the call stack)
|
|
29
|
-
* const container = RequestContextStore.getInstance().getRequestContainer()
|
|
30
|
-
* if (container) {
|
|
31
|
-
* // We're in request context
|
|
32
|
-
* const service = container.resolve(TOKEN)
|
|
33
|
-
* }
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export declare class RequestContextStore {
|
|
37
|
-
private static instance;
|
|
38
|
-
private readonly storage;
|
|
39
|
-
/**
|
|
40
|
-
* Private constructor - use getInstance() instead
|
|
41
|
-
*/
|
|
42
|
-
private constructor();
|
|
43
|
-
/**
|
|
44
|
-
* Get singleton instance
|
|
45
|
-
*
|
|
46
|
-
* **Note**: Creates instance on first call. Subsequent calls return same instance.
|
|
47
|
-
*/
|
|
48
|
-
static getInstance(): RequestContextStore;
|
|
49
|
-
/**
|
|
50
|
-
* Run callback within request context
|
|
51
|
-
*
|
|
52
|
-
* Container is automatically available to all async operations within the callback,
|
|
53
|
-
* including nested function calls, promises, timers, and queue handlers.
|
|
54
|
-
*
|
|
55
|
-
* @param container - Request-scoped dependency container
|
|
56
|
-
* @param callback - Async operation to run with context
|
|
57
|
-
* @returns Result of callback execution
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```typescript
|
|
61
|
-
* const result = await store.run(requestContainer, async () => {
|
|
62
|
-
* // Context automatically propagates to nested calls
|
|
63
|
-
* await processRequest()
|
|
64
|
-
* return { success: true }
|
|
65
|
-
* })
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
run<T>(container: DependencyContainer, callback: () => T): T;
|
|
69
|
-
/**
|
|
70
|
-
* Get current request container
|
|
71
|
-
*
|
|
72
|
-
* Returns the container for the current async context, or undefined if not in request context.
|
|
73
|
-
*
|
|
74
|
-
* **Use Cases**:
|
|
75
|
-
* - Request-scoped services resolving from request container
|
|
76
|
-
* - Services needing conditional logic based on context availability
|
|
77
|
-
* - Debugging/logging request-specific information
|
|
78
|
-
* @deprecated Use container instead
|
|
79
|
-
* @returns Request container if in request context, undefined otherwise
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* ```typescript
|
|
83
|
-
* const container = store.getRequestContainer()
|
|
84
|
-
* if (container) {
|
|
85
|
-
* // Safe to resolve request-scoped services
|
|
86
|
-
* const i18n = container.resolve(I18N_TOKENS.I18nService)
|
|
87
|
-
* } else {
|
|
88
|
-
* // Not in request context - use fallback
|
|
89
|
-
* console.log('No request context available')
|
|
90
|
-
* }
|
|
91
|
-
* ```
|
|
92
|
-
*/
|
|
93
|
-
getRequestContainer(): DependencyContainer | undefined;
|
|
94
|
-
/**
|
|
95
|
-
* Check if currently in request context
|
|
96
|
-
*
|
|
97
|
-
* Convenience method for conditional logic based on context availability.
|
|
98
|
-
*
|
|
99
|
-
* @returns true if in request context, false otherwise
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```typescript
|
|
103
|
-
* if (store.hasRequestContext()) {
|
|
104
|
-
* // Use request-specific data
|
|
105
|
-
* const locale = getLocaleFromContext()
|
|
106
|
-
* } else {
|
|
107
|
-
* // Use default
|
|
108
|
-
* const locale = 'en'
|
|
109
|
-
* }
|
|
110
|
-
* ```
|
|
111
|
-
*/
|
|
112
|
-
hasRequestContext(): boolean;
|
|
113
|
-
/**
|
|
114
|
-
* Reset singleton instance (for testing only)
|
|
115
|
-
*
|
|
116
|
-
* **Warning**: Only use in test cleanup. Never call in production code.
|
|
117
|
-
*
|
|
118
|
-
* @internal
|
|
119
|
-
*/
|
|
120
|
-
static resetInstance(): void;
|
|
121
|
-
}
|
|
122
|
-
//# sourceMappingURL=request-context-store.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"request-context-store.d.ts","sourceRoot":"","sources":["../../src/di/request-context-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAEhE;;OAEG;IACH,OAAO;IAIP;;;;OAIG;IACH,MAAM,CAAC,WAAW,IAAI,mBAAmB;IAKzC;;;;;;;;;;;;;;;;;;OAkBG;IACH,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC;IAI5D;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,mBAAmB,IAAI,mBAAmB,GAAG,SAAS;IAItD;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB,IAAI,OAAO;IAI5B;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;CAG7B"}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
-
/**
|
|
3
|
-
* Request context store using AsyncLocalStorage
|
|
4
|
-
*
|
|
5
|
-
* Stores and propagates request container across async operations without manual context passing.
|
|
6
|
-
* This enables transparent access to request-scoped services from any part of the application
|
|
7
|
-
* during request handling.
|
|
8
|
-
*
|
|
9
|
-
* **Cloudflare Workers Compatibility**:
|
|
10
|
-
* - Requires `nodejs_als` compatibility flag in wrangler.jsonc
|
|
11
|
-
* - Uses V8's SetContinuationPreservedEmbedderData API (efficient)
|
|
12
|
-
* - Performance overhead: ~3-4% in typical scenarios
|
|
13
|
-
*
|
|
14
|
-
* **Thread Safety**:
|
|
15
|
-
* - Singleton instance shared across application
|
|
16
|
-
* - Each request gets isolated storage context
|
|
17
|
-
* - No context leakage between concurrent requests
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* // In router middleware
|
|
22
|
-
* const store = RequestContextStore.getInstance()
|
|
23
|
-
* await store.run(requestContainer, async () => {
|
|
24
|
-
* // All async operations within this callback have access to requestContainer
|
|
25
|
-
* await handleRequest()
|
|
26
|
-
* })
|
|
27
|
-
*
|
|
28
|
-
* // In service (anywhere in the call stack)
|
|
29
|
-
* const container = RequestContextStore.getInstance().getRequestContainer()
|
|
30
|
-
* if (container) {
|
|
31
|
-
* // We're in request context
|
|
32
|
-
* const service = container.resolve(TOKEN)
|
|
33
|
-
* }
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export class RequestContextStore {
|
|
37
|
-
static instance = null;
|
|
38
|
-
storage;
|
|
39
|
-
/**
|
|
40
|
-
* Private constructor - use getInstance() instead
|
|
41
|
-
*/
|
|
42
|
-
constructor() {
|
|
43
|
-
this.storage = new AsyncLocalStorage();
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Get singleton instance
|
|
47
|
-
*
|
|
48
|
-
* **Note**: Creates instance on first call. Subsequent calls return same instance.
|
|
49
|
-
*/
|
|
50
|
-
static getInstance() {
|
|
51
|
-
RequestContextStore.instance ??= new RequestContextStore();
|
|
52
|
-
return RequestContextStore.instance;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Run callback within request context
|
|
56
|
-
*
|
|
57
|
-
* Container is automatically available to all async operations within the callback,
|
|
58
|
-
* including nested function calls, promises, timers, and queue handlers.
|
|
59
|
-
*
|
|
60
|
-
* @param container - Request-scoped dependency container
|
|
61
|
-
* @param callback - Async operation to run with context
|
|
62
|
-
* @returns Result of callback execution
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```typescript
|
|
66
|
-
* const result = await store.run(requestContainer, async () => {
|
|
67
|
-
* // Context automatically propagates to nested calls
|
|
68
|
-
* await processRequest()
|
|
69
|
-
* return { success: true }
|
|
70
|
-
* })
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
run(container, callback) {
|
|
74
|
-
return this.storage.run(container, callback);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Get current request container
|
|
78
|
-
*
|
|
79
|
-
* Returns the container for the current async context, or undefined if not in request context.
|
|
80
|
-
*
|
|
81
|
-
* **Use Cases**:
|
|
82
|
-
* - Request-scoped services resolving from request container
|
|
83
|
-
* - Services needing conditional logic based on context availability
|
|
84
|
-
* - Debugging/logging request-specific information
|
|
85
|
-
* @deprecated Use container instead
|
|
86
|
-
* @returns Request container if in request context, undefined otherwise
|
|
87
|
-
*
|
|
88
|
-
* @example
|
|
89
|
-
* ```typescript
|
|
90
|
-
* const container = store.getRequestContainer()
|
|
91
|
-
* if (container) {
|
|
92
|
-
* // Safe to resolve request-scoped services
|
|
93
|
-
* const i18n = container.resolve(I18N_TOKENS.I18nService)
|
|
94
|
-
* } else {
|
|
95
|
-
* // Not in request context - use fallback
|
|
96
|
-
* console.log('No request context available')
|
|
97
|
-
* }
|
|
98
|
-
* ```
|
|
99
|
-
*/
|
|
100
|
-
getRequestContainer() {
|
|
101
|
-
return this.storage.getStore();
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Check if currently in request context
|
|
105
|
-
*
|
|
106
|
-
* Convenience method for conditional logic based on context availability.
|
|
107
|
-
*
|
|
108
|
-
* @returns true if in request context, false otherwise
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* ```typescript
|
|
112
|
-
* if (store.hasRequestContext()) {
|
|
113
|
-
* // Use request-specific data
|
|
114
|
-
* const locale = getLocaleFromContext()
|
|
115
|
-
* } else {
|
|
116
|
-
* // Use default
|
|
117
|
-
* const locale = 'en'
|
|
118
|
-
* }
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
hasRequestContext() {
|
|
122
|
-
return this.storage.getStore() !== undefined;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Reset singleton instance (for testing only)
|
|
126
|
-
*
|
|
127
|
-
* **Warning**: Only use in test cleanup. Never call in production code.
|
|
128
|
-
*
|
|
129
|
-
* @internal
|
|
130
|
-
*/
|
|
131
|
-
static resetInstance() {
|
|
132
|
-
RequestContextStore.instance = null;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
//# sourceMappingURL=request-context-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"request-context-store.js","sourceRoot":"","sources":["../../src/di/request-context-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAGpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,OAAO,mBAAmB;IACtB,MAAM,CAAC,QAAQ,GAA+B,IAAI,CAAA;IACzC,OAAO,CAAwC;IAEhE;;OAEG;IACH;QACE,IAAI,CAAC,OAAO,GAAG,IAAI,iBAAiB,EAAuB,CAAA;IAC7D,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,WAAW;QAChB,mBAAmB,CAAC,QAAQ,KAAK,IAAI,mBAAmB,EAAE,CAAA;QAC1D,OAAO,mBAAmB,CAAC,QAAQ,CAAA;IACrC,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,GAAG,CAAI,SAA8B,EAAE,QAAiB;QACtD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IAC9C,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,mBAAmB;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAA;IAChC,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,SAAS,CAAA;IAC9C,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,aAAa;QAClB,mBAAmB,CAAC,QAAQ,GAAG,IAAI,CAAA;IACrC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router-already-configured.error.d.ts","sourceRoot":"","sources":["../../../src/router/errors/router-already-configured.error.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,qBAAa,4BAA6B,SAAQ,gBAAgB;;CAQjE"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ERROR_CODES } from '../../errors';
|
|
2
|
-
import { ApplicationError } from '../../errors';
|
|
3
|
-
export class RouterAlreadyConfiguredError extends ApplicationError {
|
|
4
|
-
constructor() {
|
|
5
|
-
super('errors.routerAlreadyConfigured', ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, {});
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=router-already-configured.error.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router-already-configured.error.js","sourceRoot":"","sources":["../../../src/router/errors/router-already-configured.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,OAAO,4BAA6B,SAAQ,gBAAgB;IAChE;QACE,KAAK,CACH,gCAAgC,EAChC,WAAW,CAAC,MAAM,CAAC,mBAAmB,EACtC,EAAE,CACH,CAAA;IACH,CAAC;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router-not-configured.error.d.ts","sourceRoot":"","sources":["../../../src/router/errors/router-not-configured.error.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,qBAAa,wBAAyB,SAAQ,gBAAgB;;CAQ7D"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ERROR_CODES } from '../../errors';
|
|
2
|
-
import { ApplicationError } from '../../errors';
|
|
3
|
-
export class RouterNotConfiguredError extends ApplicationError {
|
|
4
|
-
constructor() {
|
|
5
|
-
super('errors.routerNotConfigured', ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, {});
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=router-not-configured.error.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router-not-configured.error.js","sourceRoot":"","sources":["../../../src/router/errors/router-not-configured.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,OAAO,wBAAyB,SAAQ,gBAAgB;IAC5D;QACE,KAAK,CACH,4BAA4B,EAC5B,WAAW,CAAC,MAAM,CAAC,mBAAmB,EACtC,EAAE,CACH,CAAA;IACH,CAAC;CACF"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { type Container } from '../di';
|
|
2
|
-
import { type StratalEnv } from '../env';
|
|
3
|
-
import { type LoggerService } from '../logger';
|
|
4
|
-
import { type MiddlewareConfigEntry } from '../middleware';
|
|
5
|
-
import type { Constructor } from '../types';
|
|
6
|
-
import type { IController } from './controller';
|
|
7
|
-
/**
|
|
8
|
-
* RouterService manages HTTP routing and request handling with OpenAPI support
|
|
9
|
-
*
|
|
10
|
-
* Responsibilities:
|
|
11
|
-
* - Creates and configures OpenAPIHono application
|
|
12
|
-
* - Delegates to specialized services:
|
|
13
|
-
* - RequestScopeService: Request-scoped container setup
|
|
14
|
-
* - OpenAPIService: OpenAPI spec and documentation endpoints
|
|
15
|
-
* - RouteRegistrationService: Controller and route registration
|
|
16
|
-
* - Registers global middleware (CORS, logging, error handling)
|
|
17
|
-
* - Handles fetch requests via Hono
|
|
18
|
-
*
|
|
19
|
-
* Note: Route access control (domain-based enforcement) is handled by
|
|
20
|
-
* RouteAccessMiddleware in the tenancy module, applied via TenancyModule.configure().
|
|
21
|
-
*
|
|
22
|
-
* The service is registered as a singleton in the DI container
|
|
23
|
-
* and accessed by the Backend worker's fetch() method.
|
|
24
|
-
*/
|
|
25
|
-
export declare class RouterService {
|
|
26
|
-
private logger;
|
|
27
|
-
private container;
|
|
28
|
-
private app;
|
|
29
|
-
private configured;
|
|
30
|
-
constructor(logger: LoggerService, container: Container);
|
|
31
|
-
/**
|
|
32
|
-
* Setup all middleware in correct order
|
|
33
|
-
* Note: OpenAPI setup is deferred to configure() because it needs controllers
|
|
34
|
-
*/
|
|
35
|
-
private setupMiddleware;
|
|
36
|
-
/**
|
|
37
|
-
* Setup global middleware that runs for all requests
|
|
38
|
-
*/
|
|
39
|
-
private setupGlobalMiddleware;
|
|
40
|
-
/**
|
|
41
|
-
* Configure router with middlewares and controllers atomically
|
|
42
|
-
* This MUST be called immediately after RouterService construction
|
|
43
|
-
* and can only be called once.
|
|
44
|
-
*
|
|
45
|
-
* @param middlewareConfigs - Array of middleware configuration entries from modules
|
|
46
|
-
* @param controllers - Array of controller classes from modules
|
|
47
|
-
*/
|
|
48
|
-
configure(middlewareConfigs: MiddlewareConfigEntry[], controllers: Constructor<IController>[]): void;
|
|
49
|
-
/**
|
|
50
|
-
* Handle incoming fetch request via Hono
|
|
51
|
-
*
|
|
52
|
-
* This method is called by the Backend worker's fetch() method.
|
|
53
|
-
* The request-scoped container is created in RequestScopeService.
|
|
54
|
-
*
|
|
55
|
-
* @param request - Incoming Request object
|
|
56
|
-
* @param env - Cloudflare environment bindings
|
|
57
|
-
* @param ctx - Cloudflare execution context
|
|
58
|
-
* @returns Response object
|
|
59
|
-
*/
|
|
60
|
-
fetch(request: Request, env: StratalEnv, ctx: ExecutionContext): Response | Promise<Response>;
|
|
61
|
-
}
|
|
62
|
-
//# sourceMappingURL=router.service.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router.service.d.ts","sourceRoot":"","sources":["../../src/router/router.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGvD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAA;AAGxC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAA;AAEtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAS/C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,aAAa;IAMtB,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,SAAS;IAPnB,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,UAAU,CAAQ;gBAIhB,MAAM,EAAE,aAAa,EAErB,SAAS,EAAE,SAAS;IA8B9B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;;;;;;OAOG;IACH,SAAS,CAAC,iBAAiB,EAAE,qBAAqB,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,EAAE,GAAG,IAAI;IAgCpG;;;;;;;;;;OAUG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,gBAAgB,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;CAM9F"}
|