create-fate 1.0.3 → 1.3.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/README.md +3 -0
- package/bin/create-fate.mjs +594 -9
- package/package.json +2 -2
- package/templates/fate/README.md +3 -0
- package/templates/fate/_shared/vue-app/package.json +54 -0
- package/templates/fate/_shared/vue-app/pages/index.vue +57 -0
- package/templates/fate/_shared/vue-app/pages/layout.vue +32 -0
- package/templates/fate/_shared/vue-app/pages/post/[id].vue +24 -0
- package/templates/fate/_shared/vue-app/src/App.css +63 -0
- package/templates/fate/_shared/vue-app/src/fateViews.ts +14 -0
- package/templates/fate/_shared/vue-app/src/lib/cx.ts +6 -0
- package/templates/fate/_shared/vue-app/src/lib/env.ts +3 -0
- package/templates/fate/_shared/vue-app/src/ui/Button.vue +67 -0
- package/templates/fate/_shared/vue-app/src/ui/Card.vue +16 -0
- package/templates/fate/_shared/vue-app/src/ui/Error.vue +9 -0
- package/templates/fate/_shared/vue-app/src/ui/ErrorBoundary.vue +22 -0
- package/templates/fate/_shared/vue-app/src/ui/Header.vue +35 -0
- package/templates/fate/_shared/vue-app/src/ui/Link.vue +15 -0
- package/templates/fate/_shared/vue-app/src/ui/PostCard.vue +29 -0
- package/templates/fate/_shared/vue-app/src/ui/Section.vue +19 -0
- package/templates/fate/_shared/vue-app/src/ui/Thinking.vue +11 -0
- package/templates/fate/_shared/vue-app/src/ui/UserCard.vue +23 -0
- package/templates/fate/_shared/vue-app/src/vue-shims.d.ts +6 -0
- package/templates/fate/_shared/vue-app/tsconfig.json +22 -0
- package/templates/fate/_shared/vue-app/vite.config.ts +58 -0
- package/templates/fate/_shared/vue-app/void.json +5 -0
- package/templates/fate/cloudflare/.github/workflows/push.yml +27 -0
- package/templates/fate/cloudflare/.vite-hooks/pre-commit +1 -0
- package/templates/fate/cloudflare/.vscode/extensions.json +12 -0
- package/templates/fate/cloudflare/.vscode/settings.json +25 -0
- package/templates/fate/cloudflare/AGENTS.md +55 -0
- package/templates/fate/cloudflare/README.md +126 -0
- package/templates/fate/cloudflare/_gitignore +20 -0
- package/templates/fate/cloudflare/client/package.json +56 -0
- package/templates/fate/cloudflare/client/pages/index.tsx +96 -0
- package/templates/fate/cloudflare/client/pages/layout.tsx +82 -0
- package/templates/fate/cloudflare/client/pages/login.tsx +107 -0
- package/templates/fate/cloudflare/client/pages/post/[id].tsx +22 -0
- package/templates/fate/cloudflare/client/pages/search.tsx +99 -0
- package/templates/fate/cloudflare/client/public/icon.svg +1 -0
- package/templates/fate/cloudflare/client/src/App.css +153 -0
- package/templates/fate/cloudflare/client/src/lib/AvailableLanguages.tsx +5 -0
- package/templates/fate/cloudflare/client/src/lib/cx.tsx +6 -0
- package/templates/fate/cloudflare/client/src/lib/env.tsx +5 -0
- package/templates/fate/cloudflare/client/src/ui/Badge.tsx +31 -0
- package/templates/fate/cloudflare/client/src/ui/Button.tsx +108 -0
- package/templates/fate/cloudflare/client/src/ui/Card.tsx +32 -0
- package/templates/fate/cloudflare/client/src/ui/CommentCard.tsx +75 -0
- package/templates/fate/cloudflare/client/src/ui/Error.tsx +19 -0
- package/templates/fate/cloudflare/client/src/ui/H2.tsx +15 -0
- package/templates/fate/cloudflare/client/src/ui/H3.tsx +20 -0
- package/templates/fate/cloudflare/client/src/ui/Header.tsx +98 -0
- package/templates/fate/cloudflare/client/src/ui/Input.tsx +17 -0
- package/templates/fate/cloudflare/client/src/ui/Link.tsx +11 -0
- package/templates/fate/cloudflare/client/src/ui/LocaleSwitcher.tsx +52 -0
- package/templates/fate/cloudflare/client/src/ui/PostCard.tsx +303 -0
- package/templates/fate/cloudflare/client/src/ui/Section.tsx +23 -0
- package/templates/fate/cloudflare/client/src/ui/UserCard.tsx +131 -0
- package/templates/fate/cloudflare/client/src/user/AuthClient.tsx +6 -0
- package/templates/fate/cloudflare/client/translations/de_DE.json +689 -0
- package/templates/fate/cloudflare/client/translations/ja_JP.json +689 -0
- package/templates/fate/cloudflare/client/vite.config.ts +45 -0
- package/templates/fate/cloudflare/client/void.json +29 -0
- package/templates/fate/cloudflare/package.json +46 -0
- package/templates/fate/cloudflare/pnpm-workspace.yaml +39 -0
- package/templates/fate/cloudflare/server/.env.example +1 -0
- package/templates/fate/cloudflare/server/db/db.ts +30 -0
- package/templates/fate/cloudflare/server/db/migrations/20260508073357_initial_schema.sql +133 -0
- package/templates/fate/cloudflare/server/db/migrations/20260508120500_seed_cloudflare_demo.sql +170 -0
- package/templates/fate/cloudflare/server/db/migrations/meta/20260508073357_snapshot.json +868 -0
- package/templates/fate/cloudflare/server/db/migrations/meta/_journal.json +20 -0
- package/templates/fate/cloudflare/server/db/queries.ts +211 -0
- package/templates/fate/cloudflare/server/db/schema.ts +332 -0
- package/templates/fate/cloudflare/server/package.json +34 -0
- package/templates/fate/cloudflare/server/src/fate/commentPermissions.ts +17 -0
- package/templates/fate/cloudflare/server/src/fate/context.ts +15 -0
- package/templates/fate/cloudflare/server/src/fate/live.ts +7 -0
- package/templates/fate/cloudflare/server/src/fate/server.ts +411 -0
- package/templates/fate/cloudflare/server/src/fate/views.ts +164 -0
- package/templates/fate/cloudflare/server/src/index.ts +80 -0
- package/templates/fate/cloudflare/server/src/lib/auth.ts +66 -0
- package/templates/fate/cloudflare/server/src/lib/origins.ts +17 -0
- package/templates/fate/cloudflare/server/src/router.ts +2 -0
- package/templates/fate/cloudflare/server/src/user/SessionUser.tsx +17 -0
- package/templates/fate/cloudflare/server/tsconfig.json +10 -0
- package/templates/fate/cloudflare/server/wrangler.jsonc +29 -0
- package/templates/fate/cloudflare/tsconfig.json +33 -0
- package/templates/fate/cloudflare/vite.config.ts +72 -0
- package/templates/fate/drizzle/README.md +2 -8
- package/templates/fate/drizzle/client/pages/layout.tsx +2 -2
- package/templates/fate/drizzle/client/src/ui/PostCard.tsx +38 -15
- package/templates/fate/drizzle/pnpm-workspace.yaml +9 -3
- package/templates/fate/drizzle/server/vite.config.ts +1 -1
- package/templates/fate/graphql/.github/workflows/push.yml +27 -0
- package/templates/fate/graphql/.vite-hooks/pre-commit +1 -0
- package/templates/fate/graphql/.vscode/extensions.json +12 -0
- package/templates/fate/graphql/.vscode/settings.json +25 -0
- package/templates/fate/graphql/AGENTS.md +55 -0
- package/templates/fate/graphql/README.md +121 -0
- package/templates/fate/graphql/_gitignore +23 -0
- package/templates/fate/graphql/client/package.json +57 -0
- package/templates/fate/graphql/client/pages/index.tsx +96 -0
- package/templates/fate/graphql/client/pages/layout.tsx +83 -0
- package/templates/fate/graphql/client/pages/login.tsx +107 -0
- package/templates/fate/graphql/client/pages/post/[id].tsx +22 -0
- package/templates/fate/graphql/client/pages/search.tsx +99 -0
- package/templates/fate/graphql/client/public/icon.svg +1 -0
- package/templates/fate/graphql/client/src/App.css +153 -0
- package/templates/fate/graphql/client/src/lib/AvailableLanguages.tsx +5 -0
- package/templates/fate/graphql/client/src/lib/cx.tsx +6 -0
- package/templates/fate/graphql/client/src/lib/env.tsx +5 -0
- package/templates/fate/graphql/client/src/ui/Badge.tsx +31 -0
- package/templates/fate/graphql/client/src/ui/Button.tsx +108 -0
- package/templates/fate/graphql/client/src/ui/Card.tsx +32 -0
- package/templates/fate/graphql/client/src/ui/CommentCard.tsx +75 -0
- package/templates/fate/graphql/client/src/ui/Error.tsx +19 -0
- package/templates/fate/graphql/client/src/ui/H2.tsx +15 -0
- package/templates/fate/graphql/client/src/ui/H3.tsx +20 -0
- package/templates/fate/graphql/client/src/ui/Header.tsx +98 -0
- package/templates/fate/graphql/client/src/ui/Input.tsx +17 -0
- package/templates/fate/graphql/client/src/ui/Link.tsx +11 -0
- package/templates/fate/graphql/client/src/ui/LocaleSwitcher.tsx +52 -0
- package/templates/fate/graphql/client/src/ui/PostCard.tsx +303 -0
- package/templates/fate/graphql/client/src/ui/Section.tsx +23 -0
- package/templates/fate/graphql/client/src/ui/UserCard.tsx +131 -0
- package/templates/fate/graphql/client/src/user/AuthClient.tsx +6 -0
- package/templates/fate/graphql/client/translations/de_DE.json +689 -0
- package/templates/fate/graphql/client/translations/ja_JP.json +689 -0
- package/templates/fate/graphql/client/vite.config.ts +40 -0
- package/templates/fate/graphql/client/void.json +29 -0
- package/templates/fate/graphql/docker-compose.yml +11 -0
- package/templates/fate/graphql/package.json +47 -0
- package/templates/fate/graphql/pnpm-workspace.yaml +45 -0
- package/templates/fate/graphql/server/.env.example +5 -0
- package/templates/fate/graphql/server/README.md +27 -0
- package/templates/fate/graphql/server/package.json +64 -0
- package/templates/fate/graphql/server/prisma.config.ts +17 -0
- package/templates/fate/graphql/server/scripts/generate-graphql.tsx +40 -0
- package/templates/fate/graphql/server/src/__tests__/index.test.tsx +5 -0
- package/templates/fate/graphql/server/src/app.tsx +47 -0
- package/templates/fate/graphql/server/src/graphql/builder.tsx +121 -0
- package/templates/fate/graphql/server/src/graphql/context.tsx +22 -0
- package/templates/fate/graphql/server/src/graphql/fate.ts +85 -0
- package/templates/fate/graphql/server/src/graphql/lib/authDirectives.tsx +93 -0
- package/templates/fate/graphql/server/src/graphql/lib/decodeGlobalID.tsx +12 -0
- package/templates/fate/graphql/server/src/graphql/lib/decodeIDOrThrow.tsx +10 -0
- package/templates/fate/graphql/server/src/graphql/lib/encodeGlobalID.tsx +5 -0
- package/templates/fate/graphql/server/src/graphql/live.tsx +241 -0
- package/templates/fate/graphql/server/src/graphql/mutations.tsx +265 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Category.tsx +35 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Comment.tsx +46 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Event.tsx +71 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Post.tsx +45 -0
- package/templates/fate/graphql/server/src/graphql/nodes/Tag.tsx +11 -0
- package/templates/fate/graphql/server/src/graphql/nodes/User.tsx +28 -0
- package/templates/fate/graphql/server/src/graphql/schema.tsx +16 -0
- package/templates/fate/graphql/server/src/graphql/views.ts +193 -0
- package/templates/fate/graphql/server/src/index.tsx +45 -0
- package/templates/fate/graphql/server/src/lib/auth.tsx +31 -0
- package/templates/fate/graphql/server/src/lib/env.tsx +3 -0
- package/templates/fate/graphql/server/src/lib/origins.ts +18 -0
- package/templates/fate/graphql/server/src/prisma/prisma.tsx +9 -0
- package/templates/fate/graphql/server/src/prisma/schema.prisma +181 -0
- package/templates/fate/graphql/server/src/prisma/seed.tsx +161 -0
- package/templates/fate/graphql/server/src/user/SessionUser.tsx +17 -0
- package/templates/fate/graphql/server/src/user/isAdmin.tsx +3 -0
- package/templates/fate/graphql/server/tsconfig.json +33 -0
- package/templates/fate/graphql/server/vite.config.ts +55 -0
- package/templates/fate/graphql/tsconfig.json +33 -0
- package/templates/fate/graphql/vite.config.ts +80 -0
- package/templates/fate/graphql-client/.env.example +3 -0
- package/templates/fate/graphql-client/AGENTS.md +3 -0
- package/templates/fate/graphql-client/README.md +69 -0
- package/templates/fate/graphql-client/_gitignore +14 -0
- package/templates/fate/graphql-client/package.json +62 -0
- package/templates/fate/graphql-client/pages/index.tsx +69 -0
- package/templates/fate/graphql-client/pages/layout.tsx +41 -0
- package/templates/fate/graphql-client/pnpm-workspace.yaml +38 -0
- package/templates/fate/graphql-client/public/icon.svg +8 -0
- package/templates/fate/graphql-client/src/App.css +28 -0
- package/templates/fate/graphql-client/src/fate/graphql.ts +52 -0
- package/templates/fate/graphql-client/tsconfig.json +30 -0
- package/templates/fate/graphql-client/vite.config.ts +87 -0
- package/templates/fate/graphql-client/void.json +29 -0
- package/templates/fate/http/README.md +2 -8
- package/templates/fate/http/client/pages/layout.tsx +2 -2
- package/templates/fate/http/client/src/ui/PostCard.tsx +37 -15
- package/templates/fate/http/pnpm-workspace.yaml +9 -3
- package/templates/fate/http/server/vite.config.ts +1 -1
- package/templates/fate/prisma/README.md +2 -8
- package/templates/fate/prisma/client/pages/layout.tsx +2 -2
- package/templates/fate/prisma/client/src/ui/PostCard.tsx +37 -15
- package/templates/fate/prisma/pnpm-workspace.yaml +9 -3
- package/templates/fate/prisma/server/vite.config.ts +1 -1
- package/templates/fate/prisma/vite.config.ts +1 -1
- package/templates/fate/void/package.json +10 -2
- package/templates/fate/void/pages/login.tsx +3 -3
- package/templates/fate/void/pnpm-workspace.yaml +12 -4
- package/templates/fate/void/src/ui/Button.tsx +42 -26
- package/templates/fate/void/src/ui/CategoryCard.tsx +3 -7
- package/templates/fate/void/src/ui/PostCard.tsx +38 -15
- package/templates/fate/void/vite.config.ts +15 -14
- package/templates/fate/drizzle/public/fate-logo-dark.svg +0 -4
- package/templates/fate/drizzle/public/fate-logo.svg +0 -4
- package/templates/fate/http/public/fate-logo-dark.svg +0 -4
- package/templates/fate/http/public/fate-logo.svg +0 -4
- package/templates/fate/prisma/public/fate-logo-dark.svg +0 -4
- package/templates/fate/prisma/public/fate-logo.svg +0 -4
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
|
|
3
|
+
body {
|
|
4
|
+
margin: 0;
|
|
5
|
+
background: #f8fafc;
|
|
6
|
+
color: #111827;
|
|
7
|
+
font-family:
|
|
8
|
+
Inter,
|
|
9
|
+
ui-sans-serif,
|
|
10
|
+
system-ui,
|
|
11
|
+
-apple-system,
|
|
12
|
+
BlinkMacSystemFont,
|
|
13
|
+
'Segoe UI',
|
|
14
|
+
sans-serif;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
button,
|
|
18
|
+
input,
|
|
19
|
+
textarea {
|
|
20
|
+
font: inherit;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@media (prefers-color-scheme: dark) {
|
|
24
|
+
body {
|
|
25
|
+
background: #0f172a;
|
|
26
|
+
color: #f8fafc;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { graphqlMutation } from '@nkzw/fate';
|
|
2
|
+
import { dataView, list, type Entity } from '@nkzw/fate/server';
|
|
3
|
+
|
|
4
|
+
type GraphQLUser = {
|
|
5
|
+
id: string;
|
|
6
|
+
name?: string | null;
|
|
7
|
+
username?: string | null;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type GraphQLPost = {
|
|
11
|
+
author?: GraphQLUser | null;
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const userDataView = dataView<GraphQLUser>('User')({
|
|
17
|
+
id: true,
|
|
18
|
+
name: true,
|
|
19
|
+
username: true,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const postDataView = dataView<GraphQLPost>('Post')({
|
|
23
|
+
author: userDataView,
|
|
24
|
+
id: true,
|
|
25
|
+
title: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export type User = Entity<typeof userDataView, 'User'>;
|
|
29
|
+
export type Post = Entity<
|
|
30
|
+
typeof postDataView,
|
|
31
|
+
'Post',
|
|
32
|
+
{
|
|
33
|
+
author: User | null;
|
|
34
|
+
}
|
|
35
|
+
>;
|
|
36
|
+
|
|
37
|
+
export const Root = {
|
|
38
|
+
posts: list(postDataView),
|
|
39
|
+
viewer: userDataView,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const fateGraphQL = {
|
|
43
|
+
mutations: {
|
|
44
|
+
'post.like': graphqlMutation<Post, { id: string }, Post>('Post', {
|
|
45
|
+
field: 'postLike',
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
roots: {
|
|
49
|
+
posts: { field: 'posts' },
|
|
50
|
+
viewer: { field: 'viewer' },
|
|
51
|
+
},
|
|
52
|
+
} as const;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./.void/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"allowImportingTsExtensions": true,
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"forceConsistentCasingInFileNames": true,
|
|
7
|
+
"incremental": true,
|
|
8
|
+
"isolatedModules": true,
|
|
9
|
+
"jsx": "react-jsx",
|
|
10
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
11
|
+
"module": "ESNext",
|
|
12
|
+
"moduleResolution": "Bundler",
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"noImplicitOverride": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"strict": true,
|
|
19
|
+
"target": "ES2022",
|
|
20
|
+
"types": ["vite/client", "void/env"]
|
|
21
|
+
},
|
|
22
|
+
"include": [
|
|
23
|
+
".fate/**/*.ts",
|
|
24
|
+
".void/**/*.d.ts",
|
|
25
|
+
"pages/**/*.ts",
|
|
26
|
+
"pages/**/*.tsx",
|
|
27
|
+
"src/**/*.ts",
|
|
28
|
+
"src/**/*.tsx"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import nkzw from '@nkzw/oxlint-config';
|
|
2
|
+
import babel from '@rolldown/plugin-babel';
|
|
3
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
4
|
+
import { reactCompilerPreset } from '@vitejs/plugin-react';
|
|
5
|
+
import { voidReact } from '@void/react/plugin';
|
|
6
|
+
import { fate } from 'react-fate/vite';
|
|
7
|
+
import { defineConfig, lazyPlugins } from 'vite-plus';
|
|
8
|
+
import { voidPlugin } from 'void';
|
|
9
|
+
|
|
10
|
+
const isTest = process.env.NODE_ENV === 'test' || process.env.VITEST;
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
optimizeDeps: {
|
|
14
|
+
exclude: ['@nkzw/fate/client', 'react-fate/client'],
|
|
15
|
+
},
|
|
16
|
+
environments: {
|
|
17
|
+
void_worker: {
|
|
18
|
+
optimizeDeps: {
|
|
19
|
+
exclude: [
|
|
20
|
+
'@nkzw/fate',
|
|
21
|
+
'@nkzw/fate/client',
|
|
22
|
+
'@nkzw/fate/server',
|
|
23
|
+
'@void/react',
|
|
24
|
+
'@void/react/pages-server',
|
|
25
|
+
'lucide-react',
|
|
26
|
+
'react-error-boundary',
|
|
27
|
+
'react-fate',
|
|
28
|
+
'react-fate/client',
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
fmt: {
|
|
34
|
+
experimentalSortImports: {
|
|
35
|
+
newlinesBetween: false,
|
|
36
|
+
},
|
|
37
|
+
experimentalSortPackageJson: {
|
|
38
|
+
sortScripts: true,
|
|
39
|
+
},
|
|
40
|
+
experimentalTailwindcss: {
|
|
41
|
+
stylesheet: 'src/App.css',
|
|
42
|
+
},
|
|
43
|
+
ignorePatterns: ['.fate/', '.void/', 'dist/', 'node_modules/', 'pnpm-lock.yaml'],
|
|
44
|
+
singleQuote: true,
|
|
45
|
+
},
|
|
46
|
+
lint: {
|
|
47
|
+
extends: [nkzw],
|
|
48
|
+
ignorePatterns: ['.fate', '.void', 'dist', 'node_modules', 'vite.config.ts.timestamp-*'],
|
|
49
|
+
options: { typeAware: true, typeCheck: true },
|
|
50
|
+
overrides: [
|
|
51
|
+
{
|
|
52
|
+
files: ['src/fate/graphql.ts'],
|
|
53
|
+
rules: {
|
|
54
|
+
'no-console': 'off',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
rules: {
|
|
59
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
plugins: [
|
|
63
|
+
...(lazyPlugins(() => [
|
|
64
|
+
babel({
|
|
65
|
+
presets: [reactCompilerPreset()],
|
|
66
|
+
}),
|
|
67
|
+
tailwindcss(),
|
|
68
|
+
...(isTest ? [] : [voidPlugin(), voidReact()]),
|
|
69
|
+
]) ?? []),
|
|
70
|
+
fate({
|
|
71
|
+
module: './src/fate/graphql.ts',
|
|
72
|
+
transport: 'graphql',
|
|
73
|
+
}),
|
|
74
|
+
],
|
|
75
|
+
run: {
|
|
76
|
+
tasks: {
|
|
77
|
+
'test:all': {
|
|
78
|
+
command: 'vp check && vp test',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
server: { port: 6001 },
|
|
83
|
+
ssr: { noExternal: ['@nkzw/fate', 'react-fate'] },
|
|
84
|
+
staged: {
|
|
85
|
+
'*': 'vp check --fix',
|
|
86
|
+
},
|
|
87
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/void/schema.json",
|
|
3
|
+
"head": {
|
|
4
|
+
"title": "fate",
|
|
5
|
+
"titleTemplate": "%s | fate",
|
|
6
|
+
"htmlAttrs": {
|
|
7
|
+
"lang": "en"
|
|
8
|
+
},
|
|
9
|
+
"meta": [
|
|
10
|
+
{
|
|
11
|
+
"charset": "utf-8"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "viewport",
|
|
15
|
+
"content": "width=device-width, initial-scale=1"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"link": [
|
|
19
|
+
{
|
|
20
|
+
"rel": "icon",
|
|
21
|
+
"href": "/icon.svg"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"worker": {
|
|
26
|
+
"compatibility_date": "2025-12-01",
|
|
27
|
+
"compatibility_flags": ["nodejs_compat", "no_handle_cross_request_promise_resolution"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
<picture>
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="/public/fate-logo-dark.svg">
|
|
4
|
-
<source media="(prefers-color-scheme: light)" srcset="/public/fate-logo.svg">
|
|
5
|
-
<img alt="Logo" src="/public/fate-logo.svg" width="50%">
|
|
6
|
-
</picture>
|
|
7
|
-
</p>
|
|
1
|
+
# _fate_
|
|
8
2
|
|
|
9
3
|
**_fate_** is a modern data client for React inspired by [Relay](https://relay.dev/) and [GraphQL](https://graphql.org/). It combines view composition, normalized caching, data masking, Async React features, and type-safe data fetching.
|
|
10
4
|
|
|
11
5
|
Check out [fate.technology](https://fate.technology) for documentation, examples, and guides.
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
## Quick Start Template
|
|
14
8
|
|
|
15
9
|
Create a new fate app with Vite+:
|
|
16
10
|
|
|
@@ -36,7 +36,7 @@ const LocaleContext = createLocaleContext({
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
export default function Layout({ children }: { children: ReactNode }) {
|
|
39
|
-
const { data: session
|
|
39
|
+
const { data: session } = AuthClient.useSession();
|
|
40
40
|
const userId = session?.user.id;
|
|
41
41
|
|
|
42
42
|
const fate = useMemo(
|
|
@@ -57,7 +57,7 @@ export default function Layout({ children }: { children: ReactNode }) {
|
|
|
57
57
|
<div className="min-h-screen bg-background text-foreground">
|
|
58
58
|
<div className="min-h-screen bg-[radial-gradient(circle_at_20%_20%,rgba(59,130,246,0.08),transparent_35%),radial-gradient(circle_at_80%_0,rgba(99,102,241,0.08),transparent_28%)]">
|
|
59
59
|
<Header />
|
|
60
|
-
{
|
|
60
|
+
{session ? (
|
|
61
61
|
<Thinking />
|
|
62
62
|
) : (
|
|
63
63
|
<FateClient client={fate} key={userId}>
|
|
@@ -4,6 +4,7 @@ import { cx } from 'class-variance-authority';
|
|
|
4
4
|
import { fbs } from 'fbtee';
|
|
5
5
|
import {
|
|
6
6
|
KeyboardEvent,
|
|
7
|
+
Suspense,
|
|
7
8
|
startTransition,
|
|
8
9
|
useActionState,
|
|
9
10
|
useCallback,
|
|
@@ -11,7 +12,15 @@ import {
|
|
|
11
12
|
useState,
|
|
12
13
|
} from 'react';
|
|
13
14
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
defer,
|
|
17
|
+
type Deferred,
|
|
18
|
+
useListView,
|
|
19
|
+
useFateClient,
|
|
20
|
+
useView,
|
|
21
|
+
view,
|
|
22
|
+
ViewRef,
|
|
23
|
+
} from 'react-fate';
|
|
15
24
|
import { Button } from '../ui/Button.tsx';
|
|
16
25
|
import Card from '../ui/Card.tsx';
|
|
17
26
|
import AuthClient from '../user/AuthClient.tsx';
|
|
@@ -30,13 +39,36 @@ const CommentConnectionView = {
|
|
|
30
39
|
export const PostView = view<Post>()({
|
|
31
40
|
author: UserView,
|
|
32
41
|
commentCount: true,
|
|
33
|
-
comments: CommentConnectionView,
|
|
42
|
+
comments: defer(CommentConnectionView),
|
|
34
43
|
content: true,
|
|
35
44
|
id: true,
|
|
36
45
|
likes: true,
|
|
37
46
|
title: true,
|
|
38
47
|
});
|
|
39
48
|
|
|
49
|
+
const PostComments = ({
|
|
50
|
+
comments,
|
|
51
|
+
post,
|
|
52
|
+
}: {
|
|
53
|
+
comments: Deferred<{ items: ReadonlyArray<{ node: ViewRef<'Comment'> }> }>;
|
|
54
|
+
post: { commentCount: number; id: string; title: string };
|
|
55
|
+
}) => {
|
|
56
|
+
const [items, loadNext] = useListView(CommentConnectionView, comments);
|
|
57
|
+
|
|
58
|
+
return items.length > 0 ? (
|
|
59
|
+
<VStack gap={12}>
|
|
60
|
+
{items.map(({ node }) => (
|
|
61
|
+
<CommentCard comment={node} key={node.id} post={post} />
|
|
62
|
+
))}
|
|
63
|
+
{loadNext ? (
|
|
64
|
+
<Button onClick={loadNext} variant="ghost">
|
|
65
|
+
<fbt desc="Load more comments button">Load more comments</fbt>
|
|
66
|
+
</Button>
|
|
67
|
+
) : null}
|
|
68
|
+
</VStack>
|
|
69
|
+
) : null;
|
|
70
|
+
};
|
|
71
|
+
|
|
40
72
|
const CommentInput = ({
|
|
41
73
|
error,
|
|
42
74
|
post,
|
|
@@ -125,7 +157,6 @@ export function PostCard({ detail, post: postRef }: { detail?: boolean; post: Vi
|
|
|
125
157
|
const fate = useFateClient();
|
|
126
158
|
const post = useView(PostView, postRef);
|
|
127
159
|
const author = useView(UserView, post.author);
|
|
128
|
-
const [comments, loadNext] = useListView(CommentConnectionView, post.comments);
|
|
129
160
|
|
|
130
161
|
const [likeResult, likeAction, likeIsPending] = useActionState(fate.actions.post.like, null);
|
|
131
162
|
|
|
@@ -259,18 +290,9 @@ export function PostCard({ detail, post: postRef }: { detail?: boolean; post: Vi
|
|
|
259
290
|
</fbt:plural>
|
|
260
291
|
</fbt>
|
|
261
292
|
</h4>
|
|
262
|
-
{
|
|
263
|
-
<
|
|
264
|
-
|
|
265
|
-
<CommentCard comment={node} key={node.id} post={post} />
|
|
266
|
-
))}
|
|
267
|
-
{loadNext ? (
|
|
268
|
-
<Button onClick={loadNext} variant="ghost">
|
|
269
|
-
<fbt desc="Load more comments button">Load more comments</fbt>
|
|
270
|
-
</Button>
|
|
271
|
-
) : null}
|
|
272
|
-
</VStack>
|
|
273
|
-
) : null}
|
|
293
|
+
<Suspense fallback={null}>
|
|
294
|
+
<PostComments comments={post.comments} post={post} />
|
|
295
|
+
</Suspense>
|
|
274
296
|
<ErrorBoundary fallbackRender={({ error }) => <CommentInput error={error} post={post} />}>
|
|
275
297
|
<CommentInput post={post} />
|
|
276
298
|
</ErrorBoundary>
|
|
@@ -11,9 +11,14 @@ allowBuilds:
|
|
|
11
11
|
workerd: true
|
|
12
12
|
|
|
13
13
|
catalog:
|
|
14
|
-
vite: npm:@voidzero-dev/vite-plus-core@^0.1.
|
|
15
|
-
vite-plus: ^0.1.
|
|
16
|
-
vitest: npm:@voidzero-dev/vite-plus-test@^0.1.
|
|
14
|
+
vite: npm:@voidzero-dev/vite-plus-core@^0.1.23
|
|
15
|
+
vite-plus: ^0.1.23
|
|
16
|
+
vitest: npm:@voidzero-dev/vite-plus-test@^0.1.23
|
|
17
|
+
|
|
18
|
+
minimumReleaseAgeExclude:
|
|
19
|
+
- '@voidzero-dev/vite-plus-core'
|
|
20
|
+
- '@voidzero-dev/vite-plus-test'
|
|
21
|
+
- vite-plus
|
|
17
22
|
|
|
18
23
|
onlyBuiltDependencies:
|
|
19
24
|
- '@swc/core'
|
|
@@ -24,6 +29,7 @@ onlyBuiltDependencies:
|
|
|
24
29
|
- unrs-resolver
|
|
25
30
|
|
|
26
31
|
overrides:
|
|
32
|
+
kysely: 0.28.17
|
|
27
33
|
vite: 'catalog:'
|
|
28
34
|
vitest: 'catalog:'
|
|
29
35
|
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
<picture>
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="/public/fate-logo-dark.svg">
|
|
4
|
-
<source media="(prefers-color-scheme: light)" srcset="/public/fate-logo.svg">
|
|
5
|
-
<img alt="Logo" src="/public/fate-logo.svg" width="50%">
|
|
6
|
-
</picture>
|
|
7
|
-
</p>
|
|
1
|
+
# _fate_
|
|
8
2
|
|
|
9
3
|
**_fate_** is a modern data client for React inspired by [Relay](https://relay.dev/) and [GraphQL](https://graphql.org/). It combines view composition, normalized caching, data masking, Async React features, and type-safe data fetching.
|
|
10
4
|
|
|
11
5
|
Check out [fate.technology](https://fate.technology) for documentation, examples, and guides.
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
## Quick Start Template
|
|
14
8
|
|
|
15
9
|
Create a new fate app with Vite+:
|
|
16
10
|
|
|
@@ -37,7 +37,7 @@ const LocaleContext = createLocaleContext({
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
export default function Layout({ children }: { children: ReactNode }) {
|
|
40
|
-
const { data: session
|
|
40
|
+
const { data: session } = AuthClient.useSession();
|
|
41
41
|
const userId = session?.user.id;
|
|
42
42
|
|
|
43
43
|
const fate = useMemo(
|
|
@@ -62,7 +62,7 @@ export default function Layout({ children }: { children: ReactNode }) {
|
|
|
62
62
|
<div className="min-h-screen bg-background text-foreground">
|
|
63
63
|
<div className="min-h-screen bg-[radial-gradient(circle_at_20%_20%,rgba(59,130,246,0.08),transparent_35%),radial-gradient(circle_at_80%_0,rgba(99,102,241,0.08),transparent_28%)]">
|
|
64
64
|
<Header />
|
|
65
|
-
{
|
|
65
|
+
{session ? (
|
|
66
66
|
<Thinking />
|
|
67
67
|
) : (
|
|
68
68
|
<FateClient client={fate} key={userId}>
|
|
@@ -4,6 +4,7 @@ import { cx } from 'class-variance-authority';
|
|
|
4
4
|
import { fbs } from 'fbtee';
|
|
5
5
|
import {
|
|
6
6
|
KeyboardEvent,
|
|
7
|
+
Suspense,
|
|
7
8
|
startTransition,
|
|
8
9
|
useActionState,
|
|
9
10
|
useCallback,
|
|
@@ -11,7 +12,15 @@ import {
|
|
|
11
12
|
useState,
|
|
12
13
|
} from 'react';
|
|
13
14
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
defer,
|
|
17
|
+
type Deferred,
|
|
18
|
+
useListView,
|
|
19
|
+
useFateClient,
|
|
20
|
+
useView,
|
|
21
|
+
view,
|
|
22
|
+
ViewRef,
|
|
23
|
+
} from 'react-fate';
|
|
15
24
|
import { Button } from '../ui/Button.tsx';
|
|
16
25
|
import Card from '../ui/Card.tsx';
|
|
17
26
|
import AuthClient from '../user/AuthClient.tsx';
|
|
@@ -30,13 +39,36 @@ const CommentConnectionView = {
|
|
|
30
39
|
export const PostView = view<Post>()({
|
|
31
40
|
author: UserView,
|
|
32
41
|
commentCount: true,
|
|
33
|
-
comments: CommentConnectionView,
|
|
42
|
+
comments: defer(CommentConnectionView),
|
|
34
43
|
content: true,
|
|
35
44
|
id: true,
|
|
36
45
|
likes: true,
|
|
37
46
|
title: true,
|
|
38
47
|
});
|
|
39
48
|
|
|
49
|
+
const PostComments = ({
|
|
50
|
+
comments,
|
|
51
|
+
post,
|
|
52
|
+
}: {
|
|
53
|
+
comments: Deferred<{ items: ReadonlyArray<{ node: ViewRef<'Comment'> }> }>;
|
|
54
|
+
post: { commentCount: number; id: string; title: string };
|
|
55
|
+
}) => {
|
|
56
|
+
const [items, loadNext] = useListView(CommentConnectionView, comments);
|
|
57
|
+
|
|
58
|
+
return items.length > 0 ? (
|
|
59
|
+
<VStack gap={12}>
|
|
60
|
+
{items.map(({ node }) => (
|
|
61
|
+
<CommentCard comment={node} key={node.id} post={post} />
|
|
62
|
+
))}
|
|
63
|
+
{loadNext ? (
|
|
64
|
+
<Button onClick={loadNext} variant="ghost">
|
|
65
|
+
<fbt desc="Load more comments button">Load more comments</fbt>
|
|
66
|
+
</Button>
|
|
67
|
+
) : null}
|
|
68
|
+
</VStack>
|
|
69
|
+
) : null;
|
|
70
|
+
};
|
|
71
|
+
|
|
40
72
|
const CommentInput = ({
|
|
41
73
|
error,
|
|
42
74
|
post,
|
|
@@ -125,7 +157,6 @@ export function PostCard({ detail, post: postRef }: { detail?: boolean; post: Vi
|
|
|
125
157
|
const fate = useFateClient();
|
|
126
158
|
const post = useView(PostView, postRef);
|
|
127
159
|
const author = useView(UserView, post.author);
|
|
128
|
-
const [comments, loadNext] = useListView(CommentConnectionView, post.comments);
|
|
129
160
|
|
|
130
161
|
const [likeResult, likeAction, likeIsPending] = useActionState(fate.actions.post.like, null);
|
|
131
162
|
|
|
@@ -259,18 +290,9 @@ export function PostCard({ detail, post: postRef }: { detail?: boolean; post: Vi
|
|
|
259
290
|
</fbt:plural>
|
|
260
291
|
</fbt>
|
|
261
292
|
</h4>
|
|
262
|
-
{
|
|
263
|
-
<
|
|
264
|
-
|
|
265
|
-
<CommentCard comment={node} key={node.id} post={post} />
|
|
266
|
-
))}
|
|
267
|
-
{loadNext ? (
|
|
268
|
-
<Button onClick={loadNext} variant="ghost">
|
|
269
|
-
<fbt desc="Load more comments button">Load more comments</fbt>
|
|
270
|
-
</Button>
|
|
271
|
-
) : null}
|
|
272
|
-
</VStack>
|
|
273
|
-
) : null}
|
|
293
|
+
<Suspense fallback={null}>
|
|
294
|
+
<PostComments comments={post.comments} post={post} />
|
|
295
|
+
</Suspense>
|
|
274
296
|
<ErrorBoundary fallbackRender={({ error }) => <CommentInput error={error} post={post} />}>
|
|
275
297
|
<CommentInput post={post} />
|
|
276
298
|
</ErrorBoundary>
|
|
@@ -12,9 +12,14 @@ allowBuilds:
|
|
|
12
12
|
workerd: true
|
|
13
13
|
|
|
14
14
|
catalog:
|
|
15
|
-
vite: npm:@voidzero-dev/vite-plus-core@^0.1.
|
|
16
|
-
vite-plus: ^0.1.
|
|
17
|
-
vitest: npm:@voidzero-dev/vite-plus-test@^0.1.
|
|
15
|
+
vite: npm:@voidzero-dev/vite-plus-core@^0.1.23
|
|
16
|
+
vite-plus: ^0.1.23
|
|
17
|
+
vitest: npm:@voidzero-dev/vite-plus-test@^0.1.23
|
|
18
|
+
|
|
19
|
+
minimumReleaseAgeExclude:
|
|
20
|
+
- '@voidzero-dev/vite-plus-core'
|
|
21
|
+
- '@voidzero-dev/vite-plus-test'
|
|
22
|
+
- vite-plus
|
|
18
23
|
|
|
19
24
|
onlyBuiltDependencies:
|
|
20
25
|
- '@prisma/client'
|
|
@@ -27,6 +32,7 @@ onlyBuiltDependencies:
|
|
|
27
32
|
- unrs-resolver
|
|
28
33
|
|
|
29
34
|
overrides:
|
|
35
|
+
kysely: 0.28.17
|
|
30
36
|
vite: 'catalog:'
|
|
31
37
|
vitest: 'catalog:'
|
|
32
38
|
|
|
@@ -41,7 +41,7 @@ export default defineConfig({
|
|
|
41
41
|
'client/dist',
|
|
42
42
|
'server/dist',
|
|
43
43
|
'server/src/prisma/pothos-types.ts',
|
|
44
|
-
'server/src/prisma/prisma-client
|
|
44
|
+
'server/src/prisma/prisma-client/**',
|
|
45
45
|
'vite.config.ts.timestamp-*',
|
|
46
46
|
'client/vite.config.ts.timestamp-*',
|
|
47
47
|
'server/vite.config.ts.timestamp-*',
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"dev": "vp dev",
|
|
18
18
|
"dev:setup": "vp run prepare:void && vp run db:seed && vp run fate:generate",
|
|
19
19
|
"fate:generate": "vp exec fate generate",
|
|
20
|
-
"prepare:void": "void prepare"
|
|
20
|
+
"prepare:void": "void prepare",
|
|
21
|
+
"test:all": "vp check && vp test"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"@nkzw/core": "^1.3.1",
|
|
@@ -40,17 +41,24 @@
|
|
|
40
41
|
"zod": "^4.4.3"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
44
|
+
"@nkzw/eslint-plugin": "^2.0.0",
|
|
45
|
+
"@nkzw/oxlint-config": "^1.2.1",
|
|
43
46
|
"@rolldown/plugin-babel": "^0.2.3",
|
|
44
47
|
"@tailwindcss/vite": "^4.2.4",
|
|
45
48
|
"@types/node": "^25.6.0",
|
|
46
49
|
"@types/react": "^19.2.14",
|
|
47
50
|
"@types/react-dom": "^19.2.3",
|
|
51
|
+
"@typescript/native-preview": "7.0.0-dev.20260505.1",
|
|
48
52
|
"@vitejs/plugin-react": "^6.0.1",
|
|
49
53
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
54
|
+
"eslint-plugin-no-only-tests": "^3.4.0",
|
|
55
|
+
"eslint-plugin-perfectionist": "^5.9.0",
|
|
56
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
50
57
|
"tailwindcss": "^4.2.4",
|
|
51
58
|
"ts-node": "^10.9.2",
|
|
52
59
|
"vite": "catalog:",
|
|
53
|
-
"vite-plus": "catalog:"
|
|
60
|
+
"vite-plus": "catalog:",
|
|
61
|
+
"vitest": "catalog:"
|
|
54
62
|
},
|
|
55
63
|
"browserslist": [
|
|
56
64
|
">0.2%",
|
|
@@ -3,7 +3,7 @@ import { useRouter, useShared } from '@void/react';
|
|
|
3
3
|
import { ExternalLinkIcon } from 'lucide-react';
|
|
4
4
|
import { useActionState, useEffect, useState } from 'react';
|
|
5
5
|
import type { SharedData } from '../src/lib/shared.ts';
|
|
6
|
-
import {
|
|
6
|
+
import { AsyncButton } from '../src/ui/Button.tsx';
|
|
7
7
|
import Card from '../src/ui/Card.tsx';
|
|
8
8
|
import H2 from '../src/ui/H2.tsx';
|
|
9
9
|
import Input from '../src/ui/Input.tsx';
|
|
@@ -71,9 +71,9 @@ export default function LoginPage() {
|
|
|
71
71
|
value={password}
|
|
72
72
|
/>
|
|
73
73
|
<div>
|
|
74
|
-
<
|
|
74
|
+
<AsyncButton type="submit" variant="outline">
|
|
75
75
|
Sign In
|
|
76
|
-
</
|
|
76
|
+
</AsyncButton>
|
|
77
77
|
</div>
|
|
78
78
|
</VStack>
|
|
79
79
|
</Stack>
|
|
@@ -2,18 +2,22 @@ packages:
|
|
|
2
2
|
- .
|
|
3
3
|
|
|
4
4
|
allowBuilds:
|
|
5
|
-
'@swc/core': true
|
|
6
5
|
better-sqlite3: true
|
|
7
6
|
esbuild: true
|
|
8
7
|
sharp: true
|
|
9
8
|
workerd: true
|
|
10
9
|
|
|
11
10
|
catalog:
|
|
12
|
-
vite: npm:@voidzero-dev/vite-plus-core
|
|
13
|
-
vite-plus: 0.1.
|
|
11
|
+
vite: npm:@voidzero-dev/vite-plus-core@^0.1.23
|
|
12
|
+
vite-plus: ^0.1.23
|
|
13
|
+
vitest: npm:@voidzero-dev/vite-plus-test@^0.1.23
|
|
14
|
+
|
|
15
|
+
minimumReleaseAgeExclude:
|
|
16
|
+
- '@voidzero-dev/vite-plus-core'
|
|
17
|
+
- '@voidzero-dev/vite-plus-test'
|
|
18
|
+
- vite-plus
|
|
14
19
|
|
|
15
20
|
onlyBuiltDependencies:
|
|
16
|
-
- '@swc/core'
|
|
17
21
|
- '@tailwindcss/oxide'
|
|
18
22
|
- better-sqlite3
|
|
19
23
|
- esbuild
|
|
@@ -22,10 +26,14 @@ onlyBuiltDependencies:
|
|
|
22
26
|
- workerd
|
|
23
27
|
|
|
24
28
|
overrides:
|
|
29
|
+
kysely: 0.28.17
|
|
25
30
|
vite: 'catalog:'
|
|
31
|
+
vitest: 'catalog:'
|
|
26
32
|
|
|
27
33
|
peerDependencyRules:
|
|
28
34
|
allowAny:
|
|
29
35
|
- vite
|
|
36
|
+
- vitest
|
|
30
37
|
allowedVersions:
|
|
31
38
|
vite: '*'
|
|
39
|
+
vitest: '*'
|