veryfront 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/modules/react-loader/ssr-module-loader/cache/memory.d.ts.map +1 -1
  3. package/esm/src/modules/react-loader/ssr-module-loader/cache/memory.js +2 -1
  4. package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
  5. package/esm/src/modules/react-loader/ssr-module-loader/loader.js +2 -1
  6. package/esm/src/modules/react-loader/ssr-module-loader/tmp-paths.d.ts.map +1 -1
  7. package/esm/src/modules/react-loader/ssr-module-loader/tmp-paths.js +3 -2
  8. package/esm/src/modules/react-loader/ssr-module-loader/vf-module-resolver.d.ts.map +1 -1
  9. package/esm/src/modules/react-loader/ssr-module-loader/vf-module-resolver.js +2 -1
  10. package/esm/src/platform/adapters/fs/veryfront/file-list-index.d.ts +1 -0
  11. package/esm/src/platform/adapters/fs/veryfront/file-list-index.d.ts.map +1 -1
  12. package/esm/src/platform/adapters/fs/veryfront/file-list-index.js +28 -1
  13. package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts +2 -0
  14. package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts.map +1 -1
  15. package/esm/src/platform/adapters/fs/veryfront/websocket-manager.js +44 -11
  16. package/esm/src/routing/api/route-executor.d.ts.map +1 -1
  17. package/esm/src/routing/api/route-executor.js +28 -6
  18. package/esm/src/server/context/request-context.d.ts.map +1 -1
  19. package/esm/src/server/context/request-context.js +2 -1
  20. package/esm/src/server/dev-server/server.d.ts +1 -0
  21. package/esm/src/server/dev-server/server.d.ts.map +1 -1
  22. package/esm/src/server/dev-server/server.js +23 -1
  23. package/esm/src/server/dev-server/types.d.ts +1 -0
  24. package/esm/src/server/dev-server/types.d.ts.map +1 -1
  25. package/esm/src/server/handlers/preview/hmr.handler.d.ts +2 -0
  26. package/esm/src/server/handlers/preview/hmr.handler.d.ts.map +1 -1
  27. package/esm/src/server/handlers/preview/hmr.handler.js +21 -2
  28. package/esm/src/server/index.d.ts +3 -1
  29. package/esm/src/server/index.d.ts.map +1 -1
  30. package/esm/src/server/index.js +9 -3
  31. package/esm/src/server/utils/domain-parser.d.ts +8 -0
  32. package/esm/src/server/utils/domain-parser.d.ts.map +1 -1
  33. package/esm/src/server/utils/domain-parser.js +45 -0
  34. package/esm/src/utils/constants/security.d.ts +2 -2
  35. package/esm/src/utils/constants/security.d.ts.map +1 -1
  36. package/esm/src/utils/constants/security.js +3 -3
  37. package/package.json +1 -1
  38. package/src/deno.js +1 -1
  39. package/src/src/modules/react-loader/ssr-module-loader/cache/memory.ts +2 -1
  40. package/src/src/modules/react-loader/ssr-module-loader/loader.ts +2 -1
  41. package/src/src/modules/react-loader/ssr-module-loader/tmp-paths.ts +3 -2
  42. package/src/src/modules/react-loader/ssr-module-loader/vf-module-resolver.ts +2 -1
  43. package/src/src/platform/adapters/fs/veryfront/file-list-index.ts +30 -1
  44. package/src/src/platform/adapters/fs/veryfront/websocket-manager.ts +45 -10
  45. package/src/src/routing/api/route-executor.ts +34 -7
  46. package/src/src/server/context/request-context.ts +2 -1
  47. package/src/src/server/dev-server/server.ts +28 -1
  48. package/src/src/server/dev-server/types.ts +1 -0
  49. package/src/src/server/handlers/preview/hmr.handler.ts +28 -2
  50. package/src/src/server/index.ts +16 -2
  51. package/src/src/server/utils/domain-parser.ts +55 -0
  52. package/src/src/utils/constants/security.ts +3 -3
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "nodeModulesDir": "auto",
5
5
  "exclude": [
6
6
  "npm/",
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../../../src/src/modules/react-loader/ssr-module-loader/cache/memory.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAO5D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAOnE,eAAO,MAAM,iBAAiB,oCAE5B,CAAC;AAEH,eAAO,MAAM,uBAAuB,oCAElC,CAAC;AAEH,eAAO,MAAM,gBAAgB,4BAAmC,CAAC;AAEjE,eAAO,MAAM,aAAa,0BAExB,CAAC;AAEH,eAAO,MAAM,gBAAgB,4BAAmC,CAAC;AAGjE,wBAAgB,qBAAqB,IAAI,SAAS,CAKjD;AAsBD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAW/D;AAKD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAU5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CAOA;AAiDD,wBAAgB,mBAAmB,IAAI,IAAI,CAqB1C;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAiDrE"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../../../src/src/modules/react-loader/ssr-module-loader/cache/memory.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAO5D,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAOnE,eAAO,MAAM,iBAAiB,oCAE5B,CAAC;AAEH,eAAO,MAAM,uBAAuB,oCAElC,CAAC;AAEH,eAAO,MAAM,gBAAgB,4BAAmC,CAAC;AAEjE,eAAO,MAAM,aAAa,0BAExB,CAAC;AAEH,eAAO,MAAM,gBAAgB,4BAAmC,CAAC;AAGjE,wBAAgB,qBAAqB,IAAI,SAAS,CAKjD;AAsBD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAW/D;AAKD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAU5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CAOA;AAiDD,wBAAgB,mBAAmB,IAAI,IAAI,CAqB1C;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAiDrE"}
@@ -15,6 +15,7 @@
15
15
  import * as dntShim from "../../../../../_dnt.shims.js";
16
16
  import { registerCache } from "../../../../utils/memory/index.js";
17
17
  import { isKeyForProject, registerMapCache } from "../../../../cache/keys.js";
18
+ import { hashCodeHex } from "../../../../utils/hash-utils.js";
18
19
  import { rendererLogger } from "../../../../utils/index.js";
19
20
  import { LRUCache } from "../../../../utils/lru-wrapper.js";
20
21
  import { getMaxConcurrentTransforms, getTransformPerProjectLimit, resetCachedTransformLimits, SSR_TMP_DIRS_MAX_ENTRIES, } from "../constants.js";
@@ -179,7 +180,7 @@ export function clearSSRModuleCache() {
179
180
  }
180
181
  export function clearSSRModuleCacheForProject(projectId) {
181
182
  let cleared = 0;
182
- const encodedProjectId = encodeURIComponent(projectId);
183
+ const encodedProjectId = hashCodeHex(projectId);
183
184
  for (const key of globalModuleCache.keys()) {
184
185
  if (!isKeyForProject(key, projectId))
185
186
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAgCpC,OAAO,KAAK,EAAoB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAwB3E;;;;;GAKG;AACH,qBAAa,eAAe;IAKd,OAAO,CAAC,OAAO;IAJ3B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,YAAY,CAAyB;gBAEzB,OAAO,EAAE,sBAAsB;IAWnD,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,4BAA4B;YAetB,qBAAqB;YAuCrB,0BAA0B;IA2FxC,UAAU,CACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YA+C1C,2BAA2B;IAYzC,OAAO,CAAC,yBAAyB;YAiBnB,2BAA2B;CAqU1C"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAiCpC,OAAO,KAAK,EAAoB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAwB3E;;;;;GAKG;AACH,qBAAa,eAAe;IAKd,OAAO,CAAC,OAAO;IAJ3B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,YAAY,CAAyB;gBAEzB,OAAO,EAAE,sBAAsB;IAWnD,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,4BAA4B;YAetB,qBAAqB;YAuCrB,0BAA0B;IA2FxC,UAAU,CACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YA+C1C,2BAA2B;IAYzC,OAAO,CAAC,yBAAyB;YAiBnB,2BAA2B;CAqU1C"}
@@ -11,6 +11,7 @@ import { parseLocalImports, } from "../../../transforms/esm/import-parser.js";
11
11
  import { createFileSystem } from "../../../platform/compat/fs.js";
12
12
  import { verifyCacheFileExists, writeCacheFile } from "../../../utils/cache-file-ops.js";
13
13
  import { createError, toError } from "../../../errors/veryfront-error.js";
14
+ import { hashCodeHex } from "../../../utils/hash-utils.js";
14
15
  import { rendererLogger } from "../../../utils/index.js";
15
16
  import { withSpan } from "../../../observability/tracing/otlp-setup.js";
16
17
  import { SpanNames } from "../../../observability/tracing/span-names.js";
@@ -253,7 +254,7 @@ export class SSRModuleLoader {
253
254
  }
254
255
  if (this.options.projectId && this.options.contentSourceId) {
255
256
  const baseCacheDir = getMdxEsmCacheDir();
256
- const projectKey = encodeURIComponent(this.options.projectId);
257
+ const projectKey = hashCodeHex(this.options.projectId);
257
258
  const sourceKey = this.options.contentSourceId;
258
259
  const mdxCacheDir = join(baseCacheDir, projectKey, sourceKey);
259
260
  const mdxCacheResult = await lookupMdxEsmCache(filePath, mdxCacheDir, this.options.projectDir, contentHash);
@@ -1 +1 @@
1
- {"version":3,"file":"tmp-paths.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/tmp-paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB,MAAM,CAGR;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB,MAAM,CAGR;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAYR"}
1
+ {"version":3,"file":"tmp-paths.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/tmp-paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB,MAAM,CAGR;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GACtB,MAAM,CAGR;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAYR"}
@@ -2,12 +2,13 @@
2
2
  * Temp directory and temp file path helpers for SSR module loader cache.
3
3
  */
4
4
  import { join } from "../../../platform/compat/path/index.js";
5
+ import { hashCodeHex } from "../../../utils/hash-utils.js";
5
6
  export function getTmpDirCacheKey(baseCacheDir, projectId, contentSourceId) {
6
- const projectKey = encodeURIComponent(projectId);
7
+ const projectKey = hashCodeHex(projectId);
7
8
  return `${baseCacheDir}|${projectKey}|${contentSourceId}`;
8
9
  }
9
10
  export function buildTmpDirPath(baseCacheDir, projectId, contentSourceId) {
10
- const projectKey = encodeURIComponent(projectId);
11
+ const projectKey = hashCodeHex(projectId);
11
12
  return join(baseCacheDir, projectKey, contentSourceId);
12
13
  }
13
14
  export function buildTempModulePath(tmpDir, filePath, projectDir, version, contentHash) {
@@ -1 +1 @@
1
- {"version":3,"file":"vf-module-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/vf-module-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAWzE,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,6BAA6B;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAelE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
1
+ {"version":3,"file":"vf-module-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/modules/react-loader/ssr-module-loader/vf-module-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAWzE,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,6BAA6B;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAelE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
@@ -4,6 +4,7 @@
4
4
  * Extracts and resolves /_vf_modules/* imports into file:// cache paths.
5
5
  */
6
6
  import { join } from "../../../platform/compat/path/index.js";
7
+ import { hashCodeHex } from "../../../utils/hash-utils.js";
7
8
  import { rendererLogger } from "../../../utils/index.js";
8
9
  import { getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
9
10
  import { createModuleFetcherContext, fetchAndCacheModule, } from "../../../transforms/mdx/esm-module-loader/module-fetcher/index.js";
@@ -40,7 +41,7 @@ export async function resolveVfModuleImports(code, options) {
40
41
  paths: imports.map((i) => i.path).slice(0, 5),
41
42
  });
42
43
  const baseCacheDir = getMdxEsmCacheDir();
43
- const projectKey = encodeURIComponent(options.projectId);
44
+ const projectKey = hashCodeHex(options.projectId);
44
45
  const esmCacheDir = join(baseCacheDir, projectKey, options.contentSourceId);
45
46
  const fetcherContext = createModuleFetcherContext(esmCacheDir, options.adapter, options.projectDir, options.projectId, {
46
47
  reactVersion: options.reactVersion,
@@ -6,6 +6,7 @@ export declare class FileListIndex {
6
6
  private readonly getFileListCache?;
7
7
  private index;
8
8
  private indexKey;
9
+ private indexBuiltAt;
9
10
  private readyPromise;
10
11
  constructor(getFileListCache?: (() => Promise<Array<FileListCacheEntry> | undefined>) | undefined);
11
12
  setReadyPromise(promise: Promise<void>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"file-list-index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/file-list-index.ts"],"names":[],"mappings":"AAIA,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD,qBAAa,aAAa;IAMtB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IALpC,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,YAAY,CAA8B;gBAG/B,gBAAgB,CAAC,GAAE,MAAM,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC,aAAA;IAG1F,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI7C,KAAK,IAAI,IAAI;IASP,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;YAkCnD,UAAU;CAiDzB"}
1
+ {"version":3,"file":"file-list-index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/file-list-index.ts"],"names":[],"mappings":"AAIA,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAeD,qBAAa,aAAa;IAOtB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IANpC,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAA8B;gBAG/B,gBAAgB,CAAC,GAAE,MAAM,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC,aAAA;IAG1F,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI7C,KAAK,IAAI,IAAI;IAUP,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;YAkCnD,UAAU;CA0EzB"}
@@ -9,10 +9,12 @@ function hashPreview(content) {
9
9
  function previewText(content, max = 80) {
10
10
  return content.length > max ? `${content.slice(0, max)}...` : content;
11
11
  }
12
+ const INDEX_STALENESS_LIMIT_MS = 5 * 60 * 1000; // 5 minutes
12
13
  export class FileListIndex {
13
14
  getFileListCache;
14
15
  index = null;
15
16
  indexKey = null;
17
+ indexBuiltAt = 0;
16
18
  readyPromise = null;
17
19
  constructor(getFileListCache) {
18
20
  this.getFileListCache = getFileListCache;
@@ -26,6 +28,7 @@ export class FileListIndex {
26
28
  const size = this.index.size;
27
29
  this.index = null;
28
30
  this.indexKey = null;
31
+ this.indexBuiltAt = 0;
29
32
  logger.debug("Cleared file list index", { entriesCleared: size });
30
33
  }
31
34
  async lookup(normalizedPath) {
@@ -65,6 +68,27 @@ export class FileListIndex {
65
68
  }
66
69
  const fileList = await this.getFileListCache();
67
70
  if (!fileList) {
71
+ // Cache entry expired or unavailable. If we already have a built index from a
72
+ // previous successful cache read, keep using it rather than forcing network fetches.
73
+ // The index stays valid until explicitly cleared via clear() (triggered by WebSocket pokes)
74
+ // or until INDEX_STALENESS_LIMIT_MS elapses (safety net for missed pokes).
75
+ if (this.index) {
76
+ const age = Date.now() - this.indexBuiltAt;
77
+ if (age < INDEX_STALENESS_LIMIT_MS) {
78
+ logger.debug("getOrBuildFileListIndex: cache expired, using existing in-memory index", {
79
+ indexSize: this.index.size,
80
+ indexAgeMs: age,
81
+ });
82
+ return this.index;
83
+ }
84
+ logger.debug("getOrBuildFileListIndex: in-memory index too stale, discarding", {
85
+ indexSize: this.index.size,
86
+ indexAgeMs: age,
87
+ staleLimitMs: INDEX_STALENESS_LIMIT_MS,
88
+ });
89
+ this.index = null;
90
+ this.indexKey = null;
91
+ }
68
92
  logger.debug("[ReadOperations] getOrBuildFileListIndex: getFileListCache returned null/undefined");
69
93
  return null;
70
94
  }
@@ -77,8 +101,10 @@ export class FileListIndex {
77
101
  sampleContentPreview: cacheCheckSample?.content?.slice(0, 200)?.replace(/\n/g, "\\n"),
78
102
  });
79
103
  const indexKey = `${fileList.length}:${fileList[0]?.path ?? ""}:${fileList[fileList.length - 1]?.path ?? ""}`;
80
- if (this.index && this.indexKey === indexKey)
104
+ if (this.index && this.indexKey === indexKey) {
105
+ this.indexBuiltAt = Date.now();
81
106
  return this.index;
107
+ }
82
108
  const index = new Map();
83
109
  for (const file of fileList) {
84
110
  if (file.content)
@@ -86,6 +112,7 @@ export class FileListIndex {
86
112
  }
87
113
  this.index = index;
88
114
  this.indexKey = indexKey;
115
+ this.indexBuiltAt = Date.now();
89
116
  const sampleFile = fileList.find((f) => /welcome/i.test(f.path));
90
117
  const sampleContent = sampleFile?.content;
91
118
  logger.debug("Built file list index", {
@@ -28,6 +28,7 @@ export declare class WebSocketManager {
28
28
  private selectiveInvalidationTimer;
29
29
  private pendingChangedPaths;
30
30
  private wsConnectionId;
31
+ private wsConsecutiveFailures;
31
32
  private pokeMetrics;
32
33
  constructor(deps: WebSocketDeps);
33
34
  getPokeMetrics(): {
@@ -37,6 +38,7 @@ export declare class WebSocketManager {
37
38
  connectionId: string | null;
38
39
  };
39
40
  connect(projectId: string): void;
41
+ private getReconnectDelay;
40
42
  dispose(): void;
41
43
  private handlePokeMessage;
42
44
  private clearPersistentCacheForPublish;
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/websocket-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAoB/F,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,qBAAqB,EAAE,qBAAqB,CAAC;IAE7C,iBAAiB,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACvD,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,aAAa,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACxC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,qBAAa,gBAAgB;IAgBf,OAAO,CAAC,QAAQ,CAAC,IAAI;IAfjC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,iBAAiB,CAAsD;IAC/E,OAAO,CAAC,0BAA0B,CAAsD;IACxF,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,WAAW,CAIjB;gBAE2B,IAAI,EAAE,aAAa;IAEhD,cAAc,IAAI;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B;IAID,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAsDhC,OAAO,IAAI,IAAI;IAwBf,OAAO,CAAC,iBAAiB;IAkJzB,OAAO,CAAC,8BAA8B;IA0GtC,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,6BAA6B;YAiBvB,4BAA4B;YA2H5B,mBAAmB;IAmIjC,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,WAAW;CAyBpB"}
1
+ {"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/websocket-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAsB/F,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,qBAAqB,EAAE,qBAAqB,CAAC;IAE7C,iBAAiB,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACvD,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,aAAa,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACxC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,KAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB;AAED,qBAAa,gBAAgB;IAiBf,OAAO,CAAC,QAAQ,CAAC,IAAI;IAhBjC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,gBAAgB,CAAuD;IAC/E,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,iBAAiB,CAAsD;IAC/E,OAAO,CAAC,0BAA0B,CAAsD;IACxF,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,WAAW,CAIjB;gBAE2B,IAAI,EAAE,aAAa;IAEhD,cAAc,IAAI;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B;IAID,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA0EhC,OAAO,CAAC,iBAAiB;IAMzB,OAAO,IAAI,IAAI;IAwBf,OAAO,CAAC,iBAAiB;IAkJzB,OAAO,CAAC,8BAA8B;IA0GtC,OAAO,CAAC,oBAAoB;IAa5B,OAAO,CAAC,6BAA6B;YAiBvB,4BAA4B;YA2H5B,mBAAmB;IAmIjC,OAAO,CAAC,cAAc;IA4BtB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,WAAW;CAyBpB"}
@@ -5,6 +5,8 @@ import { addPendingInvalidation, getPendingInvalidationsCount, removePendingInva
5
5
  const logger = baseLogger.component("web-socket-manager");
6
6
  const INVALIDATION_DEBOUNCE_MS = 100;
7
7
  const WS_RECONNECT_DELAY_MS = 5000;
8
+ const WS_RECONNECT_MAX_DELAY_MS = 120000;
9
+ const WS_RECONNECT_MAX_FAILURES = 10;
8
10
  const WS_HEARTBEAT_INTERVAL_MS = 60000;
9
11
  const WS_HEARTBEAT_TIMEOUT_MS = 300000;
10
12
  export class WebSocketManager {
@@ -17,6 +19,7 @@ export class WebSocketManager {
17
19
  selectiveInvalidationTimer = null;
18
20
  pendingChangedPaths = new Set();
19
21
  wsConnectionId = null;
22
+ wsConsecutiveFailures = 0;
20
23
  pokeMetrics = {
21
24
  received: 0,
22
25
  invalidationsTriggered: 0,
@@ -30,6 +33,15 @@ export class WebSocketManager {
30
33
  }
31
34
  connect(projectId) {
32
35
  this.cleanupTimers();
36
+ if (this.wsConsecutiveFailures >= WS_RECONNECT_MAX_FAILURES) {
37
+ logger.warn("WebSocket reconnect failure cap reached, resetting failure counter", {
38
+ consecutiveFailures: this.wsConsecutiveFailures,
39
+ maxFailures: WS_RECONNECT_MAX_FAILURES,
40
+ cappedDelayMs: WS_RECONNECT_MAX_DELAY_MS,
41
+ projectId,
42
+ });
43
+ this.wsConsecutiveFailures = 0;
44
+ }
33
45
  const wsUrl = this.deps.apiBaseUrl
34
46
  .replace(/^http:/, "ws:")
35
47
  .replace(/^https:/, "wss:")
@@ -37,11 +49,13 @@ export class WebSocketManager {
37
49
  const url = `${wsUrl}/ws/${projectId}/events?token=${this.deps.apiToken}`;
38
50
  logger.debug("Connecting to WebSocket", {
39
51
  url: url.replace(this.deps.apiToken, "***"),
52
+ consecutiveFailures: this.wsConsecutiveFailures,
40
53
  });
41
54
  try {
42
55
  this.ws = new WebSocket(url);
43
56
  this.wsConnectionId = dntShim.crypto.randomUUID().slice(0, 8);
44
57
  this.ws.onopen = () => {
58
+ this.wsConsecutiveFailures = 0;
45
59
  logger.debug("WebSocket connected to events channel", {
46
60
  projectId,
47
61
  connectionId: this.wsConnectionId,
@@ -57,24 +71,37 @@ export class WebSocketManager {
57
71
  this.handlePokeMessage(event);
58
72
  };
59
73
  this.ws.onclose = () => {
74
+ this.wsConsecutiveFailures++;
75
+ const delay = this.getReconnectDelay();
60
76
  logger.debug("WebSocket closed, reconnecting", {
61
- delayMs: WS_RECONNECT_DELAY_MS,
77
+ delayMs: delay,
62
78
  connectionId: this.wsConnectionId,
63
79
  totalPokesReceived: this.pokeMetrics.received,
80
+ consecutiveFailures: this.wsConsecutiveFailures,
64
81
  });
65
82
  this.wsConnectionId = null;
66
83
  this.cleanupTimers();
67
- this.wsReconnectTimer = dntShim.setTimeout(() => this.connect(projectId), WS_RECONNECT_DELAY_MS);
84
+ this.wsReconnectTimer = dntShim.setTimeout(() => this.connect(projectId), delay);
68
85
  };
69
86
  this.ws.onerror = (error) => {
70
87
  logger.warn("WebSocket error", { error });
71
88
  };
72
89
  }
73
90
  catch (error) {
74
- logger.warn("Failed to connect WebSocket", { error });
75
- this.wsReconnectTimer = dntShim.setTimeout(() => this.connect(projectId), WS_RECONNECT_DELAY_MS);
91
+ this.wsConsecutiveFailures++;
92
+ const delay = this.getReconnectDelay();
93
+ logger.warn("Failed to connect WebSocket", {
94
+ error,
95
+ consecutiveFailures: this.wsConsecutiveFailures,
96
+ });
97
+ this.wsReconnectTimer = dntShim.setTimeout(() => this.connect(projectId), delay);
76
98
  }
77
99
  }
100
+ getReconnectDelay() {
101
+ // Exponential backoff: 5s, 10s, 20s, 40s, 80s, capped at 120s
102
+ const delay = WS_RECONNECT_DELAY_MS * Math.pow(2, this.wsConsecutiveFailures - 1);
103
+ return Math.min(delay, WS_RECONNECT_MAX_DELAY_MS);
104
+ }
78
105
  dispose() {
79
106
  this.cleanupTimers();
80
107
  if (this.invalidationTimer) {
@@ -529,13 +556,19 @@ export class WebSocketManager {
529
556
  logger.warn("WebSocket heartbeat timeout, reconnecting", {
530
557
  timeSinceLastPong,
531
558
  });
532
- try {
533
- this.ws?.close();
534
- }
535
- catch (error) {
536
- logger.error("WebSocket close failed during heartbeat timeout", {
537
- error: error instanceof Error ? error.message : String(error),
538
- });
559
+ // Detach onclose before closing to prevent double-reconnect:
560
+ // ws.close() triggers onclose asynchronously, which would increment
561
+ // the failure counter and schedule a separate reconnect timer.
562
+ if (this.ws) {
563
+ this.ws.onclose = null;
564
+ try {
565
+ this.ws.close();
566
+ }
567
+ catch (error) {
568
+ logger.error("WebSocket close failed during heartbeat timeout", {
569
+ error: error instanceof Error ? error.message : String(error),
570
+ });
571
+ }
539
572
  }
540
573
  this.cleanupTimers();
541
574
  this.connect(projectId);
@@ -1 +1 @@
1
- {"version":3,"file":"route-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/route-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,0BAA0B,CAAC;AA4ElC,wBAAgB,eAAe,CAC7B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA6B3B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAwB3B"}
1
+ {"version":3,"file":"route-executor.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/route-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,0BAA0B,CAAC;AA0GlC,wBAAgB,eAAe,CAC7B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA4B3B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAsB3B"}
@@ -44,9 +44,34 @@ function createProjectScopedFs(fs, projectDir) {
44
44
  resolveFile: fs.resolveFile ? (path) => fs.resolveFile(resolvePath(path)) : undefined,
45
45
  };
46
46
  }
47
+ /**
48
+ * Check if an object is a cross-context Response (e.g. Deno native Response
49
+ * when this code runs in the npm package context with a different constructor).
50
+ */
51
+ function isCrossContextResponse(value) {
52
+ if (value == null || typeof value !== "object")
53
+ return false;
54
+ const r = value;
55
+ return (typeof r.status === "number" &&
56
+ typeof r.headers === "object" &&
57
+ r.headers !== null &&
58
+ typeof r.headers.get === "function" &&
59
+ typeof r.text === "function" &&
60
+ typeof r.arrayBuffer === "function");
61
+ }
47
62
  function validateResponse(response) {
48
63
  if (response instanceof dntShim.Response)
49
- return;
64
+ return response;
65
+ // Normalize cross-context Response objects into a real Response so downstream
66
+ // code (toHeadResponse, applyCORSHeaders, withHeaders) always receives a
67
+ // genuine instance with correct body, headers, and status.
68
+ if (isCrossContextResponse(response)) {
69
+ return new dntShim.Response(response.body, {
70
+ status: response.status,
71
+ statusText: response.statusText,
72
+ headers: response.headers,
73
+ });
74
+ }
50
75
  throw toError(createError({
51
76
  type: "api",
52
77
  message: "API handler must return a Response",
@@ -69,8 +94,7 @@ export function executeAppRoute(handler, request, match, pathname, adapter) {
69
94
  return createAppRouteMethodNotAllowed(handlerModule);
70
95
  try {
71
96
  const appContext = { params: normalizeParams(match.params) };
72
- const response = await resolvedFn(request, appContext);
73
- validateResponse(response);
97
+ const response = validateResponse(await resolvedFn(request, appContext));
74
98
  return method === "HEAD" ? toHeadResponse(response) : response;
75
99
  }
76
100
  catch (error) {
@@ -88,9 +112,7 @@ export function executePagesRoute(handler, request, match, pathname, adapter, pr
88
112
  try {
89
113
  const fs = projectDir ? createProjectScopedFs(adapter.fs, projectDir) : adapter.fs;
90
114
  const ctx = createContext(request, match, fs);
91
- const response = await methodHandler(ctx);
92
- validateResponse(response);
93
- return response;
115
+ return validateResponse(await methodHandler(ctx));
94
116
  }
95
117
  catch (error) {
96
118
  return handleAPIError(error, pathname, adapter);
@@ -1 +1 @@
1
- {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;CAChC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,cAAc,CAuBzE;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,cAAc,CAAC,EAAE,OAAO,GACvB,MAAM,GAAG,YAAY,GAAG,WAAW,CAIrC;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAExF;AAED,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAG/F"}
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/src/server/context/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAIlD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;CAChC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,cAAc,CAwBzE;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,EACnB,cAAc,CAAC,EAAE,OAAO,GACvB,MAAM,GAAG,YAAY,GAAG,WAAW,CAIrC;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAExF;AAED,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAG/F"}
@@ -9,7 +9,8 @@ export function createRequestContext(req) {
9
9
  const effectiveHost = forwardedHost ?? hostHeader ?? hostname;
10
10
  const parsed = parseProjectDomain(effectiveHost);
11
11
  const xEnvironment = req.headers.get("x-environment");
12
- const mode = effectiveHost.includes(".preview.") ||
12
+ const mode = parsed.environment === "preview" ||
13
+ effectiveHost.includes(".preview.") ||
13
14
  xEnvironment === "preview"
14
15
  ? "preview"
15
16
  : "production";
@@ -17,6 +17,7 @@ export declare class DevServer {
17
17
  private _isReady;
18
18
  private reloadUnsubscribe?;
19
19
  private invalidateUnsubscribe?;
20
+ private releaseExternalBroadcastSource?;
20
21
  constructor(options: DevServerOptions);
21
22
  private isDebug;
22
23
  private logRSCStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAYlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAkCvD,qBAAa,SAAS;IAgBR,OAAO,CAAC,OAAO;IAf3B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,iBAAiB,CAAC,CAAa;IACvC,OAAO,CAAC,qBAAqB,CAAC,CAAa;gBAEvB,OAAO,EAAE,gBAAgB;IAQ7C,OAAO,CAAC,OAAO;YAID,YAAY;IAWpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA8J5B,sEAAsE;IACtE,IAAI,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAGjE;IAED,OAAO,CAAC,oBAAoB;YAcd,cAAc;YAiBd,yBAAyB;YAoBzB,uBAAuB;YA4BvB,wBAAwB;IAkBtC,OAAO,CAAC,kBAAkB;IAuBpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAarB,iBAAiB;IAoC/B,qBAAqB,IAAI,UAAU,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI;IAIlE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA4B5B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAclD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAkCvD,qBAAa,SAAS;IAiBR,OAAO,CAAC,OAAO;IAhB3B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,CAAsD;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,iBAAiB,CAAC,CAAa;IACvC,OAAO,CAAC,qBAAqB,CAAC,CAAa;IAC3C,OAAO,CAAC,8BAA8B,CAAC,CAAa;gBAEhC,OAAO,EAAE,gBAAgB;IAQ7C,OAAO,CAAC,OAAO;YAID,YAAY;IAWpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqL5B,sEAAsE;IACtE,IAAI,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAGjE;IAED,OAAO,CAAC,oBAAoB;YAcd,cAAc;YAiBd,yBAAyB;YAoBzB,uBAAuB;YA4BvB,wBAAwB;IAkBtC,OAAO,CAAC,kBAAkB;IAuBpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAarB,iBAAiB;IAoC/B,qBAAqB,IAAI,UAAU,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI;IAIlE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA6B5B"}
@@ -7,6 +7,8 @@ import { ComponentRegistry } from "../../modules/component-registry/index.js";
7
7
  import { MiddlewarePipeline } from "../../middleware/core/pipeline/index.js";
8
8
  import { bootstrapDev } from "../bootstrap.js";
9
9
  import { ReloadNotifier } from "../reload-notifier.js";
10
+ import { broadcastUpdate } from "../handlers/preview/hmr-message-router.js";
11
+ import { HMRHandler } from "../handlers/preview/hmr.handler.js";
10
12
  import { RequestHandler } from "./request-handler.js";
11
13
  import { setupMiddleware } from "./middleware.js";
12
14
  import { RouteDiscovery } from "./route-discovery.js";
@@ -50,6 +52,7 @@ export class DevServer {
50
52
  _isReady = false;
51
53
  reloadUnsubscribe;
52
54
  invalidateUnsubscribe;
55
+ releaseExternalBroadcastSource;
53
56
  constructor(options) {
54
57
  this.options = options;
55
58
  this.ready = new Promise((resolve) => {
@@ -98,6 +101,9 @@ export class DevServer {
98
101
  hmr: this.options.enableHMR,
99
102
  fastRefresh: this.options.enableFastRefresh,
100
103
  });
104
+ if (this.options.hmrPort !== undefined) {
105
+ devServerLog.warn("`hmrPort` is deprecated and ignored. HMR now uses /_ws on the main dev server port.", { hmrPort: this.options.hmrPort, serverPort: this.options.port });
106
+ }
101
107
  // Set VERYFRONT_DEV_PORT for ESM module loader HTTP fallback
102
108
  // This ensures the correct port is used when fetching modules via localhost
103
109
  setEnv("VERYFRONT_DEV_PORT", String(this.options.port));
@@ -125,7 +131,22 @@ export class DevServer {
125
131
  devServerLog.debug("INVALIDATE callback triggered - clearing runtime handler");
126
132
  this.requestHandler?.invalidateRuntimeHandler();
127
133
  });
128
- devServerLog.debug("ReloadNotifier invalidation subscription registered");
134
+ // Subscribe to debounced reload for broadcasting updates to connected HMR clients.
135
+ // This subscription must be eagerly registered here rather than lazily inside
136
+ // HMRHandler.initialize(), because HMRHandler.initialize() only runs when the
137
+ // first /_ws WebSocket request arrives. If that connection fails or hasn't
138
+ // happened yet, file changes are silently lost.
139
+ this.releaseExternalBroadcastSource = HMRHandler.registerExternalBroadcastSource();
140
+ this.reloadUnsubscribe = ReloadNotifier.subscribe((changedPaths, project) => {
141
+ hmrLog.debug("RELOAD callback triggered - broadcasting to HMR clients", {
142
+ changedPaths,
143
+ projectSlug: project?.projectSlug,
144
+ });
145
+ // Broadcast without projectSlug filter so that connectHMR() clients
146
+ // (which are registered without a projectSlug) also receive updates.
147
+ broadcastUpdate(changedPaths);
148
+ });
149
+ hmrLog.debug("ReloadNotifier subscriptions registered (invalidate + reload broadcast)");
129
150
  }
130
151
  const moduleServerUrl = buildLocalhostUrl(this.options.port);
131
152
  const vendorBundleHash = "dev-vendor-bundle";
@@ -334,6 +355,7 @@ export class DevServer {
334
355
  logger.info("Shutting down dev server...");
335
356
  this.reloadUnsubscribe?.();
336
357
  this.invalidateUnsubscribe?.();
358
+ this.releaseExternalBroadcastSource?.();
337
359
  if (this.fileWatchSetup) {
338
360
  const metrics = this.fileWatchSetup.getMetrics();
339
361
  if (metrics) {
@@ -6,6 +6,7 @@ export interface DevServerOptions {
6
6
  handlerOnly?: boolean;
7
7
  /** 0.0.0.0 = all interfaces, 127.0.0.1 = localhost only */
8
8
  bindAddress?: string;
9
+ /** @deprecated Ignored: HMR now uses /_ws on the main dev server port. */
9
10
  hmrPort?: number;
10
11
  moduleServerPort?: number;
11
12
  enableHMR?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/src/server/dev-server/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B"}
@@ -5,6 +5,7 @@ export type { HMRClientInfo } from "./hmr-client-manager.js";
5
5
  export declare class HMRHandler extends BaseHandler {
6
6
  private static rateLimiter;
7
7
  private static reloadUnsubscribe;
8
+ private static externalBroadcastSourceCount;
8
9
  private static initialized;
9
10
  metadata: HandlerMetadata;
10
11
  private static initialize;
@@ -23,6 +24,7 @@ export declare class HMRHandler extends BaseHandler {
23
24
  messagesForwarded: number;
24
25
  lastBroadcastTime: number;
25
26
  };
27
+ static registerExternalBroadcastSource(): () => void;
26
28
  static shutdown(): void;
27
29
  private static getMessageSize;
28
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AASrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAkBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAK7D,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgD;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAC7D,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC,QAAQ,EAAE,eAAe,CAKvB;IAEF,OAAO,CAAC,MAAM,CAAC,UAAU;IA6BzB,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAuJzE;;;;;OAKG;YACW,wBAAwB;IAuCtC,MAAM,CAAC,cAAc,IAAI,MAAM;IAI/B,MAAM,CAAC,UAAU,IAAI;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAID,MAAM,CAAC,QAAQ,IAAI,IAAI;IAavB,OAAO,CAAC,MAAM,CAAC,cAAc;CAO9B"}
1
+ {"version":3,"file":"hmr.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/hmr.handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AASrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAmBrB,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAK7D,qBAAa,UAAW,SAAQ,WAAW;IACzC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAgD;IAC1E,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA6B;IAC7D,OAAO,CAAC,MAAM,CAAC,4BAA4B,CAAK;IAChD,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC,QAAQ,EAAE,eAAe,CAKvB;IAEF,OAAO,CAAC,MAAM,CAAC,UAAU;IAsCzB,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA0JzE;;;;;OAKG;YACW,wBAAwB;IAuCtC,MAAM,CAAC,cAAc,IAAI,MAAM;IAI/B,MAAM,CAAC,UAAU,IAAI;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAID,MAAM,CAAC,+BAA+B,IAAI,MAAM,IAAI;IAWpD,MAAM,CAAC,QAAQ,IAAI,IAAI;IAcvB,OAAO,CAAC,MAAM,CAAC,cAAc;CAO9B"}
@@ -6,6 +6,7 @@ import { HandlerPriority, } from "../types.js";
6
6
  import { ReloadNotifier } from "../../reload-notifier.js";
7
7
  import { invalidateProjectCaches } from "../../context/cache-invalidation.js";
8
8
  import { isExtendedFSAdapter } from "../../../platform/adapters/fs/wrapper.js";
9
+ import { isLocalDevHost } from "../../utils/domain-parser.js";
9
10
  import { addClient, clearAll, getClient, getClientCount, getClientDetails, removeClient, } from "./hmr-client-manager.js";
10
11
  import { getPingIntervalMs, startPingInterval, stopPingInterval } from "./hmr-ping-keepalive.js";
11
12
  import { broadcastUpdate, getMetrics } from "./hmr-message-router.js";
@@ -15,6 +16,7 @@ const PRIORITY_HMR = HandlerPriority.EARLY;
15
16
  export class HMRHandler extends BaseHandler {
16
17
  static rateLimiter = new RateLimiter(HMR_MAX_MESSAGES_PER_MINUTE);
17
18
  static reloadUnsubscribe = null;
19
+ static externalBroadcastSourceCount = 0;
18
20
  static initialized = false;
19
21
  metadata = {
20
22
  name: "HMRHandler",
@@ -39,6 +41,13 @@ export class HMRHandler extends BaseHandler {
39
41
  environment: project?.environment,
40
42
  branchId: project?.branch ?? undefined,
41
43
  });
44
+ if (HMRHandler.externalBroadcastSourceCount > 0) {
45
+ logger.debug("Skipping handler broadcast - external source active", {
46
+ projectSlug: project?.projectSlug,
47
+ externalBroadcastSourceCount: HMRHandler.externalBroadcastSourceCount,
48
+ });
49
+ return;
50
+ }
42
51
  broadcastUpdate(changedPaths, project?.projectSlug);
43
52
  });
44
53
  startPingInterval();
@@ -54,13 +63,16 @@ export class HMRHandler extends BaseHandler {
54
63
  const isPreviewMode = ctx.requestContext?.mode === "preview" || queryEnv === "preview";
55
64
  const isLocal = !!ctx.isLocalProject;
56
65
  const host = req.headers.get("host") ?? "";
57
- const isLocalhost = host.startsWith("localhost") || host.startsWith("127.0.0.1");
66
+ const isLocalhost = isLocalDevHost(host);
58
67
  if (!isPreviewMode && !isLocal && !isLocalhost) {
59
- logger.debug("Skipping - not preview or local dev", {
68
+ logger.warn("Skipping /_ws - not preview, local dev, or localhost", {
60
69
  mode: ctx.requestContext?.mode,
61
70
  queryEnv,
62
71
  isLocalProject: ctx.isLocalProject,
63
72
  host,
73
+ isPreviewMode,
74
+ isLocal,
75
+ isLocalhost,
64
76
  });
65
77
  return Promise.resolve(this.continue());
66
78
  }
@@ -218,12 +230,19 @@ export class HMRHandler extends BaseHandler {
218
230
  static getMetrics() {
219
231
  return getMetrics();
220
232
  }
233
+ static registerExternalBroadcastSource() {
234
+ HMRHandler.externalBroadcastSourceCount++;
235
+ return () => {
236
+ HMRHandler.externalBroadcastSourceCount = Math.max(0, HMRHandler.externalBroadcastSourceCount - 1);
237
+ };
238
+ }
221
239
  static shutdown() {
222
240
  HMRHandler.reloadUnsubscribe?.();
223
241
  HMRHandler.reloadUnsubscribe = null;
224
242
  stopPingInterval();
225
243
  clearAll();
226
244
  HMRHandler.rateLimiter = new RateLimiter(HMR_MAX_MESSAGES_PER_MINUTE);
245
+ HMRHandler.externalBroadcastSourceCount = 0;
227
246
  HMRHandler.initialized = false;
228
247
  logger.debug("Shutdown complete");
229
248
  }
@@ -14,7 +14,8 @@ import { DevServer, type DevServerOptions, type FileWatcherMetrics, type RouteDi
14
14
  import { type DiscoveryOptions, type ServerHandle, startProductionServer, type StartProductionServerOptions } from "./production-server.js";
15
15
  export { DevServer, startDevServer, startProductionServer };
16
16
  export type { DevServerOptions, DiscoveryOptions, FileWatcherMetrics, RouteDirectory, ServerHandle, StartProductionServerOptions, };
17
- export { ReloadNotifier } from "./reload-notifier.js";
17
+ import { ReloadNotifier } from "./reload-notifier.js";
18
+ export { ReloadNotifier };
18
19
  export type { BuildOptions, BuildStats } from "./build-types.js";
19
20
  /** Shared options for both development and production server modes. */
20
21
  interface BaseServerOptions {
@@ -36,6 +37,7 @@ interface BaseServerOptions {
36
37
  }
37
38
  export interface StartDevModeOptions extends BaseServerOptions {
38
39
  mode?: "development";
40
+ /** @deprecated Ignored: HMR now uses /_ws on the main server port. */
39
41
  hmrPort?: number;
40
42
  moduleServerPort?: number;
41
43
  enableHMR?: boolean;