@jay-framework/dev-server 0.22.2 → 0.23.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +3 -1
  2. package/dist/index.js +198 -144
  3. package/package.json +14 -14
package/dist/index.d.ts CHANGED
@@ -140,6 +140,8 @@ interface RouteInfo {
140
140
  path: string;
141
141
  jayHtmlPath: string;
142
142
  compPath: string;
143
+ /** Dev-server tooling route — consumers like AIditor may filter from page pickers. */
144
+ devOnly?: boolean;
143
145
  }
144
146
  type DevServerRouteRegistrar = (routes: DevServerRoute[]) => void;
145
147
  declare class DevServerService {
@@ -160,7 +162,7 @@ declare class DevServerService {
160
162
  * added since dev-server startup (e.g. after AIditor Add Page).
161
163
  */
162
164
  refreshRoutes(): Promise<RouteInfo[]>;
163
- /** List all page routes in the project. */
165
+ /** List all page routes in the project (includes dev-only plugin routes). */
164
166
  listRoutes(): RouteInfo[];
165
167
  /**
166
168
  * Run loadParams for a route, yielding param batches as an async generator.
package/dist/index.js CHANGED
@@ -1,22 +1,19 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => {
4
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- return value;
6
- };
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
4
  import { createServer } from "vite";
8
5
  import { jayRuntime } from "@jay-framework/vite-plugin";
9
6
  import { createRequire } from "module";
10
7
  import "@jay-framework/compiler-shared";
11
8
  import * as path from "node:path";
12
9
  import path__default from "node:path";
13
- import { JAY_IMPORT_RESOLVER, injectHeadfullFSTemplates, parseContract, slowRenderTransform, assignCoordinatesToJayHtml, discoverHeadlessInstances } from "@jay-framework/compiler-jay-html";
10
+ import { injectHeadfullFSTemplates, JAY_IMPORT_RESOLVER, parseContract, slowRenderTransform, assignCoordinatesToJayHtml, discoverHeadlessInstances } from "@jay-framework/compiler-jay-html";
14
11
  import { getLogger, getDevLogger } from "@jay-framework/logger";
15
12
  import { createRequire as createRequire$1 } from "node:module";
16
13
  import * as fsSync from "node:fs";
17
14
  import fsSync__default from "node:fs";
18
15
  import { scanRoutes, createRoute, routeToExpressRoute } from "@jay-framework/stack-route-scanner";
19
- import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, actionRegistry, discoverAndRegisterActions, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, loadPageParts, runLoadParams, DevSlowlyChangingPhase, SlowRenderCache, preparePluginClientInits, registerService, clearServerElementCache, scanPlugins, getServiceRegistry, materializeContracts, parseCookies, renderFastChangingData, mergeHeadTags, generateClientScript, getClientInitData, generateSSRPageHtml, generateFrozenPageHtml, slowRenderInstances, normalizeAndResolveInstanceProps } from "@jay-framework/stack-server-runtime";
16
+ import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, discoverAndRegisterActions, actionRegistry, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, loadPageParts, runLoadParams, DevSlowlyChangingPhase, SlowRenderCache, preparePluginClientInits, registerService, getServiceRegistry, materializeContracts, scanPlugins, clearServerElementCache, parseCookies, generateFrozenPageHtml, renderFastChangingData, generateClientScript, getClientInitData, mergeHeadTags, generateSSRPageHtml, slowRenderInstances, normalizeAndResolveInstanceProps } from "@jay-framework/stack-server-runtime";
20
17
  import * as fs from "node:fs/promises";
21
18
  import fs__default from "node:fs/promises";
22
19
  import { pathToFileURL } from "node:url";
@@ -33,10 +30,7 @@ const s$1 = createRequire(import.meta.url), e$1 = s$1("typescript"), c$1 = new P
33
30
  });
34
31
  var __defProp2 = Object.defineProperty;
35
32
  var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
36
- var __publicField2 = (obj, key, value) => {
37
- __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
38
- return value;
39
- };
33
+ var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
40
34
  const s = createRequire(import.meta.url), e = s("typescript"), c = new Proxy(e, {
41
35
  get(t, r) {
42
36
  return t[r];
@@ -72,6 +66,9 @@ function mkTransformer(fileTransformer, config) {
72
66
  };
73
67
  };
74
68
  }
69
+ const { isStringLiteral: isStringLiteral$a, isImportDeclaration: isImportDeclaration$5, forEachChild: forEachChild$4, isNamedImports: isNamedImports$1 } = c;
70
+ const { isStringLiteral: isStringLiteral$9, forEachChild: forEachChild$3, isImportDeclaration: isImportDeclaration$4 } = c;
71
+ const { isIdentifier: isIdentifier$a, isArrowFunction: isArrowFunction$3, isFunctionDeclaration: isFunctionDeclaration$2, isVariableStatement: isVariableStatement$3, forEachChild: forEachChild$2 } = c;
75
72
  const {
76
73
  isIdentifier: isIdentifier$9,
77
74
  isStatement: isStatement$3,
@@ -89,7 +86,7 @@ const {
89
86
  isNumericLiteral,
90
87
  isToken,
91
88
  isNamespaceImport,
92
- isNamedImports: isNamedImports$1,
89
+ isNamedImports: isNamedImports$2,
93
90
  isArrowFunction: isArrowFunction$2,
94
91
  isFunctionExpression,
95
92
  isCallExpression: isCallExpression$6,
@@ -138,12 +135,9 @@ const getAccessedByProperty = (binding, accessedFrom, propertyName) => {
138
135
  return accessedFrom ? propertyName ? isIdentifier$9(propertyName) ? propertyName.text : void 0 : binding.text : void 0;
139
136
  };
140
137
  function findDeclaringStatement(node) {
141
- if (!node)
142
- return void 0;
143
- else if (isStatement$3(node))
144
- return node;
145
- else
146
- return findDeclaringStatement(node.parent);
138
+ if (!node) return void 0;
139
+ else if (isStatement$3(node)) return node;
140
+ else return findDeclaringStatement(node.parent);
147
141
  }
148
142
  function tsBindingNameToVariable(binding, accessedFrom, assignedFrom, propertyName, root) {
149
143
  if (isIdentifier$9(binding)) {
@@ -202,8 +196,7 @@ class NameBindingResolver {
202
196
  mkParameterVariableRoot(param, paramIndex)
203
197
  );
204
198
  paramVariables.forEach((variable) => {
205
- if (variable.name)
206
- this.variables.set(variable.name, variable);
199
+ if (variable.name) this.variables.set(variable.name, variable);
207
200
  });
208
201
  });
209
202
  }
@@ -304,8 +297,7 @@ class NameBindingResolver {
304
297
  let resolved;
305
298
  while ((resolved = nameResolver.getVariable(variableName)) === UNKNOWN_VARIABLE && nameResolver.parentNameResolver)
306
299
  nameResolver = nameResolver.parentNameResolver;
307
- if (resolved === UNKNOWN_VARIABLE)
308
- return { root: mkGlobalVariableRoot(variableName) };
300
+ if (resolved === UNKNOWN_VARIABLE) return { root: mkGlobalVariableRoot(variableName) };
309
301
  return resolved;
310
302
  }
311
303
  addImportDeclaration(node) {
@@ -336,7 +328,7 @@ class NameBindingResolver {
336
328
  root
337
329
  });
338
330
  this.variables.set(namedBindings.name.text, variable);
339
- } else if (isNamedImports$1(namedBindings)) {
331
+ } else if (isNamedImports$2(namedBindings)) {
340
332
  namedBindings.elements.forEach((importSpecifier) => {
341
333
  if (!importSpecifier.isTypeOnly) {
342
334
  let variable = mkVariable({
@@ -356,8 +348,7 @@ class NameBindingResolver {
356
348
  }
357
349
  }
358
350
  function flattenVariable(variable, path2 = []) {
359
- if (variable.assignedFrom)
360
- return flattenVariable(variable.assignedFrom, path2);
351
+ if (variable.assignedFrom) return flattenVariable(variable.assignedFrom, path2);
361
352
  else if (variable.accessedFrom) {
362
353
  return flattenVariable(variable.accessedFrom, [variable.accessedByProperty, ...path2]);
363
354
  } else if (variable.properties && !!variable.properties.find((_) => _.name === path2[0])) {
@@ -365,12 +356,19 @@ function flattenVariable(variable, path2 = []) {
365
356
  variable.properties.find((_) => _.name === path2[0]),
366
357
  path2.slice(1)
367
358
  );
368
- } else
369
- return { path: path2, root: variable.root };
359
+ } else return { path: path2, root: variable.root };
370
360
  }
361
+ const { isIdentifier: isIdentifier$8, isPropertyAccessExpression: isPropertyAccessExpression$4 } = c;
371
362
  function byAnd() {
372
363
  return (agg, value) => agg && value;
373
364
  }
365
+ const {
366
+ isCallExpression: isCallExpression$5,
367
+ isExpressionStatement: isExpressionStatement$1,
368
+ isIdentifier: isIdentifier$7,
369
+ isPropertyAccessExpression: isPropertyAccessExpression$3,
370
+ isBlock: isBlock$3
371
+ } = c;
374
372
  const {
375
373
  isIdentifier: isIdentifier$6,
376
374
  SyntaxKind: SyntaxKind$4,
@@ -442,12 +440,8 @@ class UnionResolvedType {
442
440
  if (rightSide instanceof UnionResolvedType) {
443
441
  for (const item1 of this.types)
444
442
  for (const item2 of rightSide.types)
445
- if (item1.canBeAssignedFrom(item2))
446
- return true;
447
- } else
448
- for (const item1 of this.types)
449
- if (item1.canBeAssignedFrom(rightSide))
450
- return true;
443
+ if (item1.canBeAssignedFrom(item2)) return true;
444
+ } else for (const item1 of this.types) if (item1.canBeAssignedFrom(rightSide)) return true;
451
445
  return false;
452
446
  }
453
447
  }
@@ -475,15 +469,11 @@ class SourceFileBindingResolver {
475
469
  return node;
476
470
  };
477
471
  const visitor = (node) => {
478
- if (isFunctionDeclaration$1(node))
479
- nbResolversQueue[0].addFunctionDeclaration(node);
480
- if (isVariableStatement$2(node))
481
- nbResolversQueue[0].addVariableStatement(node);
482
- else if (isImportDeclaration$3(node))
483
- nbResolversQueue[0].addImportDeclaration(node);
484
- else if (isBlock$2(node))
485
- return doWithChildBindingResolver(node, () => {
486
- });
472
+ if (isFunctionDeclaration$1(node)) nbResolversQueue[0].addFunctionDeclaration(node);
473
+ if (isVariableStatement$2(node)) nbResolversQueue[0].addVariableStatement(node);
474
+ else if (isImportDeclaration$3(node)) nbResolversQueue[0].addImportDeclaration(node);
475
+ else if (isBlock$2(node)) return doWithChildBindingResolver(node, () => {
476
+ });
487
477
  else if (isFunctionLikeDeclarationBase(node)) {
488
478
  return doWithChildBindingResolver(
489
479
  node,
@@ -516,8 +506,7 @@ class SourceFileBindingResolver {
516
506
  }
517
507
  findBindingResolver(node) {
518
508
  let found;
519
- while (!(found = this.nameBindingResolvers.get(node)) && node.parent)
520
- node = node.parent;
509
+ while (!(found = this.nameBindingResolvers.get(node)) && node.parent) node = node.parent;
521
510
  return found;
522
511
  }
523
512
  explain(identifier) {
@@ -528,8 +517,7 @@ class SourceFileBindingResolver {
528
517
  if (isImportModuleVariableRoot(flattened.root) && isStringLiteral$7(flattened.root.module)) {
529
518
  return new ImportFromModuleResolvedType(flattened.root.module.text, flattened.path);
530
519
  }
531
- } else
532
- return void 0;
520
+ } else return void 0;
533
521
  }
534
522
  explainType(type) {
535
523
  if (type) {
@@ -539,10 +527,8 @@ class SourceFileBindingResolver {
539
527
  let resolved = this.findBindingResolver(typeName).resolveIdentifier(typeName);
540
528
  let flattened = flattenVariable(resolved);
541
529
  let typeFromFlattened = this.explainFlattenedVariableType(flattened);
542
- if (typeFromFlattened)
543
- return typeFromFlattened;
544
- if (builtInType(typeName.text))
545
- return new BuiltInResolvedType(typeName.text);
530
+ if (typeFromFlattened) return typeFromFlattened;
531
+ if (builtInType(typeName.text)) return new BuiltInResolvedType(typeName.text);
546
532
  }
547
533
  } else if (type.kind === SyntaxKind$4.StringKeyword)
548
534
  return new BuiltInResolvedType("string");
@@ -550,10 +536,8 @@ class SourceFileBindingResolver {
550
536
  return new BuiltInResolvedType("number");
551
537
  else if (type.kind === SyntaxKind$4.BooleanKeyword)
552
538
  return new BuiltInResolvedType("boolean");
553
- else if (type.kind === SyntaxKind$4.AnyKeyword)
554
- return new BuiltInResolvedType("any");
555
- else if (type.kind === SyntaxKind$4.VoidKeyword)
556
- return new BuiltInResolvedType("void");
539
+ else if (type.kind === SyntaxKind$4.AnyKeyword) return new BuiltInResolvedType("any");
540
+ else if (type.kind === SyntaxKind$4.VoidKeyword) return new BuiltInResolvedType("void");
557
541
  else if (isArrayTypeNode(type))
558
542
  return new ArrayResolvedType(this.explainType(type.elementType));
559
543
  else if (isFunctionTypeNode(type)) {
@@ -569,7 +553,67 @@ class SourceFileBindingResolver {
569
553
  return new GlobalResolvedType(globalVariableRoot.name);
570
554
  }
571
555
  }
572
- const { isStringLiteral: isStringLiteral$2 } = c;
556
+ const {
557
+ isSpreadElement,
558
+ isFunctionDeclaration: isFunctionDeclaration$4,
559
+ isDecorator,
560
+ isCallExpression: isCallExpression$4,
561
+ isIdentifier: isIdentifier$5,
562
+ isPropertyAccessExpression: isPropertyAccessExpression$2,
563
+ isReturnStatement,
564
+ isNewExpression: isNewExpression$1,
565
+ isExpressionStatement,
566
+ isBinaryExpression: isBinaryExpression$1,
567
+ SyntaxKind: SyntaxKind$3,
568
+ transform: transform$5,
569
+ visitEachChild: visitEachChild$4
570
+ } = c;
571
+ const { visitEachChild: visitEachChild$3, transform: transform$4, visitNode: visitNode$3 } = c;
572
+ const { isTypeReferenceNode } = c;
573
+ const {
574
+ visitEachChild: visitEachChild$2,
575
+ isIdentifier: isIdentifier$4,
576
+ SyntaxKind: SyntaxKind$2,
577
+ transform: transform$3,
578
+ isStatement: isStatement$2,
579
+ isBlock: isBlock$1,
580
+ isExpression: isExpression$1,
581
+ isLiteralExpression: isLiteralExpression$1,
582
+ visitNode: visitNode$2
583
+ } = c;
584
+ const { visitEachChild: visitEachChild$1, isCallExpression: isCallExpression$3, isPropertyAccessExpression: isPropertyAccessExpression$1$1 } = c;
585
+ const {
586
+ isBinaryExpression,
587
+ isCallExpression: isCallExpression$2,
588
+ isIdentifier: isIdentifier$3,
589
+ isNewExpression,
590
+ isPropertyAccessExpression: isPropertyAccessExpression$6,
591
+ SyntaxKind: SyntaxKind$1,
592
+ isArrowFunction: isArrowFunction$1,
593
+ isLiteralExpression,
594
+ isStatement: isStatement$1,
595
+ isVariableStatement: isVariableStatement$1,
596
+ isBlock,
597
+ isIfStatement,
598
+ isForStatement,
599
+ isForOfStatement,
600
+ isForInStatement,
601
+ isWhileStatement,
602
+ isDoStatement,
603
+ isElementAccessExpression,
604
+ isPropertyAssignment
605
+ } = c;
606
+ const { isCallExpression: isCallExpression$1$1, isIdentifier: isIdentifier$2$1, isStringLiteral: isStringLiteral$6, isVariableStatement: isVariableStatement$4, forEachChild: forEachChild$1 } = c;
607
+ const { isCallExpression: isCallExpression$7, isIdentifier: isIdentifier$1$1, isStringLiteral: isStringLiteral$5, forEachChild } = c;
608
+ const { transform: transform$2, isArrowFunction, isExpression, visitNode: visitNode$1 } = c;
609
+ const { SyntaxKind: SyntaxKind$6, transform: transform$1, isStringLiteral: isStringLiteral$4, isInterfaceDeclaration: isInterfaceDeclaration$1, isImportDeclaration: isImportDeclaration$2 } = c;
610
+ const { isStringLiteral: isStringLiteral$3 } = c;
611
+ const { isImportDeclaration: isImportDeclaration$1$1 } = c;
612
+ const { visitEachChild: visitEachChild$6, transform, isStringLiteral: isStringLiteral$2, isImportDeclaration: isImportDeclaration$6 } = c;
613
+ const { createSourceFile: createSourceFile$2, ScriptTarget: ScriptTarget$2, ScriptKind } = c;
614
+ const { isStringLiteral: isStringLiteral$1$1 } = c;
615
+ const { isIdentifier: isIdentifier$b, isStatement, visitNode } = c;
616
+ const { isStringLiteral: isStringLiteral$b } = c;
573
617
  function areFlattenedAccessChainsEqual(chain1, chain2) {
574
618
  if (chain1.path.length !== chain2.path.length) {
575
619
  return false;
@@ -593,8 +637,8 @@ function areVariableRootsEqual(root1, root2) {
593
637
  switch (root1.kind) {
594
638
  case VariableRootType.ImportModule:
595
639
  if (isImportModuleVariableRoot(root1) && isImportModuleVariableRoot(root2)) {
596
- const module1 = isStringLiteral$2(root1.module) ? root1.module.text : String(root1.module);
597
- const module2 = isStringLiteral$2(root2.module) ? root2.module.text : String(root2.module);
640
+ const module1 = isStringLiteral$b(root1.module) ? root1.module.text : String(root1.module);
641
+ const module2 = isStringLiteral$b(root2.module) ? root2.module.text : String(root2.module);
598
642
  return module1 === module2 && root1.importType === root2.importType;
599
643
  }
600
644
  return false;
@@ -616,28 +660,39 @@ const COMPONENT_SERVER_METHODS = /* @__PURE__ */ new Set([
616
660
  "withSlowlyRender",
617
661
  "withFastRender"
618
662
  ]);
619
- const COMPONENT_CLIENT_METHODS = /* @__PURE__ */ new Set(["withInteractive", "withContexts"]);
663
+ const COMPONENT_CLIENT_METHODS = /* @__PURE__ */ new Set(["withContexts"]);
664
+ const COMPONENT_CLIENT_REPLACE_METHODS = /* @__PURE__ */ new Map([["withInteractive", "withInteractiveMark"]]);
620
665
  const INIT_SERVER_METHODS = /* @__PURE__ */ new Set(["withServer"]);
621
666
  const INIT_CLIENT_METHODS = /* @__PURE__ */ new Set(["withClient"]);
622
667
  function shouldRemoveMethod(methodName, environment) {
623
- if (environment === "client" && COMPONENT_SERVER_METHODS.has(methodName))
624
- return true;
625
- if (environment === "server" && COMPONENT_CLIENT_METHODS.has(methodName))
626
- return true;
627
- if (environment === "client" && INIT_SERVER_METHODS.has(methodName))
628
- return true;
629
- if (environment === "server" && INIT_CLIENT_METHODS.has(methodName))
630
- return true;
668
+ if (environment === "client" && COMPONENT_SERVER_METHODS.has(methodName)) return true;
669
+ if (environment === "server" && COMPONENT_CLIENT_METHODS.has(methodName)) return true;
670
+ if (environment === "client" && INIT_SERVER_METHODS.has(methodName)) return true;
671
+ if (environment === "server" && INIT_CLIENT_METHODS.has(methodName)) return true;
631
672
  return false;
632
673
  }
674
+ function getReplacementMethod(methodName, environment) {
675
+ if (environment === "server") return COMPONENT_CLIENT_REPLACE_METHODS.get(methodName);
676
+ return void 0;
677
+ }
633
678
  const { isCallExpression: isCallExpression$1, isPropertyAccessExpression: isPropertyAccessExpression$1, isIdentifier: isIdentifier$2, isStringLiteral: isStringLiteral$1 } = c$1;
634
679
  function findBuilderMethodsToRemove(sourceFile, bindingResolver, environment) {
635
680
  const callsToRemove = [];
636
681
  const removedVariables = /* @__PURE__ */ new Set();
682
+ const methodReplacements = [];
637
683
  const visit = (node) => {
638
684
  if (isCallExpression$1(node) && isPropertyAccessExpression$1(node.expression) && isPartOfJayStackChain(node, bindingResolver)) {
639
685
  const methodName = node.expression.name.text;
640
- if (shouldRemoveMethod(methodName, environment)) {
686
+ const replacementName = getReplacementMethod(methodName, environment);
687
+ if (replacementName) {
688
+ const nameNode = node.expression.name;
689
+ methodReplacements.push({
690
+ start: nameNode.getStart(),
691
+ end: nameNode.getEnd(),
692
+ replacement: replacementName
693
+ });
694
+ collectVariablesFromArguments(node.arguments, bindingResolver, removedVariables);
695
+ } else if (shouldRemoveMethod(methodName, environment)) {
641
696
  const variable = bindingResolver.explain(node.expression);
642
697
  const flattened = flattenVariable(variable);
643
698
  callsToRemove.push(flattened);
@@ -647,7 +702,7 @@ function findBuilderMethodsToRemove(sourceFile, bindingResolver, environment) {
647
702
  node.forEachChild(visit);
648
703
  };
649
704
  sourceFile.forEachChild(visit);
650
- return { callsToRemove, removedVariables };
705
+ return { callsToRemove, removedVariables, methodReplacements };
651
706
  }
652
707
  const JAY_BUILDER_FUNCTIONS = /* @__PURE__ */ new Set(["makeJayStackComponent", "makeJayInit"]);
653
708
  function isPartOfJayStackChain(callExpr, bindingResolver) {
@@ -828,11 +883,12 @@ function mkJayStackCodeSplitTransformer({
828
883
  workingSourceFile = factory.updateSourceFile(sourceFile, filtered);
829
884
  }
830
885
  }
831
- const { callsToRemove } = findBuilderMethodsToRemove(
886
+ const { callsToRemove, methodReplacements } = findBuilderMethodsToRemove(
832
887
  workingSourceFile,
833
888
  bindingResolver,
834
889
  environment
835
890
  );
891
+ const replacementPositions = new Map(methodReplacements.map((r) => [r.start, r]));
836
892
  const transformVisitor = (node) => {
837
893
  if (isCallExpression(node) && isPropertyAccessExpression(node.expression)) {
838
894
  const variable = bindingResolver.explain(node.expression);
@@ -841,6 +897,17 @@ function mkJayStackCodeSplitTransformer({
841
897
  const receiver = node.expression.expression;
842
898
  return transformVisitor(receiver);
843
899
  }
900
+ const nameNode = node.expression.name;
901
+ const repl = replacementPositions.get(nameNode.getStart());
902
+ if (repl) {
903
+ const newName = factory.createIdentifier(repl.replacement);
904
+ const newAccess = factory.updatePropertyAccessExpression(
905
+ node.expression,
906
+ visitEachChild(node.expression.expression, transformVisitor, context),
907
+ newName
908
+ );
909
+ return factory.updateCallExpression(node, newAccess, node.typeArguments, []);
910
+ }
844
911
  }
845
912
  return visitEachChild(node, transformVisitor, context);
846
913
  };
@@ -897,8 +964,7 @@ function findChainRootBuilderName(statement, bindingResolver) {
897
964
  if (c$1.isExpressionStatement(statement) && isCallExpression(statement.expression)) {
898
965
  expr = statement.expression;
899
966
  }
900
- if (!expr)
901
- return void 0;
967
+ if (!expr) return void 0;
902
968
  let current = expr;
903
969
  while (true) {
904
970
  if (isCallExpression(current) && isPropertyAccessExpression(current.expression)) {
@@ -1061,8 +1127,7 @@ function createImportChainTracker(options = {}) {
1061
1127
  let current = moduleId;
1062
1128
  for (let i = 0; i < 100; i++) {
1063
1129
  const importer = importChain.get(current);
1064
- if (!importer)
1065
- break;
1130
+ if (!importer) break;
1066
1131
  chain.push(importer);
1067
1132
  current = importer;
1068
1133
  }
@@ -1179,7 +1244,7 @@ function createImportChainTracker(options = {}) {
1179
1244
  }
1180
1245
  };
1181
1246
  }
1182
- const require2 = createRequire$1(import.meta.url);
1247
+ const require$1 = createRequire$1(import.meta.url);
1183
1248
  function createDefaultPluginDetector() {
1184
1249
  const cache = /* @__PURE__ */ new Map();
1185
1250
  return {
@@ -1190,9 +1255,9 @@ function createDefaultPluginDetector() {
1190
1255
  }
1191
1256
  let result = false;
1192
1257
  try {
1193
- require2.resolve(`${packageName}/plugin.yaml`, { paths: [projectRoot] });
1258
+ require$1.resolve(`${packageName}/plugin.yaml`, { paths: [projectRoot] });
1194
1259
  try {
1195
- require2.resolve(`${packageName}/client`, { paths: [projectRoot] });
1260
+ require$1.resolve(`${packageName}/client`, { paths: [projectRoot] });
1196
1261
  result = true;
1197
1262
  } catch {
1198
1263
  result = false;
@@ -1230,12 +1295,9 @@ function transformImports(options) {
1230
1295
  let result = code;
1231
1296
  result = result.replace(IMPORT_REGEX, (match, clause, quote, source) => {
1232
1297
  const packageName = extractPackageName(source);
1233
- if (!packageName)
1234
- return match;
1235
- if (isSubpathImport(source, packageName))
1236
- return match;
1237
- if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot))
1238
- return match;
1298
+ if (!packageName) return match;
1299
+ if (isSubpathImport(source, packageName)) return match;
1300
+ if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot)) return match;
1239
1301
  hasChanges = true;
1240
1302
  const newSource = `${packageName}/client`;
1241
1303
  if (verbose) {
@@ -1247,12 +1309,9 @@ function transformImports(options) {
1247
1309
  });
1248
1310
  result = result.replace(EXPORT_FROM_REGEX, (match, clause, quote, source) => {
1249
1311
  const packageName = extractPackageName(source);
1250
- if (!packageName)
1251
- return match;
1252
- if (isSubpathImport(source, packageName))
1253
- return match;
1254
- if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot))
1255
- return match;
1312
+ if (!packageName) return match;
1313
+ if (isSubpathImport(source, packageName)) return match;
1314
+ if (!pluginDetector.isJayPluginWithClientExport(packageName, projectRoot)) return match;
1256
1315
  hasChanges = true;
1257
1316
  const newSource = `${packageName}/client`;
1258
1317
  if (verbose) {
@@ -1343,7 +1402,7 @@ function jayStackCompiler(options = {}) {
1343
1402
  // Second: Action import transformation (client builds only)
1344
1403
  // Uses resolveId + load to replace action modules with virtual modules
1345
1404
  // containing createActionCaller calls BEFORE bundling happens.
1346
- (() => {
1405
+ /* @__PURE__ */ (() => {
1347
1406
  let isSSRBuild = false;
1348
1407
  return {
1349
1408
  name: "jay-stack:action-transform",
@@ -1408,10 +1467,8 @@ function jayStackCompiler(options = {}) {
1408
1467
  const hasRegularActions = actions.some((a) => !a.isStreaming);
1409
1468
  const hasStreamActions = actions.some((a) => a.isStreaming);
1410
1469
  const importNames = [];
1411
- if (hasRegularActions)
1412
- importNames.push("createActionCaller");
1413
- if (hasStreamActions)
1414
- importNames.push("createStreamCaller");
1470
+ if (hasRegularActions) importNames.push("createActionCaller");
1471
+ if (hasStreamActions) importNames.push("createStreamCaller");
1415
1472
  const lines = [
1416
1473
  `import { ${importNames.join(", ")} } from '@jay-framework/stack-client-runtime';`,
1417
1474
  ""
@@ -1440,17 +1497,12 @@ function jayStackCompiler(options = {}) {
1440
1497
  // from component files in client builds. These are server-only
1441
1498
  // constructs that shouldn't appear in client bundles.
1442
1499
  transform(code, id, options2) {
1443
- if (options2?.ssr || isSSRBuild)
1444
- return null;
1445
- if (!id.endsWith(".ts") && !id.includes(".ts?"))
1446
- return null;
1447
- if (id.includes(".jay-html"))
1448
- return null;
1449
- if (isActionImport(id))
1450
- return null;
1500
+ if (options2?.ssr || isSSRBuild) return null;
1501
+ if (!id.endsWith(".ts") && !id.includes(".ts?")) return null;
1502
+ if (id.includes(".jay-html")) return null;
1503
+ if (isActionImport(id)) return null;
1451
1504
  const ACTION_BUILDERS = ["makeJayAction", "makeJayQuery", "makeJayStream"];
1452
- if (!ACTION_BUILDERS.some((b) => code.includes(b)))
1453
- return null;
1505
+ if (!ACTION_BUILDERS.some((b) => code.includes(b))) return null;
1454
1506
  return stripInlineActionBuilders(code, ACTION_BUILDERS);
1455
1507
  }
1456
1508
  };
@@ -1758,12 +1810,9 @@ class ServiceLifecycleManager {
1758
1810
  }
1759
1811
  }
1760
1812
  function deepMergeViewStates(base, overlay, trackByMap, path2 = "") {
1761
- if (!base && !overlay)
1762
- return {};
1763
- if (!base)
1764
- return overlay || {};
1765
- if (!overlay)
1766
- return base || {};
1813
+ if (!base && !overlay) return {};
1814
+ if (!base) return overlay || {};
1815
+ if (!overlay) return base || {};
1767
1816
  const result = {};
1768
1817
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(base), ...Object.keys(overlay)]);
1769
1818
  for (const key of allKeys) {
@@ -1897,8 +1946,7 @@ function createActionRouter(options) {
1897
1946
  );
1898
1947
  const tempDir = req._jayTempDir;
1899
1948
  const cleanup = () => {
1900
- if (tempDir)
1901
- cleanupTempDir(tempDir);
1949
+ if (tempDir) cleanupTempDir(tempDir);
1902
1950
  };
1903
1951
  if (registry.isStreaming(actionName)) {
1904
1952
  res.setHeader("Content-Type", "application/x-ndjson");
@@ -1962,8 +2010,7 @@ function getStatusCodeForError(code, isActionError) {
1962
2010
  function mergeDottedMultipartKeys(body) {
1963
2011
  const keys = Object.keys(body);
1964
2012
  for (const key of keys) {
1965
- if (!key.includes("."))
1966
- continue;
2013
+ if (!key.includes(".")) continue;
1967
2014
  const val = body[key];
1968
2015
  delete body[key];
1969
2016
  const parts = key.split(".");
@@ -1991,8 +2038,7 @@ function parseMultipart(req, tempDir) {
1991
2038
  headers: req.headers
1992
2039
  });
1993
2040
  bb.on("file", (fieldname, stream, info) => {
1994
- if (errored)
1995
- return;
2041
+ if (errored) return;
1996
2042
  fileCount++;
1997
2043
  const filename = info.filename || `upload-${fileCount}`;
1998
2044
  const tempPath = path$1.join(tempDir, `${fileCount}-${filename}`);
@@ -2027,8 +2073,7 @@ function parseMultipart(req, tempDir) {
2027
2073
  );
2028
2074
  });
2029
2075
  bb.on("field", (fieldname, value) => {
2030
- if (errored)
2031
- return;
2076
+ if (errored) return;
2032
2077
  if (fieldname === "_json") {
2033
2078
  try {
2034
2079
  jsonData = JSON.parse(value);
@@ -2039,8 +2084,7 @@ function parseMultipart(req, tempDir) {
2039
2084
  }
2040
2085
  });
2041
2086
  bb.on("close", () => {
2042
- if (errored)
2043
- return;
2087
+ if (errored) return;
2044
2088
  Promise.all(pendingWrites).then(() => {
2045
2089
  const body = { ...jsonData, ...files };
2046
2090
  mergeDottedMultipartKeys(body);
@@ -2164,8 +2208,7 @@ class FreezeStore {
2164
2208
  const files = await fs.readdir(this.dir);
2165
2209
  const entries = [];
2166
2210
  for (const file of files) {
2167
- if (!file.endsWith(".json"))
2168
- continue;
2211
+ if (!file.endsWith(".json")) continue;
2169
2212
  try {
2170
2213
  const content = await fs.readFile(path.join(this.dir, file), "utf-8");
2171
2214
  const entry = JSON.parse(content);
@@ -2184,8 +2227,7 @@ class FreezeStore {
2184
2227
  }
2185
2228
  async rename(id, name) {
2186
2229
  const entry = await this.get(id);
2187
- if (!entry)
2188
- return false;
2230
+ if (!entry) return false;
2189
2231
  entry.name = name;
2190
2232
  await fs.writeFile(
2191
2233
  path.join(this.dir, `${id}.json`),
@@ -2239,12 +2281,13 @@ class DevServerService {
2239
2281
  }
2240
2282
  return this.listRoutes();
2241
2283
  }
2242
- /** List all page routes in the project. */
2284
+ /** List all page routes in the project (includes dev-only plugin routes). */
2243
2285
  listRoutes() {
2244
2286
  return this.routes.map((r) => ({
2245
2287
  path: r.path,
2246
2288
  jayHtmlPath: r.fsRoute.jayHtmlPath,
2247
- compPath: r.fsRoute.compPath
2289
+ compPath: r.fsRoute.compPath,
2290
+ ...r.fsRoute.devOnly && { devOnly: true }
2248
2291
  }));
2249
2292
  }
2250
2293
  /**
@@ -2284,8 +2327,7 @@ async function scanPluginRoutes(projectRoot, projectRoutes) {
2284
2327
  const projectPaths = new Set(projectRoutes.map((r) => r.rawRoute));
2285
2328
  const pluginRoutes = [];
2286
2329
  for (const [, plugin] of plugins) {
2287
- if (!plugin.manifest.routes)
2288
- continue;
2330
+ if (!plugin.manifest.routes) continue;
2289
2331
  for (const route of plugin.manifest.routes) {
2290
2332
  if (projectPaths.has(route.path)) {
2291
2333
  getLogger().info(
@@ -2303,8 +2345,14 @@ async function scanPluginRoutes(projectRoot, projectRoutes) {
2303
2345
  const isLocalComponent = route.component.startsWith(".");
2304
2346
  const compPath = isLocalComponent ? path__default.resolve(plugin.pluginPath, route.component) : resolvePluginModule(plugin);
2305
2347
  const componentExport = isLocalComponent ? void 0 : route.component;
2306
- pluginRoutes.push(createRoute(route.path, jayHtmlPath, compPath, componentExport));
2307
- getLogger().info(`[Routes] Plugin "${plugin.name}" provides route ${route.path}`);
2348
+ pluginRoutes.push(
2349
+ createRoute(route.path, jayHtmlPath, compPath, componentExport, {
2350
+ devOnly: route.devOnly === true
2351
+ })
2352
+ );
2353
+ getLogger().info(
2354
+ `[Routes] Plugin "${plugin.name}" provides route ${route.path}${route.devOnly ? " (dev-only)" : ""}`
2355
+ );
2308
2356
  }
2309
2357
  }
2310
2358
  return pluginRoutes;
@@ -2346,8 +2394,7 @@ function resolvePluginModule(plugin) {
2346
2394
  const mainPath = typeof mainExport === "string" ? mainExport : mainExport?.default || mainExport?.import || pkg.main;
2347
2395
  if (mainPath) {
2348
2396
  const resolved = path__default.join(plugin.pluginPath, mainPath);
2349
- if (fsSync__default.existsSync(resolved))
2350
- return resolved;
2397
+ if (fsSync__default.existsSync(resolved)) return resolved;
2351
2398
  }
2352
2399
  } catch {
2353
2400
  }
@@ -2400,8 +2447,7 @@ function handleOtherResponseCodes(res, renderedResult) {
2400
2447
  res.status(renderedResult.status).end("server error");
2401
2448
  else if (renderedResult.kind === `ClientError`)
2402
2449
  res.status(renderedResult.status).end("client error");
2403
- else
2404
- res.status(renderedResult.status).end("redirect to " + renderedResult.location);
2450
+ else res.status(renderedResult.status).end("redirect to " + renderedResult.location);
2405
2451
  }
2406
2452
  function filterPluginsForPage(allPluginClientInits, allPluginsWithInit, usedPackages) {
2407
2453
  const pluginsByPackage = /* @__PURE__ */ new Map();
@@ -2418,8 +2464,7 @@ function filterPluginsForPage(allPluginClientInits, allPluginsWithInit, usedPack
2418
2464
  while (toProcess.length > 0) {
2419
2465
  const packageName = toProcess.pop();
2420
2466
  const plugin = pluginsByPackage.get(packageName);
2421
- if (!plugin)
2422
- continue;
2467
+ if (!plugin) continue;
2423
2468
  for (const dep of plugin.dependencies) {
2424
2469
  if (pluginsByPackage.has(dep) && !expandedPackages.has(dep)) {
2425
2470
  expandedPackages.add(dep);
@@ -2606,6 +2651,7 @@ async function handleCachedRequest(vite, route, options, cachedEntry, pageParams
2606
2651
  fastViewState,
2607
2652
  clientTrackByMap || {}
2608
2653
  );
2654
+ injectJayBindings(fullViewState, pageParams, url);
2609
2655
  await sendResponse(
2610
2656
  vite,
2611
2657
  res,
@@ -2803,6 +2849,7 @@ async function handleClientOnlyRequest(vite, route, options, slowlyPhase, pagePa
2803
2849
  renderedFast.rendered,
2804
2850
  serverTrackByMap || {}
2805
2851
  );
2852
+ injectJayBindings(viewState, pageParams, url);
2806
2853
  const fastCF = renderedFast.carryForward;
2807
2854
  const pageHtml = await generateClientScript(
2808
2855
  viewState,
@@ -2886,6 +2933,11 @@ async function sendResponse(vite, res, url, jayHtmlPath, sourceJayHtmlPath, page
2886
2933
  await fs__default.mkdir(clientScriptDir, { recursive: true });
2887
2934
  await fs__default.writeFile(path__default.join(clientScriptDir, `${pageName}.html`), pageHtml, "utf-8");
2888
2935
  }
2936
+ for (const [id, mod] of vite.moduleGraph.idToModuleMap) {
2937
+ if (id.includes("html-proxy")) {
2938
+ vite.moduleGraph.invalidateModule(mod);
2939
+ }
2940
+ }
2889
2941
  const viteStart = Date.now();
2890
2942
  const compiledPageHtml = await vite.transformIndexHtml(!!url ? url : "/", pageHtml);
2891
2943
  timing?.recordViteClient(Date.now() - viteStart);
@@ -2953,8 +3005,7 @@ async function preRenderJayHtml(route, slowViewState, headlessContracts, headles
2953
3005
  try {
2954
3006
  const contractContent = await fs__default.readFile(contractPath, "utf-8");
2955
3007
  const parseResult = parseContract(contractContent, path__default.basename(contractPath));
2956
- if (parseResult.val)
2957
- contract = parseResult.val;
3008
+ if (parseResult.val) contract = parseResult.val;
2958
3009
  } catch {
2959
3010
  }
2960
3011
  const result = slowRenderTransform({
@@ -3052,8 +3103,7 @@ async function mkDevServer(rawOptions) {
3052
3103
  try {
3053
3104
  const entries = await fs__default.readdir(buildFolder).catch(() => []);
3054
3105
  for (const entry of entries) {
3055
- if (entry === "freezes")
3056
- continue;
3106
+ if (entry === "freezes") continue;
3057
3107
  await fs__default.rm(path__default.join(buildFolder, entry), { recursive: true, force: true });
3058
3108
  }
3059
3109
  } catch {
@@ -3127,8 +3177,7 @@ async function mkDevServer(rawOptions) {
3127
3177
  const existingRawRoutes = new Set(devServerRoutes.map((r) => r.fsRoute.rawRoute));
3128
3178
  const added = [];
3129
3179
  for (const jayRoute of scannedJayRoutes) {
3130
- if (existingRawRoutes.has(jayRoute.rawRoute))
3131
- continue;
3180
+ if (existingRawRoutes.has(jayRoute.rawRoute)) continue;
3132
3181
  const devRoute = mkRoute(
3133
3182
  jayRoute,
3134
3183
  vite,
@@ -3230,6 +3279,13 @@ function setupFreezeEndpoint(vite, freezeStore) {
3230
3279
  });
3231
3280
  getLogger().info("[Freeze] Freeze endpoint mounted at /_jay/freeze");
3232
3281
  }
3282
+ function injectJayBindings(viewState, params, url) {
3283
+ const urlPath = url.split("?")[0];
3284
+ viewState.__jay = {
3285
+ params,
3286
+ url: { path: urlPath.startsWith("/") ? urlPath : "/" + urlPath }
3287
+ };
3288
+ }
3233
3289
  function getRouteDir(route) {
3234
3290
  return route.rawRoute.replace(/^\//, "") || "index";
3235
3291
  }
@@ -3238,8 +3294,7 @@ function getRoutePrefix(jayHtmlPath, pagesRootFolder) {
3238
3294
  const segments = rel.split(path__default.sep).filter(Boolean);
3239
3295
  const staticSegments = [];
3240
3296
  for (const seg of segments) {
3241
- if (seg.startsWith("["))
3242
- break;
3297
+ if (seg.startsWith("[")) break;
3243
3298
  staticSegments.push(seg);
3244
3299
  }
3245
3300
  return "/" + staticSegments.join("/");
@@ -3264,8 +3319,7 @@ function setupSlowRenderCacheInvalidation(vite, cache, pagesRootFolder, projectR
3264
3319
  getLogger().info(`[SlowRender] Watching: ${file}`);
3265
3320
  }
3266
3321
  if (routePrefix) {
3267
- if (!fileToRoutes.has(file))
3268
- fileToRoutes.set(file, /* @__PURE__ */ new Set());
3322
+ if (!fileToRoutes.has(file)) fileToRoutes.set(file, /* @__PURE__ */ new Set());
3269
3323
  fileToRoutes.get(file).add(routePrefix);
3270
3324
  }
3271
3325
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/dev-server",
3
- "version": "0.22.2",
3
+ "version": "0.23.1",
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.22.2",
27
- "@jay-framework/compiler-shared": "^0.22.2",
28
- "@jay-framework/component": "^0.22.2",
29
- "@jay-framework/fullstack-component": "^0.22.2",
30
- "@jay-framework/logger": "^0.22.2",
31
- "@jay-framework/runtime": "^0.22.2",
32
- "@jay-framework/stack-client-runtime": "^0.22.2",
33
- "@jay-framework/stack-route-scanner": "^0.22.2",
34
- "@jay-framework/stack-server-runtime": "^0.22.2",
35
- "@jay-framework/view-state-merge": "^0.22.2",
26
+ "@jay-framework/compiler-jay-stack": "^0.23.1",
27
+ "@jay-framework/compiler-shared": "^0.23.1",
28
+ "@jay-framework/component": "^0.23.1",
29
+ "@jay-framework/fullstack-component": "^0.23.1",
30
+ "@jay-framework/logger": "^0.23.1",
31
+ "@jay-framework/runtime": "^0.23.1",
32
+ "@jay-framework/stack-client-runtime": "^0.23.1",
33
+ "@jay-framework/stack-route-scanner": "^0.23.1",
34
+ "@jay-framework/stack-server-runtime": "^0.23.1",
35
+ "@jay-framework/view-state-merge": "^0.23.1",
36
36
  "busboy": "^1.6.0",
37
37
  "vite": "^5.0.11"
38
38
  },
39
39
  "devDependencies": {
40
- "@jay-framework/dev-environment": "^0.22.2",
41
- "@jay-framework/jay-cli": "^0.22.2",
42
- "@jay-framework/stack-client-runtime": "^0.22.2",
40
+ "@jay-framework/dev-environment": "^0.23.1",
41
+ "@jay-framework/jay-cli": "^0.23.1",
42
+ "@jay-framework/stack-client-runtime": "^0.23.1",
43
43
  "@playwright/test": "^1.58.2",
44
44
  "@types/busboy": "^1.5.4",
45
45
  "@types/express": "^5.0.2",