@ecopages/core 0.2.0-alpha.1
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/CHANGELOG.md +89 -0
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/package.json +279 -0
- package/src/adapters/abstract/application-adapter.d.ts +168 -0
- package/src/adapters/abstract/application-adapter.js +109 -0
- package/src/adapters/abstract/application-adapter.ts +337 -0
- package/src/adapters/abstract/router-adapter.d.ts +26 -0
- package/src/adapters/abstract/router-adapter.js +5 -0
- package/src/adapters/abstract/router-adapter.ts +30 -0
- package/src/adapters/abstract/server-adapter.d.ts +69 -0
- package/src/adapters/abstract/server-adapter.js +15 -0
- package/src/adapters/abstract/server-adapter.ts +79 -0
- package/src/adapters/bun/client-bridge.d.ts +34 -0
- package/src/adapters/bun/client-bridge.js +48 -0
- package/src/adapters/bun/client-bridge.ts +62 -0
- package/src/adapters/bun/create-app.d.ts +60 -0
- package/src/adapters/bun/create-app.js +117 -0
- package/src/adapters/bun/create-app.ts +189 -0
- package/src/adapters/bun/define-api-handler.d.ts +61 -0
- package/src/adapters/bun/define-api-handler.js +15 -0
- package/src/adapters/bun/define-api-handler.ts +114 -0
- package/src/adapters/bun/hmr-manager.d.ts +84 -0
- package/src/adapters/bun/hmr-manager.js +227 -0
- package/src/adapters/bun/hmr-manager.ts +281 -0
- package/src/adapters/bun/index.d.ts +3 -0
- package/src/adapters/bun/index.js +8 -0
- package/src/adapters/bun/index.ts +3 -0
- package/src/adapters/bun/server-adapter.d.ts +155 -0
- package/src/adapters/bun/server-adapter.js +368 -0
- package/src/adapters/bun/server-adapter.ts +492 -0
- package/src/adapters/bun/server-lifecycle.d.ts +52 -0
- package/src/adapters/bun/server-lifecycle.js +120 -0
- package/src/adapters/bun/server-lifecycle.ts +154 -0
- package/src/adapters/index.d.ts +6 -0
- package/src/adapters/index.js +14 -0
- package/src/adapters/index.ts +6 -0
- package/src/adapters/node/create-app.d.ts +21 -0
- package/src/adapters/node/create-app.js +143 -0
- package/src/adapters/node/create-app.ts +179 -0
- package/src/adapters/node/index.d.ts +4 -0
- package/src/adapters/node/index.js +8 -0
- package/src/adapters/node/index.ts +9 -0
- package/src/adapters/node/node-client-bridge.d.ts +26 -0
- package/src/adapters/node/node-client-bridge.js +66 -0
- package/src/adapters/node/node-client-bridge.ts +79 -0
- package/src/adapters/node/node-hmr-manager.d.ts +62 -0
- package/src/adapters/node/node-hmr-manager.js +221 -0
- package/src/adapters/node/node-hmr-manager.ts +271 -0
- package/src/adapters/node/server-adapter.d.ts +190 -0
- package/src/adapters/node/server-adapter.js +420 -0
- package/src/adapters/node/server-adapter.ts +561 -0
- package/src/adapters/node/static-content-server.d.ts +24 -0
- package/src/adapters/node/static-content-server.js +166 -0
- package/src/adapters/node/static-content-server.ts +203 -0
- package/src/adapters/shared/api-response.d.ts +52 -0
- package/src/adapters/shared/api-response.js +96 -0
- package/src/adapters/shared/api-response.ts +104 -0
- package/src/adapters/shared/application-adapter.d.ts +18 -0
- package/src/adapters/shared/application-adapter.js +90 -0
- package/src/adapters/shared/application-adapter.ts +199 -0
- package/src/adapters/shared/explicit-static-route-matcher.d.ts +38 -0
- package/src/adapters/shared/explicit-static-route-matcher.js +100 -0
- package/src/adapters/shared/explicit-static-route-matcher.ts +134 -0
- package/src/adapters/shared/file-route-middleware-pipeline.d.ts +65 -0
- package/src/adapters/shared/file-route-middleware-pipeline.js +98 -0
- package/src/adapters/shared/file-route-middleware-pipeline.ts +123 -0
- package/src/adapters/shared/fs-server-response-factory.d.ts +19 -0
- package/src/adapters/shared/fs-server-response-factory.js +97 -0
- package/src/adapters/shared/fs-server-response-factory.ts +118 -0
- package/src/adapters/shared/fs-server-response-matcher.d.ts +71 -0
- package/src/adapters/shared/fs-server-response-matcher.js +155 -0
- package/src/adapters/shared/fs-server-response-matcher.ts +198 -0
- package/src/adapters/shared/render-context.d.ts +14 -0
- package/src/adapters/shared/render-context.js +69 -0
- package/src/adapters/shared/render-context.ts +105 -0
- package/src/adapters/shared/server-adapter.d.ts +87 -0
- package/src/adapters/shared/server-adapter.js +353 -0
- package/src/adapters/shared/server-adapter.ts +442 -0
- package/src/adapters/shared/server-route-handler.d.ts +89 -0
- package/src/adapters/shared/server-route-handler.js +120 -0
- package/src/adapters/shared/server-route-handler.ts +166 -0
- package/src/adapters/shared/server-static-builder.d.ts +38 -0
- package/src/adapters/shared/server-static-builder.js +46 -0
- package/src/adapters/shared/server-static-builder.ts +82 -0
- package/src/build/build-adapter.d.ts +74 -0
- package/src/build/build-adapter.js +54 -0
- package/src/build/build-adapter.ts +132 -0
- package/src/build/build-types.d.ts +57 -0
- package/src/build/build-types.js +0 -0
- package/src/build/build-types.ts +83 -0
- package/src/build/esbuild-build-adapter.d.ts +69 -0
- package/src/build/esbuild-build-adapter.js +390 -0
- package/src/build/esbuild-build-adapter.ts +510 -0
- package/src/config/config-builder.d.ts +227 -0
- package/src/config/config-builder.js +392 -0
- package/src/config/config-builder.ts +474 -0
- package/src/constants.d.ts +32 -0
- package/src/constants.js +21 -0
- package/src/constants.ts +39 -0
- package/src/create-app.d.ts +17 -0
- package/src/create-app.js +66 -0
- package/src/create-app.ts +87 -0
- package/src/declarations.d.ts +26 -0
- package/src/define-api-handler.d.ts +25 -0
- package/src/define-api-handler.js +15 -0
- package/src/define-api-handler.ts +66 -0
- package/src/dev/sc-server.d.ts +30 -0
- package/src/dev/sc-server.js +111 -0
- package/src/dev/sc-server.ts +143 -0
- package/src/eco/README.md +636 -0
- package/src/eco/component-render-context.d.ts +105 -0
- package/src/eco/component-render-context.js +77 -0
- package/src/eco/component-render-context.ts +202 -0
- package/src/eco/eco.d.ts +9 -0
- package/src/eco/eco.js +110 -0
- package/src/eco/eco.ts +221 -0
- package/src/eco/eco.types.d.ts +170 -0
- package/src/eco/eco.types.js +0 -0
- package/src/eco/eco.types.ts +202 -0
- package/src/eco/eco.utils.d.ts +40 -0
- package/src/eco/eco.utils.js +40 -0
- package/src/eco/eco.utils.ts +89 -0
- package/src/eco/global-injector-map.d.ts +16 -0
- package/src/eco/global-injector-map.js +80 -0
- package/src/eco/global-injector-map.ts +112 -0
- package/src/eco/lazy-injector-map.d.ts +8 -0
- package/src/eco/lazy-injector-map.js +70 -0
- package/src/eco/lazy-injector-map.ts +120 -0
- package/src/eco/module-dependencies.d.ts +18 -0
- package/src/eco/module-dependencies.js +49 -0
- package/src/eco/module-dependencies.ts +75 -0
- package/src/env.d.ts +20 -0
- package/src/errors/http-error.d.ts +31 -0
- package/src/errors/http-error.js +50 -0
- package/src/errors/http-error.ts +72 -0
- package/src/errors/index.d.ts +2 -0
- package/src/errors/index.js +4 -0
- package/src/errors/index.ts +2 -0
- package/src/errors/locals-access-error.d.ts +4 -0
- package/src/errors/locals-access-error.js +9 -0
- package/src/errors/locals-access-error.ts +7 -0
- package/src/global/app-logger.d.ts +2 -0
- package/src/global/app-logger.js +6 -0
- package/src/global/app-logger.ts +4 -0
- package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-have-HMR-script-injected-in-page-1.png +0 -0
- package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
- package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
- package/src/hmr/client/hmr-runtime.d.ts +10 -0
- package/src/hmr/client/hmr-runtime.js +86 -0
- package/src/hmr/client/hmr-runtime.ts +121 -0
- package/src/hmr/hmr-strategy.d.ts +159 -0
- package/src/hmr/hmr-strategy.js +29 -0
- package/src/hmr/hmr-strategy.ts +172 -0
- package/src/hmr/hmr.test.e2e.d.ts +1 -0
- package/src/hmr/hmr.test.e2e.js +50 -0
- package/src/hmr/hmr.test.e2e.ts +75 -0
- package/src/hmr/strategies/default-hmr-strategy.d.ts +43 -0
- package/src/hmr/strategies/default-hmr-strategy.js +34 -0
- package/src/hmr/strategies/default-hmr-strategy.ts +60 -0
- package/src/hmr/strategies/js-hmr-strategy.d.ts +136 -0
- package/src/hmr/strategies/js-hmr-strategy.js +179 -0
- package/src/hmr/strategies/js-hmr-strategy.ts +308 -0
- package/src/index.browser.d.ts +3 -0
- package/src/index.browser.js +4 -0
- package/src/index.browser.ts +3 -0
- package/src/index.d.ts +5 -0
- package/src/index.js +10 -0
- package/src/index.ts +5 -0
- package/src/integrations/ghtml/ghtml-renderer.d.ts +15 -0
- package/src/integrations/ghtml/ghtml-renderer.js +60 -0
- package/src/integrations/ghtml/ghtml-renderer.ts +93 -0
- package/src/integrations/ghtml/ghtml.plugin.d.ts +20 -0
- package/src/integrations/ghtml/ghtml.plugin.js +21 -0
- package/src/integrations/ghtml/ghtml.plugin.ts +32 -0
- package/src/internal-types.d.ts +200 -0
- package/src/internal-types.js +0 -0
- package/src/internal-types.ts +212 -0
- package/src/plugins/alias-resolver-plugin.d.ts +2 -0
- package/src/plugins/alias-resolver-plugin.js +39 -0
- package/src/plugins/alias-resolver-plugin.ts +45 -0
- package/src/plugins/eco-component-meta-plugin.d.ts +95 -0
- package/src/plugins/eco-component-meta-plugin.js +157 -0
- package/src/plugins/eco-component-meta-plugin.ts +474 -0
- package/src/plugins/integration-plugin.d.ts +102 -0
- package/src/plugins/integration-plugin.js +100 -0
- package/src/plugins/integration-plugin.ts +184 -0
- package/src/plugins/processor.d.ts +82 -0
- package/src/plugins/processor.js +122 -0
- package/src/plugins/processor.ts +220 -0
- package/src/public-types.d.ts +1094 -0
- package/src/public-types.js +0 -0
- package/src/public-types.ts +1255 -0
- package/src/route-renderer/GRAPH.md +387 -0
- package/src/route-renderer/README.md +135 -0
- package/src/route-renderer/component-graph-executor.d.ts +32 -0
- package/src/route-renderer/component-graph-executor.js +31 -0
- package/src/route-renderer/component-graph-executor.ts +84 -0
- package/src/route-renderer/component-graph.d.ts +42 -0
- package/src/route-renderer/component-graph.js +72 -0
- package/src/route-renderer/component-graph.ts +159 -0
- package/src/route-renderer/component-marker.d.ts +52 -0
- package/src/route-renderer/component-marker.js +46 -0
- package/src/route-renderer/component-marker.ts +117 -0
- package/src/route-renderer/dependency-resolver.d.ts +24 -0
- package/src/route-renderer/dependency-resolver.js +428 -0
- package/src/route-renderer/dependency-resolver.ts +596 -0
- package/src/route-renderer/html-post-processing.service.d.ts +40 -0
- package/src/route-renderer/html-post-processing.service.js +86 -0
- package/src/route-renderer/html-post-processing.service.ts +103 -0
- package/src/route-renderer/integration-renderer.d.ts +339 -0
- package/src/route-renderer/integration-renderer.js +526 -0
- package/src/route-renderer/integration-renderer.ts +696 -0
- package/src/route-renderer/marker-graph-resolver.d.ts +76 -0
- package/src/route-renderer/marker-graph-resolver.js +93 -0
- package/src/route-renderer/marker-graph-resolver.ts +153 -0
- package/src/route-renderer/page-module-loader.d.ts +61 -0
- package/src/route-renderer/page-module-loader.js +102 -0
- package/src/route-renderer/page-module-loader.ts +153 -0
- package/src/route-renderer/render-execution.service.d.ts +69 -0
- package/src/route-renderer/render-execution.service.js +91 -0
- package/src/route-renderer/render-execution.service.ts +158 -0
- package/src/route-renderer/render-preparation.service.d.ts +112 -0
- package/src/route-renderer/render-preparation.service.js +243 -0
- package/src/route-renderer/render-preparation.service.ts +358 -0
- package/src/route-renderer/route-renderer.d.ts +26 -0
- package/src/route-renderer/route-renderer.js +68 -0
- package/src/route-renderer/route-renderer.ts +80 -0
- package/src/router/fs-router-scanner.d.ts +41 -0
- package/src/router/fs-router-scanner.js +155 -0
- package/src/router/fs-router-scanner.ts +217 -0
- package/src/router/fs-router.d.ts +26 -0
- package/src/router/fs-router.js +100 -0
- package/src/router/fs-router.ts +122 -0
- package/src/services/asset-processing-service/asset-processing.service.d.ts +41 -0
- package/src/services/asset-processing-service/asset-processing.service.js +250 -0
- package/src/services/asset-processing-service/asset-processing.service.ts +306 -0
- package/src/services/asset-processing-service/asset.factory.d.ts +17 -0
- package/src/services/asset-processing-service/asset.factory.js +82 -0
- package/src/services/asset-processing-service/asset.factory.ts +105 -0
- package/src/services/asset-processing-service/assets.types.d.ts +88 -0
- package/src/services/asset-processing-service/assets.types.js +0 -0
- package/src/services/asset-processing-service/assets.types.ts +112 -0
- package/src/services/asset-processing-service/index.d.ts +3 -0
- package/src/services/asset-processing-service/index.js +3 -0
- package/src/services/asset-processing-service/index.ts +3 -0
- package/src/services/asset-processing-service/processor.interface.d.ts +22 -0
- package/src/services/asset-processing-service/processor.interface.js +6 -0
- package/src/services/asset-processing-service/processor.interface.ts +27 -0
- package/src/services/asset-processing-service/processor.registry.d.ts +8 -0
- package/src/services/asset-processing-service/processor.registry.js +15 -0
- package/src/services/asset-processing-service/processor.registry.ts +18 -0
- package/src/services/asset-processing-service/processors/base/base-processor.d.ts +24 -0
- package/src/services/asset-processing-service/processors/base/base-processor.js +59 -0
- package/src/services/asset-processing-service/processors/base/base-processor.ts +76 -0
- package/src/services/asset-processing-service/processors/base/base-script-processor.d.ts +16 -0
- package/src/services/asset-processing-service/processors/base/base-script-processor.js +80 -0
- package/src/services/asset-processing-service/processors/base/base-script-processor.ts +105 -0
- package/src/services/asset-processing-service/processors/index.d.ts +5 -0
- package/src/services/asset-processing-service/processors/index.js +5 -0
- package/src/services/asset-processing-service/processors/index.ts +5 -0
- package/src/services/asset-processing-service/processors/script/content-script.processor.d.ts +5 -0
- package/src/services/asset-processing-service/processors/script/content-script.processor.js +57 -0
- package/src/services/asset-processing-service/processors/script/content-script.processor.ts +66 -0
- package/src/services/asset-processing-service/processors/script/file-script.processor.d.ts +8 -0
- package/src/services/asset-processing-service/processors/script/file-script.processor.js +76 -0
- package/src/services/asset-processing-service/processors/script/file-script.processor.ts +88 -0
- package/src/services/asset-processing-service/processors/script/node-module-script.processor.d.ts +7 -0
- package/src/services/asset-processing-service/processors/script/node-module-script.processor.js +74 -0
- package/src/services/asset-processing-service/processors/script/node-module-script.processor.ts +84 -0
- package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +5 -0
- package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +25 -0
- package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.ts +27 -0
- package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +9 -0
- package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +63 -0
- package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.ts +77 -0
- package/src/services/cache/cache.types.d.ts +107 -0
- package/src/services/cache/cache.types.js +0 -0
- package/src/services/cache/cache.types.ts +126 -0
- package/src/services/cache/index.d.ts +7 -0
- package/src/services/cache/index.js +7 -0
- package/src/services/cache/index.ts +18 -0
- package/src/services/cache/memory-cache-store.d.ts +42 -0
- package/src/services/cache/memory-cache-store.js +98 -0
- package/src/services/cache/memory-cache-store.ts +130 -0
- package/src/services/cache/page-cache-service.d.ts +70 -0
- package/src/services/cache/page-cache-service.js +152 -0
- package/src/services/cache/page-cache-service.ts +202 -0
- package/src/services/html-transformer.service.d.ts +50 -0
- package/src/services/html-transformer.service.js +163 -0
- package/src/services/html-transformer.service.ts +217 -0
- package/src/services/page-module-import.service.d.ts +37 -0
- package/src/services/page-module-import.service.js +88 -0
- package/src/services/page-module-import.service.ts +129 -0
- package/src/services/page-request-cache-coordinator.service.d.ts +75 -0
- package/src/services/page-request-cache-coordinator.service.js +107 -0
- package/src/services/page-request-cache-coordinator.service.ts +128 -0
- package/src/services/schema-validation-service.d.ts +122 -0
- package/src/services/schema-validation-service.js +101 -0
- package/src/services/schema-validation-service.ts +204 -0
- package/src/services/validation/standard-schema.types.d.ts +65 -0
- package/src/services/validation/standard-schema.types.js +0 -0
- package/src/services/validation/standard-schema.types.ts +68 -0
- package/src/static-site-generator/static-site-generator.d.ts +57 -0
- package/src/static-site-generator/static-site-generator.js +272 -0
- package/src/static-site-generator/static-site-generator.ts +359 -0
- package/src/utils/css.d.ts +1 -0
- package/src/utils/css.js +7 -0
- package/src/utils/css.ts +5 -0
- package/src/utils/deep-merge.d.ts +14 -0
- package/src/utils/deep-merge.js +32 -0
- package/src/utils/deep-merge.ts +47 -0
- package/src/utils/hash.d.ts +1 -0
- package/src/utils/hash.js +7 -0
- package/src/utils/hash.ts +5 -0
- package/src/utils/html.d.ts +1 -0
- package/src/utils/html.js +4 -0
- package/src/utils/html.ts +1 -0
- package/src/utils/invariant.d.ts +5 -0
- package/src/utils/invariant.js +11 -0
- package/src/utils/invariant.ts +15 -0
- package/src/utils/locals-utils.d.ts +15 -0
- package/src/utils/locals-utils.js +24 -0
- package/src/utils/locals-utils.ts +37 -0
- package/src/utils/parse-cli-args.d.ts +24 -0
- package/src/utils/parse-cli-args.js +47 -0
- package/src/utils/parse-cli-args.ts +83 -0
- package/src/utils/path-utils.module.d.ts +5 -0
- package/src/utils/path-utils.module.js +14 -0
- package/src/utils/path-utils.module.ts +14 -0
- package/src/utils/runtime.d.ts +11 -0
- package/src/utils/runtime.js +40 -0
- package/src/utils/runtime.ts +44 -0
- package/src/utils/server-utils.module.d.ts +19 -0
- package/src/utils/server-utils.module.js +56 -0
- package/src/utils/server-utils.module.ts +67 -0
- package/src/watchers/project-watcher.d.ts +120 -0
- package/src/watchers/project-watcher.js +238 -0
- package/src/watchers/project-watcher.test-helpers.d.ts +4 -0
- package/src/watchers/project-watcher.test-helpers.js +51 -0
- package/src/watchers/project-watcher.test-helpers.ts +40 -0
- package/src/watchers/project-watcher.ts +306 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { getCacheControlHeader, type PageCacheService } from './cache/page-cache-service.ts';
|
|
2
|
+
import type { CacheStrategy, RenderResult } from './cache/cache.types.ts';
|
|
3
|
+
|
|
4
|
+
type CacheStatus = 'hit' | 'miss' | 'stale' | 'expired' | 'disabled';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Coordinates request-time page caching concerns around one render invocation.
|
|
8
|
+
*
|
|
9
|
+
* This service keeps `FileSystemResponseMatcher` from owning low-level cache
|
|
10
|
+
* policy mechanics such as cache key construction, `dynamic` bypass behavior,
|
|
11
|
+
* body normalization for cache storage, and final cache header generation.
|
|
12
|
+
*/
|
|
13
|
+
export class PageRequestCacheCoordinator {
|
|
14
|
+
constructor(
|
|
15
|
+
private cacheService: PageCacheService | null,
|
|
16
|
+
private defaultCacheStrategy: CacheStrategy,
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Builds the cache key used for page lookups.
|
|
21
|
+
*
|
|
22
|
+
* Query parameters are part of the key so two requests that hit the same
|
|
23
|
+
* pathname but differ by search params do not share the same rendered entry.
|
|
24
|
+
*
|
|
25
|
+
* @param input Pathname plus optional query record.
|
|
26
|
+
* @returns Stable cache key for the request.
|
|
27
|
+
*/
|
|
28
|
+
buildCacheKey(input: { pathname: string; query?: Record<string, string> }): string {
|
|
29
|
+
let key = input.pathname;
|
|
30
|
+
if (input.query && Object.keys(input.query).length > 0) {
|
|
31
|
+
const queryString = new URLSearchParams(input.query).toString();
|
|
32
|
+
key += `?${queryString}`;
|
|
33
|
+
}
|
|
34
|
+
return key;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolves a render request through the configured cache policy.
|
|
39
|
+
*
|
|
40
|
+
* Pages using `dynamic` rendering, or applications without a cache service,
|
|
41
|
+
* bypass cache lookup entirely and still receive the same response header
|
|
42
|
+
* contract as cached pages.
|
|
43
|
+
*
|
|
44
|
+
* @param options Cache coordination inputs for one page request.
|
|
45
|
+
* @returns HTTP response with cache headers applied.
|
|
46
|
+
*/
|
|
47
|
+
async render(options: {
|
|
48
|
+
cacheKey: string;
|
|
49
|
+
pageCacheStrategy: CacheStrategy;
|
|
50
|
+
renderFn: () => Promise<RenderResult>;
|
|
51
|
+
}): Promise<Response> {
|
|
52
|
+
if (!this.cacheService || options.pageCacheStrategy === 'dynamic') {
|
|
53
|
+
const { html, strategy } = await options.renderFn();
|
|
54
|
+
return this.createCachedResponse(html, strategy, 'disabled');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const result = await this.cacheService.getOrCreate(
|
|
58
|
+
options.cacheKey,
|
|
59
|
+
options.pageCacheStrategy,
|
|
60
|
+
options.renderFn,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return this.createCachedResponse(result.html, result.strategy, result.status);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Exposes the underlying cache service for invalidation and adapter plumbing.
|
|
68
|
+
*
|
|
69
|
+
* @returns Configured cache service or `null` when caching is disabled.
|
|
70
|
+
*/
|
|
71
|
+
getCacheService(): PageCacheService | null {
|
|
72
|
+
return this.cacheService;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Returns the default render strategy used when a page does not declare one.
|
|
77
|
+
*
|
|
78
|
+
* @returns Application-level fallback cache strategy.
|
|
79
|
+
*/
|
|
80
|
+
getDefaultCacheStrategy(): CacheStrategy {
|
|
81
|
+
return this.defaultCacheStrategy;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Normalizes various route render body shapes into a cacheable string.
|
|
86
|
+
*
|
|
87
|
+
* Page rendering may produce strings, buffers, byte arrays, or streams. The
|
|
88
|
+
* matcher needs a single representation before passing HTML through the cache
|
|
89
|
+
* layer, so this method centralizes the conversion rules.
|
|
90
|
+
*
|
|
91
|
+
* @param body Render output body in any supported form.
|
|
92
|
+
* @returns HTML string representation.
|
|
93
|
+
*/
|
|
94
|
+
async bodyToString(body: unknown): Promise<string> {
|
|
95
|
+
if (typeof body === 'string') {
|
|
96
|
+
return body;
|
|
97
|
+
}
|
|
98
|
+
if (Buffer.isBuffer(body)) {
|
|
99
|
+
return body.toString('utf-8');
|
|
100
|
+
}
|
|
101
|
+
if (body instanceof ReadableStream) {
|
|
102
|
+
return new Response(body).text();
|
|
103
|
+
}
|
|
104
|
+
if (body instanceof Uint8Array) {
|
|
105
|
+
return new TextDecoder().decode(body);
|
|
106
|
+
}
|
|
107
|
+
return String(body);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Creates the final HTML response with the current cache semantics encoded in
|
|
112
|
+
* response headers.
|
|
113
|
+
*
|
|
114
|
+
* @param html Rendered page HTML.
|
|
115
|
+
* @param strategy Effective cache strategy for the response.
|
|
116
|
+
* @param cacheStatus Status used for `X-Cache` and `Cache-Control` generation.
|
|
117
|
+
* @returns HTTP response ready to send to the client.
|
|
118
|
+
*/
|
|
119
|
+
private createCachedResponse(html: string, strategy: CacheStrategy, cacheStatus: CacheStatus): Response {
|
|
120
|
+
const headers: HeadersInit = {
|
|
121
|
+
'Content-Type': 'text/html',
|
|
122
|
+
'Cache-Control': getCacheControlHeader(cacheStatus === 'disabled' ? 'disabled' : strategy),
|
|
123
|
+
'X-Cache': cacheStatus.toUpperCase(),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return new Response(html, { headers });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { StandardSchema } from './validation/standard-schema.types.js';
|
|
2
|
+
export interface ValidationResult<T = unknown> {
|
|
3
|
+
success: boolean;
|
|
4
|
+
data?: T;
|
|
5
|
+
errors?: Array<{
|
|
6
|
+
message: string;
|
|
7
|
+
path?: Array<string | number>;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export interface ValidationSource {
|
|
11
|
+
body?: unknown;
|
|
12
|
+
query?: Record<string, string>;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
params?: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
export interface ValidationSchemas {
|
|
17
|
+
body?: StandardSchema;
|
|
18
|
+
query?: StandardSchema;
|
|
19
|
+
headers?: StandardSchema;
|
|
20
|
+
params?: StandardSchema;
|
|
21
|
+
}
|
|
22
|
+
export interface ValidatedData {
|
|
23
|
+
body?: unknown;
|
|
24
|
+
query?: unknown;
|
|
25
|
+
headers?: unknown;
|
|
26
|
+
params?: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Service for validating request data using Standard Schema compliant validators.
|
|
30
|
+
*
|
|
31
|
+
* This service provides a unified interface for validating HTTP request data (body, query parameters, headers)
|
|
32
|
+
* using any validation library that implements the Standard Schema specification.
|
|
33
|
+
*
|
|
34
|
+
* @example Using with Zod
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { z } from 'zod';
|
|
37
|
+
* import { SchemaValidationService } from './schema-validation-service.js';
|
|
38
|
+
*
|
|
39
|
+
* const service = new SchemaValidationService();
|
|
40
|
+
* const result = await service.validateRequest(
|
|
41
|
+
* { body: { title: 'Hello', count: 42 } },
|
|
42
|
+
* { body: z.object({ title: z.string(), count: z.number() }) }
|
|
43
|
+
* );
|
|
44
|
+
*
|
|
45
|
+
* if (result.success) {
|
|
46
|
+
* console.log(result.data.body);
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example Using with Valibot
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import * as v from 'valibot';
|
|
53
|
+
*
|
|
54
|
+
* const result = await service.validateRequest(
|
|
55
|
+
* { query: { page: '1' } },
|
|
56
|
+
* { query: v.object({ page: v.string() }) }
|
|
57
|
+
* );
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @example Using with ArkType
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { type } from 'arktype';
|
|
63
|
+
*
|
|
64
|
+
* const result = await service.validateRequest(
|
|
65
|
+
* { headers: { 'authorization': 'Bearer token' } },
|
|
66
|
+
* { headers: type({ authorization: 'string' }) }
|
|
67
|
+
* );
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @example Multiple sources
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const result = await service.validateRequest(
|
|
73
|
+
* {
|
|
74
|
+
* body: { title: 'Post' },
|
|
75
|
+
* query: { format: 'json' },
|
|
76
|
+
* headers: { 'content-type': 'application/json' }
|
|
77
|
+
* },
|
|
78
|
+
* {
|
|
79
|
+
* body: z.object({ title: z.string() }),
|
|
80
|
+
* query: v.object({ format: v.string() }),
|
|
81
|
+
* headers: type({ 'content-type': 'string' })
|
|
82
|
+
* }
|
|
83
|
+
* );
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* Supported libraries: Zod, Valibot, ArkType, Effect Schema (with standardSchemaV1 wrapper)
|
|
87
|
+
*/
|
|
88
|
+
export declare class SchemaValidationService {
|
|
89
|
+
/**
|
|
90
|
+
* Validates request data against provided schemas.
|
|
91
|
+
*
|
|
92
|
+
* Validates body, query parameters, and headers against their respective schemas.
|
|
93
|
+
* All validations are performed, and errors are aggregated from all sources.
|
|
94
|
+
*
|
|
95
|
+
* @param source - The data to validate (body, query, headers)
|
|
96
|
+
* @param schemas - The Standard Schema validators for each source
|
|
97
|
+
* @returns Validation result with validated data or aggregated errors
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const result = await service.validateRequest(
|
|
102
|
+
* { body: { name: 'John', age: 30 } },
|
|
103
|
+
* { body: z.object({ name: z.string(), age: z.number() }) }
|
|
104
|
+
* );
|
|
105
|
+
*
|
|
106
|
+
* if (result.success) {
|
|
107
|
+
* const validated = result.data.body;
|
|
108
|
+
* } else {
|
|
109
|
+
* console.error(result.errors);
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
validateRequest(source: ValidationSource, schemas: ValidationSchemas): Promise<ValidationResult<ValidatedData>>;
|
|
114
|
+
/**
|
|
115
|
+
* Validates a single value against a Standard Schema.
|
|
116
|
+
*
|
|
117
|
+
* @param schema - The Standard Schema validator
|
|
118
|
+
* @param data - The data to validate
|
|
119
|
+
* @returns Validation result with validated data or errors
|
|
120
|
+
*/
|
|
121
|
+
private validateWithSchema;
|
|
122
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
class SchemaValidationService {
|
|
2
|
+
/**
|
|
3
|
+
* Validates request data against provided schemas.
|
|
4
|
+
*
|
|
5
|
+
* Validates body, query parameters, and headers against their respective schemas.
|
|
6
|
+
* All validations are performed, and errors are aggregated from all sources.
|
|
7
|
+
*
|
|
8
|
+
* @param source - The data to validate (body, query, headers)
|
|
9
|
+
* @param schemas - The Standard Schema validators for each source
|
|
10
|
+
* @returns Validation result with validated data or aggregated errors
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const result = await service.validateRequest(
|
|
15
|
+
* { body: { name: 'John', age: 30 } },
|
|
16
|
+
* { body: z.object({ name: z.string(), age: z.number() }) }
|
|
17
|
+
* );
|
|
18
|
+
*
|
|
19
|
+
* if (result.success) {
|
|
20
|
+
* const validated = result.data.body;
|
|
21
|
+
* } else {
|
|
22
|
+
* console.error(result.errors);
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
async validateRequest(source, schemas) {
|
|
27
|
+
const validated = {};
|
|
28
|
+
const allErrors = [];
|
|
29
|
+
if (schemas.body && source.body !== void 0) {
|
|
30
|
+
const result = await this.validateWithSchema(schemas.body, source.body);
|
|
31
|
+
if (!result.success) {
|
|
32
|
+
allErrors.push(...result.errors || []);
|
|
33
|
+
} else {
|
|
34
|
+
validated.body = result.data;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (schemas.query && source.query) {
|
|
38
|
+
const result = await this.validateWithSchema(schemas.query, source.query);
|
|
39
|
+
if (!result.success) {
|
|
40
|
+
allErrors.push(...result.errors || []);
|
|
41
|
+
} else {
|
|
42
|
+
validated.query = result.data;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (schemas.headers && source.headers) {
|
|
46
|
+
const result = await this.validateWithSchema(schemas.headers, source.headers);
|
|
47
|
+
if (!result.success) {
|
|
48
|
+
allErrors.push(...result.errors || []);
|
|
49
|
+
} else {
|
|
50
|
+
validated.headers = result.data;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (schemas.params && source.params) {
|
|
54
|
+
const result = await this.validateWithSchema(schemas.params, source.params);
|
|
55
|
+
if (!result.success) {
|
|
56
|
+
allErrors.push(...result.errors || []);
|
|
57
|
+
} else {
|
|
58
|
+
validated.params = result.data;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (allErrors.length > 0) {
|
|
62
|
+
return { success: false, errors: allErrors };
|
|
63
|
+
}
|
|
64
|
+
return { success: true, data: validated };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validates a single value against a Standard Schema.
|
|
68
|
+
*
|
|
69
|
+
* @param schema - The Standard Schema validator
|
|
70
|
+
* @param data - The data to validate
|
|
71
|
+
* @returns Validation result with validated data or errors
|
|
72
|
+
*/
|
|
73
|
+
async validateWithSchema(schema, data) {
|
|
74
|
+
try {
|
|
75
|
+
const resultOrPromise = schema["~standard"].validate(data);
|
|
76
|
+
const result = resultOrPromise instanceof Promise ? await resultOrPromise : resultOrPromise;
|
|
77
|
+
if (result.issues) {
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
errors: result.issues.map((issue) => ({
|
|
81
|
+
message: issue.message,
|
|
82
|
+
path: issue.path?.map((p) => typeof p === "object" && "key" in p ? p.key : p)
|
|
83
|
+
}))
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return { success: true, data: result.value };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
errors: [
|
|
91
|
+
{
|
|
92
|
+
message: error instanceof Error ? error.message : "Validation failed"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
SchemaValidationService
|
|
101
|
+
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { StandardSchema, StandardSchemaIssue } from './validation/standard-schema.types.ts';
|
|
2
|
+
|
|
3
|
+
export interface ValidationResult<T = unknown> {
|
|
4
|
+
success: boolean;
|
|
5
|
+
data?: T;
|
|
6
|
+
errors?: Array<{
|
|
7
|
+
message: string;
|
|
8
|
+
path?: Array<string | number>;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ValidationSource {
|
|
13
|
+
body?: unknown;
|
|
14
|
+
query?: Record<string, string>;
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
params?: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ValidationSchemas {
|
|
20
|
+
body?: StandardSchema;
|
|
21
|
+
query?: StandardSchema;
|
|
22
|
+
headers?: StandardSchema;
|
|
23
|
+
params?: StandardSchema;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ValidatedData {
|
|
27
|
+
body?: unknown;
|
|
28
|
+
query?: unknown;
|
|
29
|
+
headers?: unknown;
|
|
30
|
+
params?: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Service for validating request data using Standard Schema compliant validators.
|
|
35
|
+
*
|
|
36
|
+
* This service provides a unified interface for validating HTTP request data (body, query parameters, headers)
|
|
37
|
+
* using any validation library that implements the Standard Schema specification.
|
|
38
|
+
*
|
|
39
|
+
* @example Using with Zod
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import { z } from 'zod';
|
|
42
|
+
* import { SchemaValidationService } from './schema-validation-service.ts';
|
|
43
|
+
*
|
|
44
|
+
* const service = new SchemaValidationService();
|
|
45
|
+
* const result = await service.validateRequest(
|
|
46
|
+
* { body: { title: 'Hello', count: 42 } },
|
|
47
|
+
* { body: z.object({ title: z.string(), count: z.number() }) }
|
|
48
|
+
* );
|
|
49
|
+
*
|
|
50
|
+
* if (result.success) {
|
|
51
|
+
* console.log(result.data.body);
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @example Using with Valibot
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import * as v from 'valibot';
|
|
58
|
+
*
|
|
59
|
+
* const result = await service.validateRequest(
|
|
60
|
+
* { query: { page: '1' } },
|
|
61
|
+
* { query: v.object({ page: v.string() }) }
|
|
62
|
+
* );
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example Using with ArkType
|
|
66
|
+
* ```typescript
|
|
67
|
+
* import { type } from 'arktype';
|
|
68
|
+
*
|
|
69
|
+
* const result = await service.validateRequest(
|
|
70
|
+
* { headers: { 'authorization': 'Bearer token' } },
|
|
71
|
+
* { headers: type({ authorization: 'string' }) }
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @example Multiple sources
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const result = await service.validateRequest(
|
|
78
|
+
* {
|
|
79
|
+
* body: { title: 'Post' },
|
|
80
|
+
* query: { format: 'json' },
|
|
81
|
+
* headers: { 'content-type': 'application/json' }
|
|
82
|
+
* },
|
|
83
|
+
* {
|
|
84
|
+
* body: z.object({ title: z.string() }),
|
|
85
|
+
* query: v.object({ format: v.string() }),
|
|
86
|
+
* headers: type({ 'content-type': 'string' })
|
|
87
|
+
* }
|
|
88
|
+
* );
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* Supported libraries: Zod, Valibot, ArkType, Effect Schema (with standardSchemaV1 wrapper)
|
|
92
|
+
*/
|
|
93
|
+
export class SchemaValidationService {
|
|
94
|
+
/**
|
|
95
|
+
* Validates request data against provided schemas.
|
|
96
|
+
*
|
|
97
|
+
* Validates body, query parameters, and headers against their respective schemas.
|
|
98
|
+
* All validations are performed, and errors are aggregated from all sources.
|
|
99
|
+
*
|
|
100
|
+
* @param source - The data to validate (body, query, headers)
|
|
101
|
+
* @param schemas - The Standard Schema validators for each source
|
|
102
|
+
* @returns Validation result with validated data or aggregated errors
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const result = await service.validateRequest(
|
|
107
|
+
* { body: { name: 'John', age: 30 } },
|
|
108
|
+
* { body: z.object({ name: z.string(), age: z.number() }) }
|
|
109
|
+
* );
|
|
110
|
+
*
|
|
111
|
+
* if (result.success) {
|
|
112
|
+
* const validated = result.data.body;
|
|
113
|
+
* } else {
|
|
114
|
+
* console.error(result.errors);
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
async validateRequest(
|
|
119
|
+
source: ValidationSource,
|
|
120
|
+
schemas: ValidationSchemas,
|
|
121
|
+
): Promise<ValidationResult<ValidatedData>> {
|
|
122
|
+
const validated: ValidatedData = {};
|
|
123
|
+
const allErrors: Array<{ message: string; path?: Array<string | number> }> = [];
|
|
124
|
+
|
|
125
|
+
if (schemas.body && source.body !== undefined) {
|
|
126
|
+
const result = await this.validateWithSchema(schemas.body, source.body);
|
|
127
|
+
if (!result.success) {
|
|
128
|
+
allErrors.push(...(result.errors || []));
|
|
129
|
+
} else {
|
|
130
|
+
validated.body = result.data;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (schemas.query && source.query) {
|
|
135
|
+
const result = await this.validateWithSchema(schemas.query, source.query);
|
|
136
|
+
if (!result.success) {
|
|
137
|
+
allErrors.push(...(result.errors || []));
|
|
138
|
+
} else {
|
|
139
|
+
validated.query = result.data;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (schemas.headers && source.headers) {
|
|
144
|
+
const result = await this.validateWithSchema(schemas.headers, source.headers);
|
|
145
|
+
if (!result.success) {
|
|
146
|
+
allErrors.push(...(result.errors || []));
|
|
147
|
+
} else {
|
|
148
|
+
validated.headers = result.data;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (schemas.params && source.params) {
|
|
153
|
+
const result = await this.validateWithSchema(schemas.params, source.params);
|
|
154
|
+
if (!result.success) {
|
|
155
|
+
allErrors.push(...(result.errors || []));
|
|
156
|
+
} else {
|
|
157
|
+
validated.params = result.data;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (allErrors.length > 0) {
|
|
162
|
+
return { success: false, errors: allErrors };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return { success: true, data: validated };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Validates a single value against a Standard Schema.
|
|
170
|
+
*
|
|
171
|
+
* @param schema - The Standard Schema validator
|
|
172
|
+
* @param data - The data to validate
|
|
173
|
+
* @returns Validation result with validated data or errors
|
|
174
|
+
*/
|
|
175
|
+
private async validateWithSchema<T>(schema: StandardSchema, data: unknown): Promise<ValidationResult<T>> {
|
|
176
|
+
try {
|
|
177
|
+
const resultOrPromise = schema['~standard'].validate(data);
|
|
178
|
+
const result = resultOrPromise instanceof Promise ? await resultOrPromise : resultOrPromise;
|
|
179
|
+
|
|
180
|
+
if (result.issues) {
|
|
181
|
+
return {
|
|
182
|
+
success: false,
|
|
183
|
+
errors: result.issues.map((issue: StandardSchemaIssue) => ({
|
|
184
|
+
message: issue.message,
|
|
185
|
+
path: issue.path?.map((p) => (typeof p === 'object' && 'key' in p ? p.key : p)) as
|
|
186
|
+
| Array<string | number>
|
|
187
|
+
| undefined,
|
|
188
|
+
})),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return { success: true, data: result.value as T };
|
|
193
|
+
} catch (error) {
|
|
194
|
+
return {
|
|
195
|
+
success: false,
|
|
196
|
+
errors: [
|
|
197
|
+
{
|
|
198
|
+
message: error instanceof Error ? error.message : 'Validation failed',
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard Schema interface for universal validation.
|
|
3
|
+
* Compatible with Zod, Valibot, ArkType, Effect Schema, and other validation libraries.
|
|
4
|
+
*
|
|
5
|
+
* @see https://standardschema.dev
|
|
6
|
+
*
|
|
7
|
+
* @example Using with Zod
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { z } from 'zod';
|
|
10
|
+
*
|
|
11
|
+
* const bodySchema = z.object({
|
|
12
|
+
* title: z.string().min(1),
|
|
13
|
+
* content: z.string()
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* app.post('/posts', async (ctx) => {
|
|
17
|
+
* const { title, content } = ctx.body;
|
|
18
|
+
* return ctx.json({ id: 1, title, content });
|
|
19
|
+
* }, {
|
|
20
|
+
* schema: { body: bodySchema }
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface StandardSchema<Input = unknown, Output = Input> {
|
|
25
|
+
readonly '~standard': {
|
|
26
|
+
readonly version: 1;
|
|
27
|
+
readonly vendor: string;
|
|
28
|
+
readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
|
|
29
|
+
readonly types?: {
|
|
30
|
+
readonly input: Input;
|
|
31
|
+
readonly output: Output;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Result of Standard Schema validation.
|
|
37
|
+
*/
|
|
38
|
+
export type StandardSchemaResult<Output> = StandardSchemaSuccessResult<Output> | StandardSchemaFailureResult;
|
|
39
|
+
/**
|
|
40
|
+
* Successful validation result.
|
|
41
|
+
*/
|
|
42
|
+
export interface StandardSchemaSuccessResult<Output> {
|
|
43
|
+
readonly value: Output;
|
|
44
|
+
readonly issues?: undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Failed validation result.
|
|
48
|
+
*/
|
|
49
|
+
export interface StandardSchemaFailureResult {
|
|
50
|
+
readonly value?: undefined;
|
|
51
|
+
readonly issues: ReadonlyArray<StandardSchemaIssue>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validation issue details.
|
|
55
|
+
*/
|
|
56
|
+
export interface StandardSchemaIssue {
|
|
57
|
+
readonly message: string;
|
|
58
|
+
readonly path?: ReadonlyArray<PropertyKey | {
|
|
59
|
+
key: PropertyKey;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Infers the output type from a Standard Schema.
|
|
64
|
+
*/
|
|
65
|
+
export type InferOutput<T extends StandardSchema> = T extends StandardSchema<any, infer O> ? O : never;
|
|
File without changes
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard Schema interface for universal validation.
|
|
3
|
+
* Compatible with Zod, Valibot, ArkType, Effect Schema, and other validation libraries.
|
|
4
|
+
*
|
|
5
|
+
* @see https://standardschema.dev
|
|
6
|
+
*
|
|
7
|
+
* @example Using with Zod
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { z } from 'zod';
|
|
10
|
+
*
|
|
11
|
+
* const bodySchema = z.object({
|
|
12
|
+
* title: z.string().min(1),
|
|
13
|
+
* content: z.string()
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* app.post('/posts', async (ctx) => {
|
|
17
|
+
* const { title, content } = ctx.body;
|
|
18
|
+
* return ctx.json({ id: 1, title, content });
|
|
19
|
+
* }, {
|
|
20
|
+
* schema: { body: bodySchema }
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export interface StandardSchema<Input = unknown, Output = Input> {
|
|
25
|
+
readonly '~standard': {
|
|
26
|
+
readonly version: 1;
|
|
27
|
+
readonly vendor: string;
|
|
28
|
+
readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
|
|
29
|
+
readonly types?: {
|
|
30
|
+
readonly input: Input;
|
|
31
|
+
readonly output: Output;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Result of Standard Schema validation.
|
|
38
|
+
*/
|
|
39
|
+
export type StandardSchemaResult<Output> = StandardSchemaSuccessResult<Output> | StandardSchemaFailureResult;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Successful validation result.
|
|
43
|
+
*/
|
|
44
|
+
export interface StandardSchemaSuccessResult<Output> {
|
|
45
|
+
readonly value: Output;
|
|
46
|
+
readonly issues?: undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Failed validation result.
|
|
51
|
+
*/
|
|
52
|
+
export interface StandardSchemaFailureResult {
|
|
53
|
+
readonly value?: undefined;
|
|
54
|
+
readonly issues: ReadonlyArray<StandardSchemaIssue>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Validation issue details.
|
|
59
|
+
*/
|
|
60
|
+
export interface StandardSchemaIssue {
|
|
61
|
+
readonly message: string;
|
|
62
|
+
readonly path?: ReadonlyArray<PropertyKey | { key: PropertyKey }>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Infers the output type from a Standard Schema.
|
|
67
|
+
*/
|
|
68
|
+
export type InferOutput<T extends StandardSchema> = T extends StandardSchema<any, infer O> ? O : never;
|