@taujs/create-taujs 0.4.0 → 0.6.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.
- package/dist/index.js +78 -37
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26,12 +26,12 @@ function generateClaudeMd() {
|
|
|
26
26
|
|
|
27
27
|
This project runs a \u03C4js MCP server (\`taujs-mcp\`, wired in \`.mcp.json\`). **Prefer its
|
|
28
28
|
tools over reading \`taujs.config.ts\` or server internals by hand** \u2014 they answer from the
|
|
29
|
-
emitted request graph and live request
|
|
29
|
+
emitted request graph and live request episodes:
|
|
30
30
|
|
|
31
31
|
- Start with \`taujs_overview\`; use \`taujs_list_routes\` / \`taujs_get_route\` /
|
|
32
32
|
\`taujs_explain_route\` for structure.
|
|
33
33
|
- \`taujs_who_calls_service\` maps route \u2192 service edges (labelled declared vs observed).
|
|
34
|
-
- Live behaviour: \`
|
|
34
|
+
- Live behaviour: \`taujs_get_recent_episodes\` \u2192 \`taujs_get_episode\` \u2192 \`taujs_get_episode_logs\`
|
|
35
35
|
(requires the dev server: \`pnpm dev\`). \`taujs_doctor\` summarises problems.
|
|
36
36
|
|
|
37
37
|
Tool responses cite staleness and label every joined fact's source. Field values in
|
|
@@ -273,6 +273,9 @@ function planFiles(config) {
|
|
|
273
273
|
{ path: "CLAUDE.md", content: generateClaudeMd() },
|
|
274
274
|
{ path: "src/client/index.html", content: generateIndexHtml() },
|
|
275
275
|
{ path: "src/client/styles.css", content: generateStyles() },
|
|
276
|
+
// The derived type contract (framework-independent): AppData/AppRouteContext come from
|
|
277
|
+
// taujs.config.ts, so client code never hand-writes a payload shape.
|
|
278
|
+
{ path: "src/client/app-types.ts", content: generateAppTypes() },
|
|
276
279
|
// server (framework-independent — a single shared source)
|
|
277
280
|
{ path: "src/server/index.ts", content: generateServerIndex() },
|
|
278
281
|
{ path: "src/server/services/registry.ts", content: generateServiceRegistry() },
|
|
@@ -483,7 +486,15 @@ import { reactRenderer } from '@taujs/react/renderer';`;
|
|
|
483
486
|
renderer: vueRenderer(),` : framework === "solid" ? `
|
|
484
487
|
renderer: solidRenderer({ project: './tsconfig.solid.json' }),` : `
|
|
485
488
|
renderer: reactRenderer({ project: './tsconfig.json' }),`;
|
|
486
|
-
return `import { defineConfig } from '@taujs/server/config';${rendererImport}
|
|
489
|
+
return `import { createServiceData, defineConfig } from '@taujs/server/config';${rendererImport}
|
|
490
|
+
|
|
491
|
+
import type { ServiceRegistry } from './src/server/services/registry.ts';
|
|
492
|
+
|
|
493
|
+
// Registry-typed service declarations: the helper carries each method's RESULT type into
|
|
494
|
+
// RouteData, so the app's types derive from this file instead of being hand-written
|
|
495
|
+
// (see src/client/app-types.ts). Closure handlers and ctx.call remain available for dynamic
|
|
496
|
+
// dispatch - https://taujs.dev/guides/services/
|
|
497
|
+
const serviceData = createServiceData<ServiceRegistry>();
|
|
487
498
|
|
|
488
499
|
export default defineConfig({
|
|
489
500
|
server: {
|
|
@@ -507,10 +518,8 @@ export default defineConfig({
|
|
|
507
518
|
attr: {
|
|
508
519
|
render: 'ssr',
|
|
509
520
|
hydrate: true,
|
|
510
|
-
//
|
|
511
|
-
data:
|
|
512
|
-
return ctx.call('example', 'greet', { name: 'SSR' });
|
|
513
|
-
},
|
|
521
|
+
// Declared service edge: RouteData<typeof config, '/'> is greet()'s resolved result
|
|
522
|
+
data: serviceData('example', 'greet', () => ({ name: 'SSR' })),
|
|
514
523
|
},
|
|
515
524
|
},
|
|
516
525
|
{
|
|
@@ -518,12 +527,8 @@ export default defineConfig({
|
|
|
518
527
|
attr: {
|
|
519
528
|
render: 'streaming',
|
|
520
529
|
hydrate: true,
|
|
521
|
-
//
|
|
522
|
-
data:
|
|
523
|
-
args: { name: 'Streaming' },
|
|
524
|
-
serviceName: 'example',
|
|
525
|
-
serviceMethod: 'greet',
|
|
526
|
-
}),
|
|
530
|
+
// The same declared edge on a streaming route: the shell streams while greet() resolves
|
|
531
|
+
data: serviceData('example', 'greet', () => ({ name: 'Streaming' })),
|
|
527
532
|
// meta recommended for streaming routes for SEO/social and render timing
|
|
528
533
|
meta: {
|
|
529
534
|
title: "\u03C4js \u2014 Streaming",
|
|
@@ -584,8 +589,10 @@ function generateReadme(projectName, packageManager, framework) {
|
|
|
584
589
|
const clientTree = framework === "vue" ? `\u2502 \u2502 \u251C\u2500\u2500 App.vue # Root component (route switch)
|
|
585
590
|
\u2502 \u2502 \u251C\u2500\u2500 HomePage.vue # SSR route (useSSRData + v-if)
|
|
586
591
|
\u2502 \u2502 \u251C\u2500\u2500 StreamingPage.vue # Streaming route (await useSSRDataAsync)
|
|
592
|
+
\u2502 \u2502 \u251C\u2500\u2500 app-types.ts # Types derived from taujs.config.ts
|
|
587
593
|
\u2502 \u2502 \u251C\u2500\u2500 entry-client.ts # Client hydration entry
|
|
588
594
|
\u2502 \u2502 \u251C\u2500\u2500 entry-server.ts # SSR render entry` : `\u2502 \u2502 \u251C\u2500\u2500 App.tsx # Root component
|
|
595
|
+
\u2502 \u2502 \u251C\u2500\u2500 app-types.ts # Types derived from taujs.config.ts
|
|
589
596
|
\u2502 \u2502 \u251C\u2500\u2500 entry-client.tsx # Client hydration entry
|
|
590
597
|
\u2502 \u2502 \u251C\u2500\u2500 entry-server.tsx # SSR render entry`;
|
|
591
598
|
const mainUi = framework === "vue" ? "App.vue" : "App.tsx";
|
|
@@ -680,13 +687,11 @@ import { useSSRStore } from '@taujs/react';
|
|
|
680
687
|
|
|
681
688
|
import "./styles.css";
|
|
682
689
|
|
|
683
|
-
type
|
|
684
|
-
message: string;
|
|
685
|
-
timestamp: string;
|
|
686
|
-
};
|
|
690
|
+
import type { AppData } from './app-types';
|
|
687
691
|
|
|
688
692
|
function GreetingCard() {
|
|
689
|
-
|
|
693
|
+
// AppData is derived from taujs.config.ts - greet()'s result, never hand-written.
|
|
694
|
+
const data = useSSRStore<AppData>();
|
|
690
695
|
|
|
691
696
|
return (
|
|
692
697
|
<section className="card card--primary">
|
|
@@ -740,9 +745,9 @@ export function App() {
|
|
|
740
745
|
which is ideal for predictable latency and caching.
|
|
741
746
|
</p>
|
|
742
747
|
<p>
|
|
743
|
-
<strong>STREAM:</strong> The <code>/streaming</code> route
|
|
744
|
-
|
|
745
|
-
a fallback while the server resolves it, then progressively streams the final content.
|
|
748
|
+
<strong>STREAM:</strong> The <code>/streaming</code> route declares the same typed
|
|
749
|
+
service edge with streaming rendering. The <code><Suspense></code> boundary above
|
|
750
|
+
shows a fallback while the server resolves it, then progressively streams the final content.
|
|
746
751
|
</p>
|
|
747
752
|
</section>
|
|
748
753
|
|
|
@@ -980,6 +985,33 @@ code {
|
|
|
980
985
|
text-align: center;
|
|
981
986
|
}`;
|
|
982
987
|
}
|
|
988
|
+
function generateAppTypes() {
|
|
989
|
+
return `/**
|
|
990
|
+
* The application's type contract, DERIVED from taujs.config.ts - never hand-written.
|
|
991
|
+
* Every import here is type-only, so nothing from the config or server reaches the client bundle.
|
|
992
|
+
*/
|
|
993
|
+
import type config from '../../taujs.config.ts';
|
|
994
|
+
import type { RouteContext, RouteData } from '@taujs/server/config';
|
|
995
|
+
|
|
996
|
+
/** The route-discriminated context the host passes to appComponent and headContent. */
|
|
997
|
+
export type AppRouteContext = RouteContext<typeof config>;
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* The union of every declared route's resolved data - both scaffold routes resolve greet(), so
|
|
1001
|
+
* one shared type serves the whole app.
|
|
1002
|
+
*
|
|
1003
|
+
* A declared route WITHOUT \`attr.data\` contributes \`Record<string, undefined>\` (the server
|
|
1004
|
+
* supplies \`{}\` for it), so the union stays usable when such routes exist: reads become
|
|
1005
|
+
* \`T | undefined\`, making code account for the no-data route. When routes diverge further,
|
|
1006
|
+
* narrow per route with the derived aliases below - still from the config, never hand-written.
|
|
1007
|
+
*/
|
|
1008
|
+
export type AppData = RouteData<typeof config>;
|
|
1009
|
+
|
|
1010
|
+
// Optional narrowing when routes diverge:
|
|
1011
|
+
// export type HomeData = RouteData<typeof config, '/'>;
|
|
1012
|
+
// export type StreamingData = RouteData<typeof config, '/streaming'>;
|
|
1013
|
+
`;
|
|
1014
|
+
}
|
|
983
1015
|
function generateViteEnv() {
|
|
984
1016
|
return `/// <reference types="vite/client" />
|
|
985
1017
|
`;
|
|
@@ -1070,13 +1102,11 @@ function generateHomePageVue() {
|
|
|
1070
1102
|
return `<script setup lang="ts">
|
|
1071
1103
|
import { useSSRData } from '@taujs/vue';
|
|
1072
1104
|
|
|
1073
|
-
type
|
|
1074
|
-
message: string;
|
|
1075
|
-
timestamp: string;
|
|
1076
|
-
};
|
|
1105
|
+
import type { AppData } from './app-types';
|
|
1077
1106
|
|
|
1078
1107
|
// Fallback idiom: non-blocking; \`data\` is undefined until ready, guarded with v-if.
|
|
1079
|
-
|
|
1108
|
+
// AppData is derived from taujs.config.ts - greet()'s result, never hand-written.
|
|
1109
|
+
const data = useSSRData<AppData>();
|
|
1080
1110
|
</script>
|
|
1081
1111
|
|
|
1082
1112
|
<template>
|
|
@@ -1095,13 +1125,11 @@ function generateStreamingPageVue() {
|
|
|
1095
1125
|
return `<script setup lang="ts">
|
|
1096
1126
|
import { useSSRDataAsync } from '@taujs/vue';
|
|
1097
1127
|
|
|
1098
|
-
type
|
|
1099
|
-
message: string;
|
|
1100
|
-
timestamp: string;
|
|
1101
|
-
};
|
|
1128
|
+
import type { AppData } from './app-types';
|
|
1102
1129
|
|
|
1103
1130
|
// Suspense idiom: async setup blocks on the data, so streamed routes deliver it in the payload.
|
|
1104
|
-
|
|
1131
|
+
// AppData is derived from taujs.config.ts - greet()'s result, never hand-written.
|
|
1132
|
+
const data = await useSSRDataAsync<AppData>();
|
|
1105
1133
|
</script>
|
|
1106
1134
|
|
|
1107
1135
|
<template>
|
|
@@ -1129,13 +1157,17 @@ function generateEntryServerVue() {
|
|
|
1129
1157
|
|
|
1130
1158
|
import App from './App.vue';
|
|
1131
1159
|
|
|
1132
|
-
|
|
1160
|
+
import type { AppData, AppRouteContext } from './app-types';
|
|
1161
|
+
|
|
1162
|
+
// Generics derived from taujs.config.ts: typed data for headContent and the store, typed
|
|
1163
|
+
// routeContext for appComponent.
|
|
1164
|
+
export const { renderSSR, renderStream } = createRenderer<AppData, AppRouteContext>({
|
|
1133
1165
|
appComponent: App,
|
|
1134
1166
|
headContent: ({ data, meta }) => \`
|
|
1135
1167
|
<title>\${meta?.title || "\u03C4js - Composing systems, not just apps"}</title>
|
|
1136
1168
|
<meta name="description" content="\${
|
|
1137
1169
|
meta?.description ||
|
|
1138
|
-
|
|
1170
|
+
data?.message ||
|
|
1139
1171
|
"\u03C4js - Composing systems, not just apps"
|
|
1140
1172
|
}">
|
|
1141
1173
|
\`,
|
|
@@ -1158,7 +1190,11 @@ function generateEntryServer() {
|
|
|
1158
1190
|
return `import { createRenderer } from '@taujs/react';
|
|
1159
1191
|
import { App } from './App';
|
|
1160
1192
|
|
|
1161
|
-
|
|
1193
|
+
import type { AppData, AppRouteContext } from './app-types';
|
|
1194
|
+
|
|
1195
|
+
// Generics derived from taujs.config.ts: typed data for headContent and the store, typed
|
|
1196
|
+
// routeContext for appComponent.
|
|
1197
|
+
export const { renderSSR, renderStream } = createRenderer<AppData, AppRouteContext>({
|
|
1162
1198
|
appComponent: () => <App />,
|
|
1163
1199
|
headContent: ({ data, meta }) => \`
|
|
1164
1200
|
<title>\${meta?.title || "\u03C4js - Composing systems, not just apps"}</title>
|
|
@@ -1194,12 +1230,13 @@ function generateAppComponentSolid() {
|
|
|
1194
1230
|
return `import { Show } from 'solid-js';
|
|
1195
1231
|
import { useSSRStore } from '@taujs/solid';
|
|
1196
1232
|
|
|
1197
|
-
type
|
|
1233
|
+
import type { AppData } from './app-types';
|
|
1198
1234
|
|
|
1199
1235
|
export function App() {
|
|
1200
1236
|
// Route data arrives through the store, which the renderer provides. On the server it is already
|
|
1201
1237
|
// committed before the render begins; on the client it is seeded from window.__INITIAL_DATA__.
|
|
1202
|
-
|
|
1238
|
+
// AppData is derived from taujs.config.ts - greet()'s result, never hand-written.
|
|
1239
|
+
const store = useSSRStore<AppData>();
|
|
1203
1240
|
|
|
1204
1241
|
return (
|
|
1205
1242
|
<main>
|
|
@@ -1234,7 +1271,11 @@ function generateEntryServerSolid() {
|
|
|
1234
1271
|
import { App } from './App';
|
|
1235
1272
|
import { RENDER_ID } from './renderId';
|
|
1236
1273
|
|
|
1237
|
-
|
|
1274
|
+
import type { AppData, AppRouteContext } from './app-types';
|
|
1275
|
+
|
|
1276
|
+
// Generics derived from taujs.config.ts: typed data for headContent and the store, typed
|
|
1277
|
+
// routeContext for appComponent.
|
|
1278
|
+
export const { renderSSR, renderStream } = createRenderer<AppData, AppRouteContext>({
|
|
1238
1279
|
appComponent: () => <App />,
|
|
1239
1280
|
renderId: RENDER_ID,
|
|
1240
1281
|
headContent: ({ data, meta }) => \`
|