@jay-framework/dev-server 0.16.2 → 0.16.4

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 (2) hide show
  1. package/dist/index.js +83 -26
  2. package/package.json +14 -14
package/dist/index.js CHANGED
@@ -13,15 +13,15 @@ import path__default from "node:path";
13
13
  import { JAY_IMPORT_RESOLVER, injectHeadfullFSTemplates, parseContract, slowRenderTransform, discoverHeadlessInstances, assignCoordinatesToJayHtml, resolveHeadlessInstances } from "@jay-framework/compiler-jay-html";
14
14
  import { getLogger, getDevLogger } from "@jay-framework/logger";
15
15
  import { createRequire as createRequire$1 } from "node:module";
16
- import * as fs from "node:fs";
17
- import fs__default$1 from "node:fs";
16
+ import * as fsSync from "node:fs";
17
+ import fsSync__default from "node:fs";
18
18
  import { scanRoutes, createRoute, routeToExpressRoute } from "@jay-framework/stack-route-scanner";
19
19
  import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, actionRegistry, discoverAndRegisterActions, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, loadPageParts, runLoadParams, DevSlowlyChangingPhase, SlowRenderCache, preparePluginClientInits, registerService, clearServerElementCache, scanPlugins, getServiceRegistry, materializeContracts, renderFastChangingData, mergeHeadTags, generateClientScript, getClientInitData, generateSSRPageHtml, generateFrozenPageHtml, validateForEachInstances, slowRenderInstances } from "@jay-framework/stack-server-runtime";
20
- import * as fs$1 from "node:fs/promises";
20
+ import * as fs from "node:fs/promises";
21
21
  import fs__default from "node:fs/promises";
22
22
  import { pathToFileURL } from "node:url";
23
23
  import Busboy from "busboy";
24
- import fs$2 from "fs";
24
+ import fs$1 from "fs";
25
25
  import path$1 from "path";
26
26
  import crypto from "crypto";
27
27
  import { randomUUID } from "node:crypto";
@@ -1318,16 +1318,16 @@ function jayStackCompiler(options = {}) {
1318
1318
  const importerDir = path.dirname(importer);
1319
1319
  let resolvedPath = path.resolve(importerDir, source);
1320
1320
  if (!resolvedPath.endsWith(".ts") && !resolvedPath.endsWith(".js")) {
1321
- if (fs.existsSync(resolvedPath + ".ts")) {
1321
+ if (fsSync.existsSync(resolvedPath + ".ts")) {
1322
1322
  resolvedPath += ".ts";
1323
- } else if (fs.existsSync(resolvedPath + ".js")) {
1323
+ } else if (fsSync.existsSync(resolvedPath + ".js")) {
1324
1324
  resolvedPath += ".js";
1325
1325
  } else {
1326
1326
  return null;
1327
1327
  }
1328
- } else if (resolvedPath.endsWith(".js") && !fs.existsSync(resolvedPath)) {
1328
+ } else if (resolvedPath.endsWith(".js") && !fsSync.existsSync(resolvedPath)) {
1329
1329
  const tsPath = resolvedPath.slice(0, -3) + ".ts";
1330
- if (fs.existsSync(tsPath)) {
1330
+ if (fsSync.existsSync(tsPath)) {
1331
1331
  resolvedPath = tsPath;
1332
1332
  } else {
1333
1333
  return null;
@@ -1342,7 +1342,7 @@ function jayStackCompiler(options = {}) {
1342
1342
  const actualPath = id.slice("\0jay-action:".length);
1343
1343
  let code;
1344
1344
  try {
1345
- code = await fs.promises.readFile(actualPath, "utf-8");
1345
+ code = await fsSync.promises.readFile(actualPath, "utf-8");
1346
1346
  } catch (err) {
1347
1347
  getLogger().error(
1348
1348
  `[action-transform] Could not read ${actualPath}: ${err}`
@@ -1417,6 +1417,22 @@ async function createViteServer(options) {
1417
1417
  base,
1418
1418
  // Root directory for module resolution
1419
1419
  root: pagesRoot,
1420
+ // Force singleton resolution for all runtime packages.
1421
+ // Without this, pre-bundled deps (in .vite/deps/) inline their own copy
1422
+ // of these packages, while plugin client bundles (served as raw ESM via /@fs/)
1423
+ // resolve to a separate instance → duplicate createJayContext() → runtime crash.
1424
+ resolve: {
1425
+ dedupe: [
1426
+ "@jay-framework/runtime",
1427
+ "@jay-framework/reactive",
1428
+ "@jay-framework/component",
1429
+ "@jay-framework/fullstack-component",
1430
+ "@jay-framework/stack-client-runtime",
1431
+ "@jay-framework/runtime-automation",
1432
+ "@jay-framework/view-state-merge",
1433
+ "@jay-framework/json-patch"
1434
+ ]
1435
+ },
1420
1436
  // SSR configuration
1421
1437
  ssr: {
1422
1438
  // Mark jay-framework packages as external so Vite uses Node's require
@@ -1424,7 +1440,10 @@ async function createViteServer(options) {
1424
1440
  external: ["@jay-framework/stack-server-runtime", "@jay-framework/fullstack-component"]
1425
1441
  },
1426
1442
  // Disable automatic entry point discovery for pre-bundling —
1427
- // we run in middleware mode with no HTML files, so Vite can't auto-detect entries
1443
+ // we run in middleware mode with no HTML files, so Vite can't auto-detect entries.
1444
+ // Explicitly include singleton packages so Vite pre-bundles them as separate entries.
1445
+ // Without this, stack-client-runtime inlines its own copy of component/reactive/runtime
1446
+ // into the .vite/deps/ chunk, while plugin client bundles import the raw ESM copy → duplicates.
1428
1447
  optimizeDeps: {
1429
1448
  entries: []
1430
1449
  },
@@ -1482,7 +1501,7 @@ class ServiceLifecycleManager {
1482
1501
  const extensions = [".ts", ".js"];
1483
1502
  for (const ext of extensions) {
1484
1503
  const filePath = path.join(this.projectRoot, this.sourceBase, "init" + ext);
1485
- if (fs.existsSync(filePath)) {
1504
+ if (fsSync.existsSync(filePath)) {
1486
1505
  return filePath;
1487
1506
  }
1488
1507
  }
@@ -1861,9 +1880,29 @@ function getStatusCodeForError(code, isActionError) {
1861
1880
  }
1862
1881
  const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
1863
1882
  const DEFAULT_MAX_FILES = 10;
1883
+ function mergeDottedMultipartKeys(body) {
1884
+ const keys = Object.keys(body);
1885
+ for (const key of keys) {
1886
+ if (!key.includes("."))
1887
+ continue;
1888
+ const val = body[key];
1889
+ delete body[key];
1890
+ const parts = key.split(".");
1891
+ let cur = body;
1892
+ for (let i = 0; i < parts.length - 1; i++) {
1893
+ const p = parts[i];
1894
+ const next = cur[p];
1895
+ if (typeof next !== "object" || next === null || Array.isArray(next)) {
1896
+ cur[p] = {};
1897
+ }
1898
+ cur = cur[p];
1899
+ }
1900
+ cur[parts[parts.length - 1]] = val;
1901
+ }
1902
+ }
1864
1903
  function parseMultipart(req, tempDir, maxFileSize, maxFiles) {
1865
1904
  return new Promise((resolve, reject) => {
1866
- fs$2.mkdirSync(tempDir, { recursive: true });
1905
+ fs$1.mkdirSync(tempDir, { recursive: true });
1867
1906
  const files = {};
1868
1907
  let jsonData = {};
1869
1908
  let fileCount = 0;
@@ -1884,7 +1923,7 @@ function parseMultipart(req, tempDir, maxFileSize, maxFiles) {
1884
1923
  const tempPath = path$1.join(tempDir, `${fileCount}-${filename}`);
1885
1924
  let size = 0;
1886
1925
  let truncated = false;
1887
- const writeStream = fs$2.createWriteStream(tempPath);
1926
+ const writeStream = fs$1.createWriteStream(tempPath);
1888
1927
  stream.pipe(writeStream);
1889
1928
  stream.on("data", (data) => {
1890
1929
  size += data.length;
@@ -1939,7 +1978,11 @@ function parseMultipart(req, tempDir, maxFileSize, maxFiles) {
1939
1978
  bb.on("close", () => {
1940
1979
  if (errored)
1941
1980
  return;
1942
- Promise.all(pendingWrites).then(() => resolve({ body: { ...jsonData, ...files }, tempDir })).catch((err) => reject(err));
1981
+ Promise.all(pendingWrites).then(() => {
1982
+ const body = { ...jsonData, ...files };
1983
+ mergeDottedMultipartKeys(body);
1984
+ resolve({ body, tempDir });
1985
+ }).catch((err) => reject(err));
1943
1986
  });
1944
1987
  bb.on("error", (err) => {
1945
1988
  if (!errored) {
@@ -1952,7 +1995,7 @@ function parseMultipart(req, tempDir, maxFileSize, maxFiles) {
1952
1995
  }
1953
1996
  function cleanupTempDir(dir) {
1954
1997
  try {
1955
- fs$2.rmSync(dir, { recursive: true, force: true });
1998
+ fs$1.rmSync(dir, { recursive: true, force: true });
1956
1999
  } catch {
1957
2000
  }
1958
2001
  }
@@ -2032,7 +2075,7 @@ class FreezeStore {
2032
2075
  this.dir = path.join(buildFolder, "freezes");
2033
2076
  }
2034
2077
  async save(route, viewState, routePattern) {
2035
- await fs$1.mkdir(this.dir, { recursive: true });
2078
+ await fs.mkdir(this.dir, { recursive: true });
2036
2079
  const entry = {
2037
2080
  id: randomUUID().slice(0, 8),
2038
2081
  route,
@@ -2040,7 +2083,7 @@ class FreezeStore {
2040
2083
  viewState,
2041
2084
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
2042
2085
  };
2043
- await fs$1.writeFile(
2086
+ await fs.writeFile(
2044
2087
  path.join(this.dir, `${entry.id}.json`),
2045
2088
  JSON.stringify(entry, null, 2),
2046
2089
  "utf-8"
@@ -2049,7 +2092,7 @@ class FreezeStore {
2049
2092
  }
2050
2093
  async get(id) {
2051
2094
  try {
2052
- const content = await fs$1.readFile(path.join(this.dir, `${id}.json`), "utf-8");
2095
+ const content = await fs.readFile(path.join(this.dir, `${id}.json`), "utf-8");
2053
2096
  return JSON.parse(content);
2054
2097
  } catch {
2055
2098
  return void 0;
@@ -2057,13 +2100,13 @@ class FreezeStore {
2057
2100
  }
2058
2101
  async list(route) {
2059
2102
  try {
2060
- const files = await fs$1.readdir(this.dir);
2103
+ const files = await fs.readdir(this.dir);
2061
2104
  const entries = [];
2062
2105
  for (const file of files) {
2063
2106
  if (!file.endsWith(".json"))
2064
2107
  continue;
2065
2108
  try {
2066
- const content = await fs$1.readFile(path.join(this.dir, file), "utf-8");
2109
+ const content = await fs.readFile(path.join(this.dir, file), "utf-8");
2067
2110
  const entry = JSON.parse(content);
2068
2111
  if (!route || entry.routePattern === route || entry.route === route) {
2069
2112
  entries.push(entry);
@@ -2083,7 +2126,7 @@ class FreezeStore {
2083
2126
  if (!entry)
2084
2127
  return false;
2085
2128
  entry.name = name;
2086
- await fs$1.writeFile(
2129
+ await fs.writeFile(
2087
2130
  path.join(this.dir, `${id}.json`),
2088
2131
  JSON.stringify(entry, null, 2),
2089
2132
  "utf-8"
@@ -2092,7 +2135,7 @@ class FreezeStore {
2092
2135
  }
2093
2136
  async delete(id) {
2094
2137
  try {
2095
- await fs$1.unlink(path.join(this.dir, `${id}.json`));
2138
+ await fs.unlink(path.join(this.dir, `${id}.json`));
2096
2139
  return true;
2097
2140
  } catch {
2098
2141
  return false;
@@ -2186,7 +2229,7 @@ function resolvePluginExport(pluginPath, exportSubpath) {
2186
2229
  const normalized = exportSubpath.replace(/^\.\//, "");
2187
2230
  const packageJsonPath = path__default.join(pluginPath, "package.json");
2188
2231
  try {
2189
- const packageJson = JSON.parse(fs__default$1.readFileSync(packageJsonPath, "utf-8"));
2232
+ const packageJson = JSON.parse(fsSync__default.readFileSync(packageJsonPath, "utf-8"));
2190
2233
  if (packageJson.exports) {
2191
2234
  const exportKey = "./" + normalized;
2192
2235
  const exportValue = packageJson.exports[exportKey];
@@ -2203,7 +2246,7 @@ function resolvePluginExport(pluginPath, exportSubpath) {
2203
2246
  for (const dir of ["dist", "lib", ""]) {
2204
2247
  const candidate = path__default.join(pluginPath, dir, normalized);
2205
2248
  try {
2206
- fs__default$1.accessSync(candidate);
2249
+ fsSync__default.accessSync(candidate);
2207
2250
  return candidate;
2208
2251
  } catch {
2209
2252
  }
@@ -2211,11 +2254,25 @@ function resolvePluginExport(pluginPath, exportSubpath) {
2211
2254
  return void 0;
2212
2255
  }
2213
2256
  function resolvePluginModule(plugin) {
2257
+ const pkgJsonPath = path__default.join(plugin.pluginPath, "package.json");
2258
+ if (fsSync__default.existsSync(pkgJsonPath)) {
2259
+ try {
2260
+ const pkg = JSON.parse(fsSync__default.readFileSync(pkgJsonPath, "utf-8"));
2261
+ const mainExport = pkg.exports?.["."];
2262
+ const mainPath = typeof mainExport === "string" ? mainExport : mainExport?.default || mainExport?.import || pkg.main;
2263
+ if (mainPath) {
2264
+ const resolved = path__default.join(plugin.pluginPath, mainPath);
2265
+ if (fsSync__default.existsSync(resolved))
2266
+ return resolved;
2267
+ }
2268
+ } catch {
2269
+ }
2270
+ }
2214
2271
  const modulePath = plugin.manifest.module || "index";
2215
2272
  for (const ext of [".ts", ".js", "/index.ts", "/index.js"]) {
2216
2273
  const candidate = path__default.join(plugin.pluginPath, modulePath + ext);
2217
2274
  try {
2218
- fs__default$1.accessSync(candidate);
2275
+ fsSync__default.accessSync(candidate);
2219
2276
  return candidate;
2220
2277
  } catch {
2221
2278
  }
@@ -2223,7 +2280,7 @@ function resolvePluginModule(plugin) {
2223
2280
  for (const ext of [".ts", ".js"]) {
2224
2281
  const candidate = path__default.join(plugin.pluginPath, "lib", path__default.basename(modulePath) + ext);
2225
2282
  try {
2226
- fs__default$1.accessSync(candidate);
2283
+ fsSync__default.accessSync(candidate);
2227
2284
  return candidate;
2228
2285
  } catch {
2229
2286
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/dev-server",
3
- "version": "0.16.2",
3
+ "version": "0.16.4",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -23,23 +23,23 @@
23
23
  "test:watch": "vitest"
24
24
  },
25
25
  "dependencies": {
26
- "@jay-framework/compiler-jay-stack": "^0.16.2",
27
- "@jay-framework/compiler-shared": "^0.16.2",
28
- "@jay-framework/component": "^0.16.2",
29
- "@jay-framework/fullstack-component": "^0.16.2",
30
- "@jay-framework/logger": "^0.16.2",
31
- "@jay-framework/runtime": "^0.16.2",
32
- "@jay-framework/stack-client-runtime": "^0.16.2",
33
- "@jay-framework/stack-route-scanner": "^0.16.2",
34
- "@jay-framework/stack-server-runtime": "^0.16.2",
35
- "@jay-framework/view-state-merge": "^0.16.2",
26
+ "@jay-framework/compiler-jay-stack": "^0.16.4",
27
+ "@jay-framework/compiler-shared": "^0.16.4",
28
+ "@jay-framework/component": "^0.16.4",
29
+ "@jay-framework/fullstack-component": "^0.16.4",
30
+ "@jay-framework/logger": "^0.16.4",
31
+ "@jay-framework/runtime": "^0.16.4",
32
+ "@jay-framework/stack-client-runtime": "^0.16.4",
33
+ "@jay-framework/stack-route-scanner": "^0.16.4",
34
+ "@jay-framework/stack-server-runtime": "^0.16.4",
35
+ "@jay-framework/view-state-merge": "^0.16.4",
36
36
  "busboy": "^1.6.0",
37
37
  "vite": "^5.0.11"
38
38
  },
39
39
  "devDependencies": {
40
- "@jay-framework/dev-environment": "^0.16.2",
41
- "@jay-framework/jay-cli": "^0.16.2",
42
- "@jay-framework/stack-client-runtime": "^0.16.2",
40
+ "@jay-framework/dev-environment": "^0.16.4",
41
+ "@jay-framework/jay-cli": "^0.16.4",
42
+ "@jay-framework/stack-client-runtime": "^0.16.4",
43
43
  "@playwright/test": "^1.58.2",
44
44
  "@types/busboy": "^1.5.4",
45
45
  "@types/express": "^5.0.2",