@ecopages/core 0.2.0-beta.21 → 0.2.0-beta.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/core",
3
- "version": "0.2.0-beta.21",
3
+ "version": "0.2.0-beta.23",
4
4
  "description": "Core package for Ecopages",
5
5
  "keywords": [
6
6
  "ecopages",
@@ -17,7 +17,7 @@
17
17
  "directory": "packages/core"
18
18
  },
19
19
  "dependencies": {
20
- "@ecopages/file-system": "0.2.0-beta.21",
20
+ "@ecopages/file-system": "0.2.0-beta.23",
21
21
  "@ecopages/logger": "^0.2.3",
22
22
  "@ecopages/scripts-injector": "^0.1.5",
23
23
  "@oxc-project/runtime": "0.134.0",
@@ -27,7 +27,9 @@
27
27
  "ghtml": "^4.0.2",
28
28
  "oxc-parser": "^0.124.0",
29
29
  "rolldown": "^1.1.0",
30
- "ws": "^8.20.1"
30
+ "ws": "^8.20.1",
31
+ "@standard-schema/spec": "^1.1.0",
32
+ "@standard-schema/utils": "^0.3.0"
31
33
  },
32
34
  "exports": {
33
35
  ".": {
@@ -27,6 +27,7 @@ export declare abstract class SharedServerAdapter<TOptions extends ServerAdapter
27
27
  staticRoutes: StaticRoute[];
28
28
  hmrManager?: any;
29
29
  }): Promise<void>;
30
+ private ensureRouteRendererFactory;
30
31
  protected createSharedWatchRefreshCallback(options: {
31
32
  staticRoutes: StaticRoute[];
32
33
  hmrManager?: any;
@@ -29,9 +29,20 @@ class SharedServerAdapter extends AbstractServerAdapter {
29
29
  schemaValidator = new SchemaValidationService();
30
30
  hostOwnsDevClient = false;
31
31
  async initializeSharedRouteHandling(options) {
32
+ this.ensureRouteRendererFactory();
32
33
  await this.initSharedRouter();
33
34
  this.configureSharedResponseHandlers(options.staticRoutes, options.hmrManager);
34
35
  }
36
+ ensureRouteRendererFactory() {
37
+ if (this.routeRendererFactory) {
38
+ return;
39
+ }
40
+ this.routeRendererFactory = new RouteRendererFactory({
41
+ appConfig: this.appConfig,
42
+ rendererModules: this.appConfig.runtime?.rendererModuleContext,
43
+ runtimeOrigin: this.runtimeOrigin
44
+ });
45
+ }
35
46
  createSharedWatchRefreshCallback(options) {
36
47
  return async () => {
37
48
  try {
@@ -71,16 +82,10 @@ class SharedServerAdapter extends AbstractServerAdapter {
71
82
  await this.router.init();
72
83
  }
73
84
  createRouteRegistryPageModuleAdapter() {
74
- const serverModuleTranspiler = getAppServerModuleTranspiler(this.appConfig);
85
+ this.ensureRouteRendererFactory();
75
86
  return {
76
87
  loadPageModule: async (filePath) => {
77
- const module = await serverModuleTranspiler.importModule({
78
- filePath,
79
- outdir: path.join(resolveInternalExecutionDir(this.appConfig), ".server-route-modules"),
80
- externalPackages: true,
81
- transpileErrorMessage: (details) => `Error transpiling route module: ${details}`,
82
- noOutputMessage: (targetFilePath) => `No transpiled output generated for route module: ${targetFilePath}`
83
- });
88
+ const module = await this.routeRendererFactory.getPageRenderer(filePath).loadPageModule(filePath);
84
89
  const page = module.default;
85
90
  return {
86
91
  staticPaths: page?.staticPaths ?? module.getStaticPaths,
@@ -104,11 +109,7 @@ class SharedServerAdapter extends AbstractServerAdapter {
104
109
  * @param hmrManager - The runtime-specific Hot Module Replacement orchestrator (if watching).
105
110
  */
106
111
  configureSharedResponseHandlers(staticRoutes, hmrManager) {
107
- this.routeRendererFactory = new RouteRendererFactory({
108
- appConfig: this.appConfig,
109
- rendererModules: this.appConfig.runtime?.rendererModuleContext,
110
- runtimeOrigin: this.runtimeOrigin
111
- });
112
+ this.ensureRouteRendererFactory();
112
113
  const { fileSystemResponseMatcher, explicitStaticRouteMatcher } = this.createSharedResponseHandlerDependencies(staticRoutes);
113
114
  this.fileSystemResponseMatcher = fileSystemResponseMatcher;
114
115
  this.routeHandler = new ServerRouteHandler({
@@ -41,3 +41,9 @@ export declare function removeStaleHmrEntrypointOutput(outputPath: string, scope
41
41
  * fresher artifact than the edited source file.
42
42
  */
43
43
  export declare function isHmrOutputFresh(outputPath: string, sourcePath: string): boolean;
44
+ /**
45
+ * @remarks
46
+ * Missing output is treated as a benign rebuild race. This helper isolates the
47
+ * post-build case where a bundle exists but is still older than its source.
48
+ */
49
+ export declare function isHmrOutputOlderThanSource(outputPath: string, sourcePath: string): boolean;
@@ -43,10 +43,17 @@ function isHmrOutputFresh(outputPath, sourcePath) {
43
43
  const sourceMtimeMs = fs.statSync(sourcePath).mtimeMs;
44
44
  return outputMtimeMs >= sourceMtimeMs;
45
45
  }
46
+ function isHmrOutputOlderThanSource(outputPath, sourcePath) {
47
+ if (!fileSystem.exists(outputPath) || !fileSystem.exists(sourcePath)) {
48
+ return false;
49
+ }
50
+ return fs.statSync(outputPath).mtimeMs < fs.statSync(sourcePath).mtimeMs;
51
+ }
46
52
  export {
47
53
  encodeHmrDynamicSegments,
48
54
  isBrowserOnlyRegisteredScriptEntrypoint,
49
55
  isHmrOutputFresh,
56
+ isHmrOutputOlderThanSource,
50
57
  isRegisteredScriptEntrypoint,
51
58
  removeStaleHmrEntrypointOutput,
52
59
  resolveHmrEntrypointOutputPaths
@@ -6,7 +6,8 @@ import {
6
6
  removeStaleHmrEntrypointOutput,
7
7
  resolveHmrEntrypointOutputPaths,
8
8
  isRegisteredScriptEntrypoint,
9
- isHmrOutputFresh
9
+ isHmrOutputFresh,
10
+ isHmrOutputOlderThanSource
10
11
  } from "../hmr-entrypoint-output.js";
11
12
  class JsHmrStrategy extends HmrStrategy {
12
13
  type = HmrStrategyType.SCRIPT;
@@ -200,7 +201,11 @@ class JsHmrStrategy extends HmrStrategy {
200
201
  async processOutput(filepath, url, sourcePath) {
201
202
  try {
202
203
  if (sourcePath && !isHmrOutputFresh(filepath, sourcePath)) {
203
- appLogger.warn(`[JsHmrStrategy] Skipping broadcast for stale HMR output ${url}`);
204
+ if (isHmrOutputOlderThanSource(filepath, sourcePath)) {
205
+ appLogger.warn(
206
+ `[JsHmrStrategy] HMR output is older than source after rebuild; skipping broadcast for ${url}`
207
+ );
208
+ }
204
209
  return { success: false, requiresReload: false };
205
210
  }
206
211
  const code = await fileSystem.readFile(filepath);
package/src/index.d.ts CHANGED
@@ -4,3 +4,4 @@ export { eco } from './eco/eco.js';
4
4
  export { defineApiHandler, defineGroupHandler, type GroupHandler } from './adapters/shared/define-api-handler.js';
5
5
  export { createEcoBuildPluginFromSourceTransform, createVitePluginsFromAppSourceTransforms, getAppSourceTransforms, createVitePluginFromSourceTransform, normalizeTransformId, type EcoSourceTransform, type EcoSourceTransformResult, type EcoViteCompatiblePlugin, } from './plugins/source-transform.js';
6
6
  export { createEcoComponentMetaTransform } from './plugins/eco-component-meta-plugin.js';
7
+ export { SchemaError, validateStandardSchema } from './services/validation/validate-standard-schema.js';
package/src/index.js CHANGED
@@ -8,7 +8,9 @@ import {
8
8
  normalizeTransformId
9
9
  } from "./plugins/source-transform.js";
10
10
  import { createEcoComponentMetaTransform } from "./plugins/eco-component-meta-plugin.js";
11
+ import { SchemaError, validateStandardSchema } from "./services/validation/validate-standard-schema.js";
11
12
  export {
13
+ SchemaError,
12
14
  createEcoBuildPluginFromSourceTransform,
13
15
  createEcoComponentMetaTransform,
14
16
  createVitePluginFromSourceTransform,
@@ -17,5 +19,6 @@ export {
17
19
  defineGroupHandler,
18
20
  eco,
19
21
  getAppSourceTransforms,
20
- normalizeTransformId
22
+ normalizeTransformId,
23
+ validateStandardSchema
21
24
  };
@@ -1,5 +1,6 @@
1
1
  import type { EcoBuildPlugin } from '../build/build-types.js';
2
2
  import type { EcoPagesAppConfig, IClientBridge } from '../types/internal-types.js';
3
+ import { GENERATED_BASE_PATHS } from '../config/constants.js';
3
4
  import type { RuntimeCapabilityDeclaration } from './runtime-capability.js';
4
5
  export type { RuntimeCapabilityDeclaration, RuntimeCapabilityTag } from './runtime-capability.js';
5
6
  export type { EcoBuildLoader, EcoBuildOnLoadArgs, EcoBuildOnLoadResult, EcoBuildOnResolveArgs, EcoBuildOnResolveResult, EcoBuildPlugin, EcoBuildPluginBuilder, } from '../build/build-types.js';
@@ -7,6 +8,11 @@ export declare const PROCESSOR_ERRORS: {
7
8
  readonly CACHE_DIRECTORY_NOT_SET: "Cache directory not set in context";
8
9
  };
9
10
  export declare function mergeProcessorOptions<TDefaults, TOverrides>(defaults: TDefaults, overrides: TOverrides): TDefaults & TOverrides;
11
+ export declare function resolveGeneratedPath(type: keyof typeof GENERATED_BASE_PATHS, options: {
12
+ root: string;
13
+ module: string;
14
+ subPath?: string;
15
+ }): string;
10
16
  export interface ProcessorWatchContext {
11
17
  path: string;
12
18
  bridge: IClientBridge;
@@ -155,5 +155,6 @@ class Processor {
155
155
  export {
156
156
  PROCESSOR_ERRORS,
157
157
  Processor,
158
- mergeProcessorOptions
158
+ mergeProcessorOptions,
159
+ resolveGeneratedPath
159
160
  };
@@ -113,10 +113,7 @@ export declare class SchemaValidationService {
113
113
  validateRequest(source: ValidationSource, schemas: ValidationSchemas): Promise<ValidationResult<ValidatedData>>;
114
114
  /**
115
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
116
  */
117
+ private mapSchemaIssue;
121
118
  private validateWithSchema;
122
119
  }
@@ -1,3 +1,4 @@
1
+ import { SchemaError, validateStandardSchema } from "./validate-standard-schema.js";
1
2
  class SchemaValidationService {
2
3
  /**
3
4
  * Validates request data against provided schemas.
@@ -65,26 +66,24 @@ class SchemaValidationService {
65
66
  }
66
67
  /**
67
68
  * 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
69
  */
70
+ mapSchemaIssue(issue) {
71
+ return {
72
+ message: issue.message,
73
+ path: issue.path?.map((p) => typeof p === "object" && "key" in p ? p.key : p)
74
+ };
75
+ }
73
76
  async validateWithSchema(schema, data) {
74
77
  try {
75
- const resultOrPromise = schema["~standard"].validate(data);
76
- const result = resultOrPromise instanceof Promise ? await resultOrPromise : resultOrPromise;
77
- if (result.issues) {
78
+ const value = await validateStandardSchema(schema, data);
79
+ return { success: true, data: value };
80
+ } catch (error) {
81
+ if (error instanceof SchemaError) {
78
82
  return {
79
83
  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
+ errors: error.issues.map((issue) => this.mapSchemaIssue(issue))
84
85
  };
85
86
  }
86
- return { success: true, data: result.value };
87
- } catch (error) {
88
87
  return {
89
88
  success: false,
90
89
  errors: [
@@ -1,65 +1,12 @@
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
1
2
  /**
2
- * Standard Schema interface for universal validation.
3
- * Compatible with Zod, Valibot, ArkType, Effect Schema, and other validation libraries.
4
- *
3
+ * Ecopages aliases for the official Standard Schema V1 types.
5
4
  * @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
5
  */
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;
6
+ export type StandardSchema<Input = unknown, Output = Input> = StandardSchemaV1<Input, Output>;
7
+ export type StandardSchemaResult<Output> = StandardSchemaV1.Result<Output>;
8
+ export type StandardSchemaSuccessResult<Output> = StandardSchemaV1.SuccessResult<Output>;
9
+ export type StandardSchemaFailureResult = StandardSchemaV1.FailureResult;
10
+ export type StandardSchemaIssue = StandardSchemaV1.Issue;
11
+ export type InferOutput<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>;
12
+ export type { StandardSchemaV1 } from '@standard-schema/spec';
@@ -0,0 +1,7 @@
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
2
+ export { SchemaError } from '@standard-schema/utils';
3
+ /**
4
+ * Validates a value with any Standard Schema-compliant validator.
5
+ * Throws {@link SchemaError} when validation fails.
6
+ */
7
+ export declare function validateStandardSchema<T>(schema: StandardSchemaV1<unknown, T>, value: unknown): Promise<T>;
@@ -0,0 +1,14 @@
1
+ import { SchemaError } from "@standard-schema/utils";
2
+ import { SchemaError as SchemaError2 } from "@standard-schema/utils";
3
+ async function validateStandardSchema(schema, value) {
4
+ const resultOrPromise = schema["~standard"].validate(value);
5
+ const result = resultOrPromise instanceof Promise ? await resultOrPromise : resultOrPromise;
6
+ if (result.issues) {
7
+ throw new SchemaError(result.issues);
8
+ }
9
+ return result.value;
10
+ }
11
+ export {
12
+ SchemaError2 as SchemaError,
13
+ validateStandardSchema
14
+ };
@@ -89,8 +89,8 @@ export interface EcopagesWebSocketHandler<TContext = unknown, TParams extends Re
89
89
  onClose?(socket: EcopagesSocket<TContext, TParams>, event: WebSocketCloseInfo): void | Promise<void>;
90
90
  onError?(socket: EcopagesSocket<TContext, TParams>, error: unknown): void | Promise<void>;
91
91
  }
92
- import type { StandardSchema, StandardSchemaResult, StandardSchemaSuccessResult, StandardSchemaFailureResult, StandardSchemaIssue, InferOutput } from '../services/validation/standard-schema.types.js';
93
- export type { StandardSchema, StandardSchemaResult, StandardSchemaSuccessResult, StandardSchemaFailureResult, StandardSchemaIssue, InferOutput, ForeignChildRuntime, };
92
+ import type { StandardSchema, StandardSchemaResult, StandardSchemaSuccessResult, StandardSchemaFailureResult, StandardSchemaIssue, InferOutput, StandardSchemaV1 } from '../services/validation/standard-schema.types.js';
93
+ export type { StandardSchema, StandardSchemaResult, StandardSchemaSuccessResult, StandardSchemaFailureResult, StandardSchemaIssue, InferOutput, StandardSchemaV1, ForeignChildRuntime, };
94
94
  export type InteractionEventsString = ScriptsInjectorInteractionEventsString;
95
95
  export type DependencyLazyTrigger = {
96
96
  'on:idle': true;