proteum 2.4.3 → 2.5.0

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 (74) hide show
  1. package/README.md +60 -55
  2. package/agents/project/AGENTS.md +112 -31
  3. package/agents/project/CODING_STYLE.md +2 -2
  4. package/agents/project/app-root/AGENTS.md +1 -3
  5. package/agents/project/client/AGENTS.md +1 -1
  6. package/agents/project/client/pages/AGENTS.md +21 -9
  7. package/agents/project/diagnostics.md +2 -2
  8. package/agents/project/optimizations.md +1 -1
  9. package/agents/project/root/AGENTS.md +105 -22
  10. package/agents/project/server/routes/AGENTS.md +30 -1
  11. package/agents/project/tests/AGENTS.md +1 -1
  12. package/cli/commands/doctor.ts +54 -3
  13. package/cli/commands/runtime.ts +6 -0
  14. package/cli/commands/worktree.ts +116 -0
  15. package/cli/compiler/artifacts/controllers.ts +16 -15
  16. package/cli/compiler/artifacts/discovery.ts +129 -17
  17. package/cli/compiler/artifacts/routing.ts +0 -5
  18. package/cli/compiler/artifacts/services.ts +253 -76
  19. package/cli/compiler/common/controllers.ts +159 -57
  20. package/cli/compiler/common/generatedRouteModules.ts +457 -363
  21. package/cli/mcp/router.ts +47 -3
  22. package/cli/presentation/commands.ts +25 -15
  23. package/cli/runtime/commands.ts +39 -12
  24. package/cli/runtime/worktreeBootstrap.ts +608 -0
  25. package/cli/scaffold/index.ts +28 -18
  26. package/cli/scaffold/templates.ts +44 -33
  27. package/cli/utils/agents.ts +14 -1
  28. package/client/services/router/index.tsx +23 -3
  29. package/client/services/router/request/api.ts +14 -4
  30. package/common/dev/contractsDoctor.ts +1 -1
  31. package/common/dev/mcpPayloads.ts +8 -1
  32. package/common/env/proteumEnv.ts +14 -2
  33. package/common/router/contracts.ts +1 -1
  34. package/common/router/definitions.ts +177 -0
  35. package/common/router/index.ts +23 -12
  36. package/common/router/pageData.ts +5 -5
  37. package/common/router/register.ts +2 -2
  38. package/common/router/request/api.ts +12 -2
  39. package/docs/agent-routing.md +5 -2
  40. package/docs/diagnostics.md +2 -0
  41. package/docs/mcp.md +6 -3
  42. package/eslint.js +36 -1
  43. package/package.json +1 -1
  44. package/server/app/commands.ts +5 -1
  45. package/server/app/container/console/http-client-error-context.test.cjs +10 -1
  46. package/server/app/container/console/index.ts +2 -1
  47. package/server/app/controller/index.ts +98 -40
  48. package/server/app/index.ts +92 -1
  49. package/server/app/service/index.ts +5 -1
  50. package/server/index.ts +6 -2
  51. package/server/services/router/index.ts +47 -38
  52. package/server/services/router/response/index.ts +2 -2
  53. package/tests/agents-utils.test.cjs +14 -1
  54. package/tests/cli-mcp-command.test.cjs +84 -0
  55. package/tests/definition-contracts.test.cjs +453 -0
  56. package/tests/dev-transpile-watch.test.cjs +37 -28
  57. package/tests/eslint-rules.test.cjs +39 -1
  58. package/tests/mcp.test.cjs +90 -0
  59. package/tests/worktree-bootstrap.test.cjs +206 -0
  60. package/types/aliases.d.ts +0 -5
  61. package/types/controller-input.test.ts +23 -17
  62. package/types/controller-request-context.test.ts +10 -11
  63. package/cli/commands/migrate.ts +0 -51
  64. package/cli/migrate/pageContract.ts +0 -516
  65. package/docs/migrate-from-2.1.3.md +0 -396
  66. package/scripts/cleanup-generated-controllers.ts +0 -62
  67. package/scripts/fix-reference-app-typing.ts +0 -490
  68. package/scripts/format-router-registrations.ts +0 -119
  69. package/scripts/migrate-explicit-controllers-and-request.ts +0 -423
  70. package/scripts/refactor-client-app-imports.ts +0 -244
  71. package/scripts/refactor-client-pages.ts +0 -587
  72. package/scripts/refactor-server-controllers.ts +0 -471
  73. package/scripts/refactor-server-runtime-aliases.ts +0 -360
  74. package/scripts/restore-client-app-import-files.ts +0 -41
@@ -50,6 +50,11 @@ type TResolvedImportSource = {
50
50
  sourceFilepath?: string;
51
51
  };
52
52
 
53
+ type TObjectLiteralFactoryDetails = {
54
+ object: ts.ObjectLiteralExpression;
55
+ localInitializers: Map<string, ts.Expression>;
56
+ };
57
+
53
58
  const coreServicesRoot = normalizeAbsolutePath(path.join(cli.paths.core.root, 'server', 'services'));
54
59
  const appServicesRoot = normalizeAbsolutePath(path.join(app.paths.root, 'server', 'services'));
55
60
  const coreServerRoot = normalizeAbsolutePath(path.join(cli.paths.core.root, 'server'));
@@ -111,7 +116,7 @@ const getDefaultExportClassDeclaration = (sourceFile: ts.SourceFile) => {
111
116
  }
112
117
 
113
118
  if (!defaultExportIdentifier) {
114
- throw new Error(`Expected ${sourceFile.fileName} to default-export an Application subclass.`);
119
+ throw new Error(`Expected ${sourceFile.fileName} to default-export a class.`);
115
120
  }
116
121
 
117
122
  const declaration = sourceFile.statements.find(
@@ -121,7 +126,7 @@ const getDefaultExportClassDeclaration = (sourceFile: ts.SourceFile) => {
121
126
 
122
127
  if (!declaration) {
123
128
  throw new Error(
124
- `Unable to resolve the default-exported Application class "${defaultExportIdentifier}" in ${sourceFile.fileName}.`,
129
+ `Unable to resolve the default-exported class "${defaultExportIdentifier}" in ${sourceFile.fileName}.`,
125
130
  );
126
131
  }
127
132
 
@@ -251,6 +256,125 @@ const getObjectLiteralProperty = (expression: ts.ObjectLiteralExpression, proper
251
256
  return getPropertyNameText(property.name) === propertyName;
252
257
  });
253
258
 
259
+ const collectConstInitializers = (sourceFile: ts.SourceFile) => {
260
+ const initializers = new Map<string, ts.Expression>();
261
+
262
+ for (const statement of sourceFile.statements) {
263
+ if (!ts.isVariableStatement(statement)) continue;
264
+ if (!(statement.declarationList.flags & ts.NodeFlags.Const)) continue;
265
+
266
+ for (const declaration of statement.declarationList.declarations) {
267
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
268
+
269
+ initializers.set(declaration.name.text, declaration.initializer);
270
+ }
271
+ }
272
+
273
+ return initializers;
274
+ };
275
+
276
+ const resolveLocalIdentifierExpression = (
277
+ expression: ts.Expression,
278
+ constInitializers: Map<string, ts.Expression>,
279
+ ) => {
280
+ const unwrappedExpression = unwrapExpression(expression);
281
+ if (!ts.isIdentifier(unwrappedExpression)) return unwrappedExpression;
282
+
283
+ return constInitializers.get(unwrappedExpression.text) || unwrappedExpression;
284
+ };
285
+
286
+ const getDefaultExportExpression = (sourceFile: ts.SourceFile) => {
287
+ const constInitializers = collectConstInitializers(sourceFile);
288
+
289
+ for (const statement of sourceFile.statements) {
290
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals) continue;
291
+
292
+ return resolveLocalIdentifierExpression(statement.expression, constInitializers);
293
+ }
294
+
295
+ return undefined;
296
+ };
297
+
298
+ const getCallExpressionName = (expression: ts.Expression) => {
299
+ if (ts.isIdentifier(expression)) return expression.text;
300
+ if (ts.isPropertyAccessExpression(expression)) return expression.name.text;
301
+ return undefined;
302
+ };
303
+
304
+ const getObjectLiteralFromFactory = (expression: ts.Expression): ts.ObjectLiteralExpression | undefined => {
305
+ return getObjectLiteralFactoryDetails(expression)?.object;
306
+ };
307
+
308
+ const getExpressionFromFactory = (expression: ts.Expression): ts.Expression => {
309
+ const unwrappedExpression = unwrapExpression(expression);
310
+
311
+ if (ts.isArrowFunction(unwrappedExpression) || ts.isFunctionExpression(unwrappedExpression)) {
312
+ const body = unwrappedExpression.body;
313
+ if (!ts.isBlock(body)) return unwrapExpression(body);
314
+
315
+ for (const statement of body.statements) {
316
+ if (!ts.isReturnStatement(statement) || !statement.expression) continue;
317
+
318
+ return unwrapExpression(statement.expression);
319
+ }
320
+ }
321
+
322
+ return unwrappedExpression;
323
+ };
324
+
325
+ const getObjectLiteralFactoryDetails = (expression: ts.Expression): TObjectLiteralFactoryDetails | undefined => {
326
+ const unwrappedExpression = unwrapExpression(expression);
327
+
328
+ if (ts.isObjectLiteralExpression(unwrappedExpression)) {
329
+ return { object: unwrappedExpression, localInitializers: new Map() };
330
+ }
331
+
332
+ if (ts.isArrowFunction(unwrappedExpression) || ts.isFunctionExpression(unwrappedExpression)) {
333
+ const body = unwrapExpression(unwrappedExpression.body as ts.Expression);
334
+
335
+ if (ts.isObjectLiteralExpression(body)) {
336
+ return { object: body, localInitializers: new Map() };
337
+ }
338
+
339
+ if (ts.isBlock(unwrappedExpression.body)) {
340
+ const localInitializers = new Map<string, ts.Expression>();
341
+
342
+ for (const statement of unwrappedExpression.body.statements) {
343
+ if (ts.isVariableStatement(statement) && statement.declarationList.flags & ts.NodeFlags.Const) {
344
+ for (const declaration of statement.declarationList.declarations) {
345
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
346
+
347
+ localInitializers.set(declaration.name.text, declaration.initializer);
348
+ }
349
+ continue;
350
+ }
351
+
352
+ if (!ts.isReturnStatement(statement) || !statement.expression) continue;
353
+
354
+ const returnExpression = unwrapExpression(statement.expression);
355
+ if (ts.isObjectLiteralExpression(returnExpression)) {
356
+ return { object: returnExpression, localInitializers };
357
+ }
358
+ }
359
+ }
360
+ }
361
+
362
+ return undefined;
363
+ };
364
+
365
+ const getDefaultDefineApplicationObject = (sourceFile: ts.SourceFile) => {
366
+ const expression = getDefaultExportExpression(sourceFile);
367
+ if (!expression || !ts.isCallExpression(expression)) return undefined;
368
+ if (getCallExpressionName(expression.expression) !== 'defineApplication') return undefined;
369
+
370
+ const [definitionArg] = [...expression.arguments];
371
+ if (!definitionArg || !ts.isObjectLiteralExpression(definitionArg)) {
372
+ throw new Error(`defineApplication(...) in ${sourceFile.fileName} must receive an object literal.`);
373
+ }
374
+
375
+ return definitionArg;
376
+ };
377
+
254
378
  const readNumericLiteral = (expression: ts.Expression) => {
255
379
  const unwrappedExpression = unwrapExpression(expression);
256
380
 
@@ -398,8 +522,13 @@ const parseServiceInstantiation = (
398
522
  imports: Map<string, TImportedBinding>,
399
523
  sourceFilepath: string,
400
524
  configArgIndex: number,
525
+ localInitializers = new Map<string, ts.Expression>(),
401
526
  ): TParsedService | undefined => {
402
- const unwrappedExpression = unwrapExpression(expression);
527
+ const factoryExpression = getExpressionFromFactory(expression);
528
+ const unwrappedExpression =
529
+ ts.isIdentifier(factoryExpression) && localInitializers.has(factoryExpression.text)
530
+ ? getExpressionFromFactory(localInitializers.get(factoryExpression.text)!)
531
+ : factoryExpression;
403
532
  if (!ts.isNewExpression(unwrappedExpression)) return undefined;
404
533
 
405
534
  const resolvedService = resolveImportedService(unwrappedExpression.expression, imports, sourceFilepath);
@@ -447,40 +576,122 @@ const extractRouterPlugins = (
447
576
  return routerPlugins;
448
577
  };
449
578
 
450
- const parseAppBootstrap = (): TParsedAppBootstrap => {
451
- const sourceFile = createSourceFile(getAppServerEntryFilepath());
452
- const imports = buildImportIndex(sourceFile);
453
- const appClass = getDefaultExportClassDeclaration(sourceFile);
579
+ const parseRootServiceObject = (
580
+ servicesObject: ts.ObjectLiteralExpression | undefined,
581
+ imports: Map<string, TImportedBinding>,
582
+ sourceFilepath: string,
583
+ localInitializers = new Map<string, ts.Expression>(),
584
+ ) => {
585
+ if (!servicesObject) return [];
454
586
 
455
587
  const rootServices: TParsedService[] = [];
456
- let routerPlugins: TParsedService[] = [];
457
588
 
458
- for (const member of appClass.members) {
459
- if (!ts.isPropertyDeclaration(member) || !member.initializer) continue;
589
+ for (const property of servicesObject.properties) {
590
+ if (!ts.isPropertyAssignment(property)) continue;
460
591
 
461
- const registeredName = getPropertyNameText(member.name);
592
+ const registeredName = getPropertyNameText(property.name);
462
593
  if (!registeredName) continue;
463
594
 
464
- const rootService = parseServiceInstantiation(registeredName, member.initializer, imports, sourceFile.fileName, 1);
595
+ const initializer =
596
+ ts.isIdentifier(unwrapExpression(property.initializer)) &&
597
+ localInitializers.has((unwrapExpression(property.initializer) as ts.Identifier).text)
598
+ ? localInitializers.get((unwrapExpression(property.initializer) as ts.Identifier).text)!
599
+ : property.initializer;
600
+ const rootService = parseServiceInstantiation(registeredName, initializer, imports, sourceFilepath, 1);
465
601
  if (!rootService) continue;
466
602
 
467
603
  rootServices.push(rootService);
604
+ }
468
605
 
469
- if (rootService.importPath === '@server/services/router') {
470
- const initializer = unwrapExpression(member.initializer);
471
- if (!ts.isNewExpression(initializer)) continue;
606
+ return rootServices;
607
+ };
472
608
 
609
+ const parseDefineApplicationBootstrap = (
610
+ sourceFile: ts.SourceFile,
611
+ imports: Map<string, TImportedBinding>,
612
+ ): TParsedAppBootstrap | undefined => {
613
+ const topLevelInitializers = collectConstInitializers(sourceFile);
614
+ const definitionArg = getDefaultDefineApplicationObject(sourceFile);
615
+ if (!definitionArg) return undefined;
616
+
617
+ const servicesProperty = getObjectLiteralProperty(definitionArg, 'services');
618
+ const servicesDetails =
619
+ servicesProperty && ts.isPropertyAssignment(servicesProperty)
620
+ ? getObjectLiteralFactoryDetails(servicesProperty.initializer)
621
+ : undefined;
622
+ const servicesObject = servicesDetails?.object;
623
+ const localServiceInitializers = servicesDetails?.localInitializers || new Map<string, ts.Expression>();
624
+ const rootServices = parseRootServiceObject(servicesObject, imports, sourceFile.fileName, localServiceInitializers);
625
+ const routerProperty = getObjectLiteralProperty(definitionArg, 'router');
626
+
627
+ if (routerProperty && ts.isPropertyAssignment(routerProperty)) {
628
+ const routerService = parseServiceInstantiation(
629
+ 'Router',
630
+ routerProperty.initializer,
631
+ imports,
632
+ sourceFile.fileName,
633
+ 1,
634
+ topLevelInitializers,
635
+ );
636
+ if (routerService && !rootServices.some((service) => service.registeredName === 'Router')) {
637
+ rootServices.push(routerService);
638
+ }
639
+ }
640
+
641
+ const routerService = rootServices.find((rootService) => rootService.importPath === '@server/services/router');
642
+ let routerPlugins: TParsedService[] = [];
643
+
644
+ if (routerService?.registeredName === 'Router') {
645
+ const routerExpression =
646
+ servicesObject &&
647
+ servicesObject.properties
648
+ .filter((property): property is ts.PropertyAssignment => ts.isPropertyAssignment(property))
649
+ .find((property) => getPropertyNameText(property.name) === 'Router')?.initializer;
650
+
651
+ const routerInitializer =
652
+ routerExpression ||
653
+ (routerProperty && ts.isPropertyAssignment(routerProperty) ? routerProperty.initializer : undefined);
654
+ const unwrappedRouterInitializer = routerInitializer ? getExpressionFromFactory(routerInitializer) : undefined;
655
+ const initializer =
656
+ unwrappedRouterInitializer &&
657
+ ts.isIdentifier(unwrappedRouterInitializer) &&
658
+ (localServiceInitializers.has(unwrappedRouterInitializer.text) ||
659
+ topLevelInitializers.has(unwrappedRouterInitializer.text))
660
+ ? getExpressionFromFactory(
661
+ (localServiceInitializers.get(unwrappedRouterInitializer.text) ||
662
+ topLevelInitializers.get(unwrappedRouterInitializer.text))!,
663
+ )
664
+ : unwrappedRouterInitializer;
665
+
666
+ if (initializer && ts.isNewExpression(initializer)) {
473
667
  routerPlugins = extractRouterPlugins(initializer.arguments?.[1], imports, sourceFile.fileName);
474
668
  }
475
669
  }
476
670
 
477
- if (rootServices.length === 0) {
671
+ return { rootServices, routerPlugins };
672
+ };
673
+
674
+ export const parseAppBootstrapSource = (sourceFilepath: string): TParsedAppBootstrap => {
675
+ const sourceFile = createSourceFile(sourceFilepath);
676
+ const imports = buildImportIndex(sourceFile);
677
+ const definitionBootstrap = parseDefineApplicationBootstrap(sourceFile, imports);
678
+
679
+ if (!definitionBootstrap) {
680
+ throw new Error(
681
+ `${sourceFile.fileName} must default-export defineApplication({ services, router, models, commands }). ` +
682
+ 'Application subclasses are no longer supported.',
683
+ );
684
+ }
685
+
686
+ if (definitionBootstrap.rootServices.length === 0) {
478
687
  throw new Error(`No root services were found in ${sourceFile.fileName}.`);
479
688
  }
480
689
 
481
- return { rootServices, routerPlugins };
690
+ return definitionBootstrap;
482
691
  };
483
692
 
693
+ const parseAppBootstrap = (): TParsedAppBootstrap => parseAppBootstrapSource(getAppServerEntryFilepath());
694
+
484
695
  const commandServiceSearchRoots = [
485
696
  { root: coreServicesRoot, prefix: '@server/services/' },
486
697
  { root: appServicesRoot, prefix: '@/server/services/' },
@@ -652,7 +863,7 @@ const createCommandServiceStubDeclarations = (rootServices: TParsedService[]): T
652
863
  stubs.set(
653
864
  source.aliasImportPath,
654
865
  `declare class ${getStubTypeName(source)} {
655
- app: import("@/server/index").default;
866
+ app: InstanceType<typeof import("@/server/index").default>;
656
867
  [key: string]: any;
657
868
  }`,
658
869
  );
@@ -660,7 +871,7 @@ const createCommandServiceStubDeclarations = (rootServices: TParsedService[]): T
660
871
  }
661
872
 
662
873
  const className = getStubTypeName(source);
663
- const classMembers = [` app: import("@/server/index").default;`];
874
+ const classMembers = [` app: InstanceType<typeof import("@/server/index").default>;`];
664
875
 
665
876
  for (const member of defaultClass.members) {
666
877
  if (isPrivateOrProtectedInstanceMember(member)) continue;
@@ -714,12 +925,12 @@ ${classMembers.join('\n')}
714
925
  const isNamespaceImportDeclaration = (statement: ts.ImportDeclaration) =>
715
926
  statement.importClause?.namedBindings !== undefined && ts.isNamespaceImport(statement.importClause.namedBindings);
716
927
 
717
- const isClientServerStubSupportStatement = (statement: ts.Statement, appClassIdentifier: string) => {
928
+ const isClientServerStubSupportStatement = (statement: ts.Statement, appIdentifier: string) => {
718
929
  if (ts.isTypeAliasDeclaration(statement)) {
719
930
  return !new Set([
720
- `${appClassIdentifier}Disks`,
721
- `${appClassIdentifier}Router`,
722
- `${appClassIdentifier}RouterPlugins`,
931
+ `${appIdentifier}Disks`,
932
+ `${appIdentifier}Router`,
933
+ `${appIdentifier}RouterPlugins`,
723
934
  ]).has(statement.name.text);
724
935
  }
725
936
 
@@ -728,7 +939,6 @@ const isClientServerStubSupportStatement = (statement: ts.Statement, appClassIde
728
939
 
729
940
  const createClientServerIndexDeclaration = (rootServices: TParsedService[]) => {
730
941
  const sourceFile = createSourceFile(getAppServerEntryFilepath());
731
- const appClass = getDefaultExportClassDeclaration(sourceFile);
732
942
  const serviceTypesByRegisteredName = new Map(
733
943
  rootServices.map((service) => [service.registeredName, `import("${service.importPath}").default`] as const),
734
944
  );
@@ -738,26 +948,19 @@ const createClientServerIndexDeclaration = (rootServices: TParsedService[]) => {
738
948
  .filter((statement) => !isNamespaceImportDeclaration(statement))
739
949
  .map((statement) => statement.getText(sourceFile));
740
950
  const supportStatements = sourceFile.statements
741
- .slice(0, sourceFile.statements.indexOf(appClass))
742
951
  .filter((statement) => isClientServerStubSupportStatement(statement, app.identity.identifier))
743
952
  .map((statement) => statement.getText(sourceFile));
744
- const heritageClauses = appClass.heritageClauses?.map((clause) => clause.getText(sourceFile)).join(' ');
745
- const properties = appClass.members
746
- .filter((member): member is ts.PropertyDeclaration => ts.isPropertyDeclaration(member))
747
- .filter((member) => !isPrivateOrProtectedInstanceMember(member))
748
- .map((property) => {
749
- const propertyName = getPropertyNameText(property.name);
750
- if (!propertyName) return undefined;
751
-
953
+ const properties = rootServices
954
+ .map((service) => {
752
955
  const propertyType =
753
- propertyName === 'Disks'
956
+ service.registeredName === 'Disks'
754
957
  ? 'object'
755
- : propertyName === 'Router'
958
+ : service.registeredName === 'Router'
756
959
  ? `${app.identity.identifier}Router`
757
- : property.type?.getText(sourceFile) || serviceTypesByRegisteredName.get(propertyName);
960
+ : serviceTypesByRegisteredName.get(service.registeredName);
758
961
  if (!propertyType) return undefined;
759
962
 
760
- return ` public ${propertyName}: ${propertyType};`;
963
+ return ` public ${service.registeredName}: ${propertyType};`;
761
964
  })
762
965
  .filter((property): property is string => property !== undefined);
763
966
 
@@ -767,7 +970,7 @@ ${supportStatements.join('\n\n')}
767
970
 
768
971
  type ${app.identity.identifier}Router = Router<${app.identity.identifier}>;
769
972
 
770
- export default class ${app.identity.identifier}${heritageClauses ? ` ${heritageClauses}` : ''} {
973
+ export default class ${app.identity.identifier} {
771
974
  ${properties.join('\n')}
772
975
  }
773
976
  `;
@@ -786,7 +989,7 @@ const resolveManifestService = (service: TParsedService, parent: string): TProte
786
989
 
787
990
  export const generateServiceArtifacts = () => {
788
991
  const { rootServices, routerPlugins } = parseAppBootstrap();
789
- const appClassIdentifier = app.identity.identifier;
992
+ const appIdentifier = app.identity.identifier;
790
993
  const containerServices = app.containerServices.map((serviceName) => "'" + serviceName + "'").join('|');
791
994
  const appServices = rootServices.map((service) => resolveManifestService(service, 'app'));
792
995
  const routerPluginServices = routerPlugins.map((service) => resolveManifestService(service, 'Router.plugins'));
@@ -799,15 +1002,7 @@ export const generateServiceArtifacts = () => {
799
1002
 
800
1003
  writeIfChanged(
801
1004
  path.join(app.paths.client.generated, 'services.d.ts'),
802
- `declare type ${appClassIdentifier} = import("@/server/index").default;
803
-
804
- declare module "@app" {
805
-
806
- import { ${appClassIdentifier} as ${appClassIdentifier}Client } from "@/client";
807
-
808
- export const Router: ${appClassIdentifier}Client['Router'];
809
-
810
- }
1005
+ `declare type ${appIdentifier} = InstanceType<typeof import("@/server/index").default>;
811
1006
 
812
1007
  declare module '@models/types' {
813
1008
  export * from '@generated/client/models';
@@ -841,12 +1036,12 @@ declare namespace preact.JSX {
841
1036
 
842
1037
  writeIfChanged(
843
1038
  path.join(app.paths.client.generated, 'context.ts'),
844
- `// TODO: move it into core (but how to make sure usecontext returns ${appClassIdentifier}'s context ?)
1039
+ `// TODO: move it into core (but how to make sure usecontext returns ${appIdentifier}'s context ?)
845
1040
  import React from 'react';
846
1041
 
847
- import type ${appClassIdentifier}Client from '@/client/index';
1042
+ import type ${appIdentifier}Client from '@/client/index';
848
1043
 
849
- export type ClientContext = ${appClassIdentifier}Client["Router"]["context"];
1044
+ export type ClientContext = ${appIdentifier}Client["Router"]["context"];
850
1045
 
851
1046
  type GlobalClientContextStore = typeof globalThis & {
852
1047
  __proteumClientContexts?: Record<string, React.Context<ClientContext | undefined>>;
@@ -856,14 +1051,14 @@ const globalClientContextStore = globalThis as GlobalClientContextStore;
856
1051
  const clientContexts = (globalClientContextStore.__proteumClientContexts ??= {});
857
1052
 
858
1053
  export const ReactClientContext =
859
- clientContexts['${appClassIdentifier}'] ?? (clientContexts['${appClassIdentifier}'] = React.createContext<ClientContext | undefined>(undefined));
1054
+ clientContexts['${appIdentifier}'] ?? (clientContexts['${appIdentifier}'] = React.createContext<ClientContext | undefined>(undefined));
860
1055
  export default (): ClientContext => {
861
1056
  const context = React.useContext<ClientContext | undefined>(ReactClientContext);
862
1057
  if (context) return context;
863
1058
 
864
1059
  throw new Error(
865
1060
  'Proteum router context hook was called outside the App provider. This is a framework contract failure. ' +
866
- 'Likely fix: move the hook back under Router.page render ownership or pass the required values explicitly. ' +
1061
+ 'Likely fix: move the hook back under definePageRoute render ownership or pass the required values explicitly. ' +
867
1062
  'Re-check both SSR and client navigation after the fix.',
868
1063
  );
869
1064
  };`,
@@ -871,7 +1066,7 @@ export default (): ClientContext => {
871
1066
 
872
1067
  writeIfChanged(
873
1068
  path.join(app.paths.common.generated, 'services.d.ts'),
874
- `declare type ${appClassIdentifier} = import("@/server/index").default;
1069
+ `declare type ${appIdentifier} = InstanceType<typeof import("@/server/index").default>;
875
1070
 
876
1071
  declare module '@models/types' {
877
1072
  export * from '@generated/common/models';
@@ -888,7 +1083,7 @@ declare module '@models/types' {
888
1083
 
889
1084
  writeIfChanged(
890
1085
  path.join(app.paths.server.generated, 'commands.d.ts'),
891
- `declare type ${appClassIdentifier} = import("@/server/index").default;
1086
+ `declare type ${appIdentifier} = InstanceType<typeof import("@/server/index").default>;
892
1087
 
893
1088
  declare module "@models/types" {
894
1089
  const Models: any;
@@ -903,7 +1098,7 @@ export {};
903
1098
  path.join(app.paths.server.generated, 'commands.app.d.ts'),
904
1099
  `${commandServiceStubs.declarations}
905
1100
 
906
- declare class ${appClassIdentifier} implements import("@server/app/commands").TCommandApplication {
1101
+ declare class ${appIdentifier} implements import("@server/app/commands").TCommandApplication {
907
1102
  env: import("@server/app/commands").TCommandApplication["env"];
908
1103
  identity: import("@server/app/commands").TCommandApplication["identity"];
909
1104
  getRootServices: import("@server/app/commands").TCommandApplication["getRootServices"];
@@ -920,7 +1115,7 @@ ${rootServices
920
1115
  .join('\n')}
921
1116
  }
922
1117
 
923
- export default ${appClassIdentifier};
1118
+ export default ${appIdentifier};
924
1119
  `,
925
1120
  );
926
1121
 
@@ -932,25 +1127,7 @@ export default ${appClassIdentifier};
932
1127
 
933
1128
  writeIfChanged(
934
1129
  path.join(app.paths.server.generated, 'services.d.ts'),
935
- `type InstalledServices = import("@server/app").RootServicesOf<import("@/server/index").default>;
936
-
937
- declare type ${appClassIdentifier} = import("@/server/index").default;
938
-
939
- declare module "@app" {
940
-
941
- import { ApplicationContainer } from '@server/app/container';
942
-
943
- const ServerServices: (
944
- Pick<
945
- ApplicationContainer<InstalledServices>,
946
- ${containerServices}
947
- >
948
- &
949
- ${appClassIdentifier}
950
- )
951
-
952
- export = ServerServices
953
- }
1130
+ `declare type ${appIdentifier} = InstanceType<typeof import("@/server/index").default>;
954
1131
 
955
1132
  declare module '@common/errors' {
956
1133