kitcn 0.12.4 → 0.12.6
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/aggregate/index.d.ts +1 -1
- package/dist/auth/generated/index.d.ts +1 -1
- package/dist/auth/index.d.ts +12 -12
- package/dist/auth/start/index.d.ts +1 -0
- package/dist/auth/start/index.js +1 -0
- package/dist/cli.mjs +829 -29
- package/dist/{codegen-lF80HSWu.mjs → codegen-B60fOYhd.mjs} +17 -13
- package/dist/crpc/index.d.ts +1 -1
- package/dist/{generated-contract-disabled-D-sOFy92.d.ts → generated-contract-disabled-ngvXLZ4i.d.ts} +29 -29
- package/dist/orm/index.d.ts +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/ratelimit/index.d.ts +1 -1
- package/dist/rsc/index.d.ts +1 -1
- package/dist/watcher.mjs +1 -1
- package/dist/{where-clause-compiler-DdjN63Io.d.ts → where-clause-compiler-CuH2JNxb.d.ts} +12 -12
- package/package.json +2 -1
- package/skills/convex/references/features/auth.md +1 -1
- package/skills/convex/references/setup/start.md +58 -18
- /package/dist/{middleware-BUybuv9n.d.ts → middleware-BL2wn3s0.d.ts} +0 -0
- /package/dist/{types-HhO_R6pd.d.ts → types-BLvtq_eH.d.ts} +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as isColorEnabled, c as EnableRLS, d as TableName, f as createSystemFields, i as highlighter, l as OrmSchemaExtensions, n as getConvexConfig, o as getSchemaRelations, r as logger, s as Columns, t as generateMeta, u as RlsPolicies } from "./codegen-
|
|
2
|
+
import { a as isColorEnabled, c as EnableRLS, d as TableName, f as createSystemFields, i as highlighter, l as OrmSchemaExtensions, n as getConvexConfig, o as getSchemaRelations, r as logger, s as Columns, t as generateMeta, u as RlsPolicies } from "./codegen-B60fOYhd.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import fs, { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import path, { basename, delimiter, dirname, isAbsolute, join, posix, relative, resolve } from "node:path";
|
|
@@ -2330,10 +2330,10 @@ function mapFrameworkToScaffoldMode(framework) {
|
|
|
2330
2330
|
}
|
|
2331
2331
|
function resolveProjectScaffoldContext(params = {}) {
|
|
2332
2332
|
const cwd = params.cwd ?? process.cwd();
|
|
2333
|
-
const detectedFramework =
|
|
2333
|
+
const detectedFramework = (params.template === "next" ? "next-app" : params.template === "start" ? "tanstack-start" : params.template === "vite" ? "vite" : null) ?? detectProjectFramework(cwd);
|
|
2334
2334
|
if (!detectedFramework) {
|
|
2335
2335
|
if (params.allowMissing) return null;
|
|
2336
|
-
throw new Error("Could not detect a supported app scaffold. Supported modes currently start from `next` or `vite`.");
|
|
2336
|
+
throw new Error("Could not detect a supported app scaffold. Supported modes currently start from `next`, `start`, or `vite`.");
|
|
2337
2337
|
}
|
|
2338
2338
|
let mode;
|
|
2339
2339
|
try {
|
|
@@ -2451,6 +2451,8 @@ const INIT_TEMPLATE_DEPENDENCY_INSTALL_SPECS = ["superjson"];
|
|
|
2451
2451
|
|
|
2452
2452
|
//#endregion
|
|
2453
2453
|
//#region src/cli/registry/dependencies.ts
|
|
2454
|
+
const BUN_LOCK_PATH = "bun.lock";
|
|
2455
|
+
const BETTER_AUTH_CORE_LOCK_MARKER = "@better-auth/core";
|
|
2454
2456
|
const findNearestPackageJsonPath$1 = (startDir) => {
|
|
2455
2457
|
let current = resolve(startDir);
|
|
2456
2458
|
while (true) {
|
|
@@ -2479,6 +2481,26 @@ const resolvePackageJsonInstallTarget = () => {
|
|
|
2479
2481
|
packageJson: packageJsonPath ? JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) : null
|
|
2480
2482
|
};
|
|
2481
2483
|
};
|
|
2484
|
+
const resolveBunPeerWarningPreinstallSpecs = () => {
|
|
2485
|
+
const { packageJsonPath, packageJson } = resolvePackageJsonInstallTarget();
|
|
2486
|
+
if (!packageJsonPath || !packageJson) return [];
|
|
2487
|
+
if (!(hasDependency(packageJson, "kitcn") || hasDependency(packageJson, "better-auth") || hasDependency(packageJson, "@convex-dev/better-auth"))) return [];
|
|
2488
|
+
if (hasDependency(packageJson, getPackageNameFromInstallSpec(OPENTELEMETRY_API_INSTALL_SPEC))) return [];
|
|
2489
|
+
const bunLockPath = join(dirname(packageJsonPath), BUN_LOCK_PATH);
|
|
2490
|
+
if (!fs.existsSync(bunLockPath)) return [];
|
|
2491
|
+
if (!fs.readFileSync(bunLockPath, "utf8").includes(BETTER_AUTH_CORE_LOCK_MARKER)) return [];
|
|
2492
|
+
return [OPENTELEMETRY_API_INSTALL_SPEC];
|
|
2493
|
+
};
|
|
2494
|
+
const applyBunPeerWarningPreinstall = async (execaFn) => {
|
|
2495
|
+
const dependencySpecs = resolveBunPeerWarningPreinstallSpecs();
|
|
2496
|
+
if (dependencySpecs.length === 0) return [];
|
|
2497
|
+
const { packageJsonPath } = resolvePackageJsonInstallTarget();
|
|
2498
|
+
await execaFn("bun", ["add", ...dependencySpecs], {
|
|
2499
|
+
cwd: dirname(packageJsonPath),
|
|
2500
|
+
stdio: "inherit"
|
|
2501
|
+
});
|
|
2502
|
+
return dependencySpecs;
|
|
2503
|
+
};
|
|
2482
2504
|
const inspectPluginDependencyInstall = async (params) => {
|
|
2483
2505
|
const packageName = params.descriptor.packageName;
|
|
2484
2506
|
const packageSpec = resolveSupportedDependencyInstallSpec(params.descriptor.packageInstallSpec ?? params.descriptor.packageName);
|
|
@@ -2512,27 +2534,30 @@ const resolveMissingDependencyHints = (dependencyHints) => {
|
|
|
2512
2534
|
return dependencyHints.filter((dependencyHint) => !hasDependency(packageJson, getPackageNameFromInstallSpec(dependencyHint)));
|
|
2513
2535
|
};
|
|
2514
2536
|
const applyDependencyHintsInstall = async (dependencyHints, execaFn) => {
|
|
2515
|
-
const
|
|
2516
|
-
|
|
2537
|
+
const preinstalledSpecs = await applyBunPeerWarningPreinstall(execaFn);
|
|
2538
|
+
const missingDependencyHints = resolveMissingDependencyHints(dependencyHints).filter((dependencyHint) => !preinstalledSpecs.includes(dependencyHint));
|
|
2539
|
+
if (missingDependencyHints.length === 0) return preinstalledSpecs;
|
|
2517
2540
|
const { packageJsonPath } = resolvePackageJsonInstallTarget();
|
|
2518
2541
|
await execaFn("bun", ["add", ...missingDependencyHints], {
|
|
2519
2542
|
cwd: dirname(packageJsonPath),
|
|
2520
2543
|
stdio: "inherit"
|
|
2521
2544
|
});
|
|
2522
|
-
return missingDependencyHints;
|
|
2545
|
+
return [...preinstalledSpecs, ...missingDependencyHints];
|
|
2523
2546
|
};
|
|
2524
2547
|
const applyPlanningDependencyInstall = async (dependencySpecs, execaFn) => {
|
|
2525
|
-
const
|
|
2526
|
-
|
|
2548
|
+
const preinstalledSpecs = await applyBunPeerWarningPreinstall(execaFn);
|
|
2549
|
+
const missingDependencySpecs = resolveMissingDependencyHints(dependencySpecs).filter((dependencySpec) => !preinstalledSpecs.includes(dependencySpec));
|
|
2550
|
+
if (missingDependencySpecs.length === 0) return preinstalledSpecs;
|
|
2527
2551
|
const { packageJsonPath } = resolvePackageJsonInstallTarget();
|
|
2528
2552
|
await execaFn("bun", ["add", ...missingDependencySpecs], {
|
|
2529
2553
|
cwd: dirname(packageJsonPath),
|
|
2530
2554
|
stdio: "inherit"
|
|
2531
2555
|
});
|
|
2532
|
-
return missingDependencySpecs;
|
|
2556
|
+
return [...preinstalledSpecs, ...missingDependencySpecs];
|
|
2533
2557
|
};
|
|
2534
2558
|
const applyPluginDependencyInstall = async (install, execaFn) => {
|
|
2535
2559
|
if (install.skipped || !install.packageName || !install.packageJsonPath) return install;
|
|
2560
|
+
await applyBunPeerWarningPreinstall(execaFn);
|
|
2536
2561
|
const packageSpec = install.packageSpec ?? install.packageName;
|
|
2537
2562
|
await execaFn("bun", ["add", packageSpec], {
|
|
2538
2563
|
cwd: dirname(install.packageJsonPath),
|
|
@@ -2723,6 +2748,53 @@ function QueryProvider({ children }: { children: ReactNode }) {
|
|
|
2723
2748
|
}
|
|
2724
2749
|
`;
|
|
2725
2750
|
|
|
2751
|
+
//#endregion
|
|
2752
|
+
//#region src/cli/registry/init/start/init-start-convex-provider.template.ts
|
|
2753
|
+
const INIT_START_CONVEX_PROVIDER_TEMPLATE = `'use client';
|
|
2754
|
+
|
|
2755
|
+
import { QueryClientProvider as TanstackQueryClientProvider } from '@tanstack/react-query';
|
|
2756
|
+
import {
|
|
2757
|
+
ConvexProvider,
|
|
2758
|
+
ConvexReactClient,
|
|
2759
|
+
getConvexQueryClientSingleton,
|
|
2760
|
+
getQueryClientSingleton,
|
|
2761
|
+
} from 'kitcn/react';
|
|
2762
|
+
import type { ReactNode } from 'react';
|
|
2763
|
+
|
|
2764
|
+
import { CRPCProvider } from '@/lib/convex/crpc';
|
|
2765
|
+
import { createQueryClient } from '@/lib/convex/query-client';
|
|
2766
|
+
|
|
2767
|
+
const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL!);
|
|
2768
|
+
|
|
2769
|
+
export function AppConvexProvider({
|
|
2770
|
+
children,
|
|
2771
|
+
}: {
|
|
2772
|
+
children: ReactNode;
|
|
2773
|
+
}) {
|
|
2774
|
+
return (
|
|
2775
|
+
<ConvexProvider client={convex}>
|
|
2776
|
+
<QueryProvider>{children}</QueryProvider>
|
|
2777
|
+
</ConvexProvider>
|
|
2778
|
+
);
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
function QueryProvider({ children }: { children: ReactNode }) {
|
|
2782
|
+
const queryClient = getQueryClientSingleton(createQueryClient);
|
|
2783
|
+
const convexQueryClient = getConvexQueryClientSingleton({
|
|
2784
|
+
convex,
|
|
2785
|
+
queryClient,
|
|
2786
|
+
});
|
|
2787
|
+
|
|
2788
|
+
return (
|
|
2789
|
+
<TanstackQueryClientProvider client={queryClient}>
|
|
2790
|
+
<CRPCProvider convexClient={convex} convexQueryClient={convexQueryClient}>
|
|
2791
|
+
{children}
|
|
2792
|
+
</CRPCProvider>
|
|
2793
|
+
</TanstackQueryClientProvider>
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
`;
|
|
2797
|
+
|
|
2726
2798
|
//#endregion
|
|
2727
2799
|
//#region src/cli/utils/content-compare.ts
|
|
2728
2800
|
const AST_COMPARABLE_EXTENSIONS = new Set([
|
|
@@ -3195,10 +3267,10 @@ const resolvePluginScaffoldFiles = (templates, roots, functionsDir, existingTemp
|
|
|
3195
3267
|
if (template.target === "lib") rootDir = roots.libRootDir;
|
|
3196
3268
|
else if (template.target === "functions") rootDir = roots.functionsRootDir;
|
|
3197
3269
|
else if (template.target === "app") {
|
|
3198
|
-
if (!roots.appRootDir) throw new Error(`${descriptor.label} scaffolding requires a supported app baseline. Run \`kitcn init --yes\` in a supported app, or bootstrap one with \`kitcn init -t <next|vite>\` first.`);
|
|
3270
|
+
if (!roots.appRootDir) throw new Error(`${descriptor.label} scaffolding requires a supported app baseline. Run \`kitcn init --yes\` in a supported app, or bootstrap one with \`kitcn init -t <next|start|vite>\` first.`);
|
|
3199
3271
|
rootDir = roots.appRootDir;
|
|
3200
3272
|
} else {
|
|
3201
|
-
if (!roots.clientLibRootDir) throw new Error(`${descriptor.label} scaffolding requires a supported app baseline. Run \`kitcn init --yes\` in a supported app, or bootstrap one with \`kitcn init -t <next|vite>\` first.`);
|
|
3273
|
+
if (!roots.clientLibRootDir) throw new Error(`${descriptor.label} scaffolding requires a supported app baseline. Run \`kitcn init --yes\` in a supported app, or bootstrap one with \`kitcn init -t <next|start|vite>\` first.`);
|
|
3202
3274
|
rootDir = roots.clientLibRootDir;
|
|
3203
3275
|
}
|
|
3204
3276
|
const mappedLockfilePath = existingTemplatePathMap?.[template.id];
|
|
@@ -4159,6 +4231,24 @@ export const authClient = createAuthClient({
|
|
|
4159
4231
|
plugins: [convexClient()],
|
|
4160
4232
|
});
|
|
4161
4233
|
|
|
4234
|
+
export const {
|
|
4235
|
+
useSignInMutationOptions,
|
|
4236
|
+
useSignOutMutationOptions,
|
|
4237
|
+
useSignUpMutationOptions,
|
|
4238
|
+
} = createAuthMutations(authClient);
|
|
4239
|
+
`;
|
|
4240
|
+
const AUTH_START_CLIENT_TEMPLATE = `import { createAuthClient } from 'better-auth/react';
|
|
4241
|
+
import { convexClient } from 'kitcn/auth/client';
|
|
4242
|
+
import { createAuthMutations } from 'kitcn/react';
|
|
4243
|
+
|
|
4244
|
+
export const authClient = createAuthClient({
|
|
4245
|
+
baseURL:
|
|
4246
|
+
typeof window === 'undefined'
|
|
4247
|
+
? (import.meta.env.VITE_SITE_URL as string | undefined)
|
|
4248
|
+
: window.location.origin,
|
|
4249
|
+
plugins: [convexClient()],
|
|
4250
|
+
});
|
|
4251
|
+
|
|
4162
4252
|
export const {
|
|
4163
4253
|
useSignInMutationOptions,
|
|
4164
4254
|
useSignOutMutationOptions,
|
|
@@ -4712,6 +4802,295 @@ export const authSchema = {
|
|
|
4712
4802
|
};
|
|
4713
4803
|
`;
|
|
4714
4804
|
|
|
4805
|
+
//#endregion
|
|
4806
|
+
//#region src/cli/registry/items/auth/auth-start-convex-provider.template.ts
|
|
4807
|
+
const AUTH_START_CONVEX_PROVIDER_TEMPLATE = `'use client';
|
|
4808
|
+
|
|
4809
|
+
import { QueryClientProvider as TanstackQueryClientProvider } from '@tanstack/react-query';
|
|
4810
|
+
import { ConvexAuthProvider } from 'kitcn/auth/client';
|
|
4811
|
+
import {
|
|
4812
|
+
ConvexReactClient,
|
|
4813
|
+
getConvexQueryClientSingleton,
|
|
4814
|
+
getQueryClientSingleton,
|
|
4815
|
+
useAuthStore,
|
|
4816
|
+
} from 'kitcn/react';
|
|
4817
|
+
import type { ReactNode } from 'react';
|
|
4818
|
+
|
|
4819
|
+
import { authClient } from '@/lib/convex/auth-client';
|
|
4820
|
+
import { CRPCProvider } from '@/lib/convex/crpc';
|
|
4821
|
+
import { createQueryClient } from '@/lib/convex/query-client';
|
|
4822
|
+
|
|
4823
|
+
const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL!);
|
|
4824
|
+
|
|
4825
|
+
export function AppConvexProvider({
|
|
4826
|
+
children,
|
|
4827
|
+
}: {
|
|
4828
|
+
children: ReactNode;
|
|
4829
|
+
}) {
|
|
4830
|
+
return (
|
|
4831
|
+
<ConvexAuthProvider authClient={authClient} client={convex}>
|
|
4832
|
+
<QueryProvider>{children}</QueryProvider>
|
|
4833
|
+
</ConvexAuthProvider>
|
|
4834
|
+
);
|
|
4835
|
+
}
|
|
4836
|
+
|
|
4837
|
+
function QueryProvider({ children }: { children: ReactNode }) {
|
|
4838
|
+
const authStore = useAuthStore();
|
|
4839
|
+
const queryClient = getQueryClientSingleton(createQueryClient);
|
|
4840
|
+
const convexQueryClient = getConvexQueryClientSingleton({
|
|
4841
|
+
authStore,
|
|
4842
|
+
convex,
|
|
4843
|
+
queryClient,
|
|
4844
|
+
});
|
|
4845
|
+
|
|
4846
|
+
return (
|
|
4847
|
+
<TanstackQueryClientProvider client={queryClient}>
|
|
4848
|
+
<CRPCProvider convexClient={convex} convexQueryClient={convexQueryClient}>
|
|
4849
|
+
{children}
|
|
4850
|
+
</CRPCProvider>
|
|
4851
|
+
</TanstackQueryClientProvider>
|
|
4852
|
+
);
|
|
4853
|
+
}
|
|
4854
|
+
`;
|
|
4855
|
+
|
|
4856
|
+
//#endregion
|
|
4857
|
+
//#region src/cli/registry/items/auth/auth-start-page.template.ts
|
|
4858
|
+
const AUTH_START_PAGE_TEMPLATE = `'use client';
|
|
4859
|
+
|
|
4860
|
+
import { useMutation } from '@tanstack/react-query';
|
|
4861
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
4862
|
+
import { useAuth } from 'kitcn/react';
|
|
4863
|
+
import { useState } from 'react';
|
|
4864
|
+
|
|
4865
|
+
import {
|
|
4866
|
+
authClient,
|
|
4867
|
+
useSignInMutationOptions,
|
|
4868
|
+
useSignOutMutationOptions,
|
|
4869
|
+
useSignUpMutationOptions,
|
|
4870
|
+
} from '@/lib/convex/auth-client';
|
|
4871
|
+
|
|
4872
|
+
export const Route = createFileRoute('/auth' as never)({
|
|
4873
|
+
component: AuthPage,
|
|
4874
|
+
});
|
|
4875
|
+
|
|
4876
|
+
function AuthPage() {
|
|
4877
|
+
const { hasSession, isLoading } = useAuth();
|
|
4878
|
+
const authSession = authClient.useSession();
|
|
4879
|
+
const session = authSession.data;
|
|
4880
|
+
const user = session?.user ?? null;
|
|
4881
|
+
const hasSignedInUser = hasSession || Boolean(user);
|
|
4882
|
+
const [mode, setMode] = useState<'signin' | 'signup'>('signin');
|
|
4883
|
+
const [name, setName] = useState('');
|
|
4884
|
+
const [email, setEmail] = useState('');
|
|
4885
|
+
const [password, setPassword] = useState('');
|
|
4886
|
+
|
|
4887
|
+
const signIn = useMutation(useSignInMutationOptions());
|
|
4888
|
+
const signUp = useMutation(useSignUpMutationOptions());
|
|
4889
|
+
const signOut = useMutation(useSignOutMutationOptions());
|
|
4890
|
+
|
|
4891
|
+
const errorMessage =
|
|
4892
|
+
signIn.error?.message ??
|
|
4893
|
+
signUp.error?.message ??
|
|
4894
|
+
signOut.error?.message ??
|
|
4895
|
+
null;
|
|
4896
|
+
const isPending =
|
|
4897
|
+
signIn.isPending || signUp.isPending || signOut.isPending;
|
|
4898
|
+
|
|
4899
|
+
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
|
4900
|
+
event.preventDefault();
|
|
4901
|
+
|
|
4902
|
+
if (mode === 'signup') {
|
|
4903
|
+
signUp.mutate({
|
|
4904
|
+
email,
|
|
4905
|
+
name,
|
|
4906
|
+
password,
|
|
4907
|
+
});
|
|
4908
|
+
return;
|
|
4909
|
+
}
|
|
4910
|
+
|
|
4911
|
+
signIn.mutate({
|
|
4912
|
+
email,
|
|
4913
|
+
password,
|
|
4914
|
+
});
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
if (isLoading && !hasSignedInUser) {
|
|
4918
|
+
return (
|
|
4919
|
+
<main className="mx-auto flex min-h-[60vh] max-w-md items-center px-6 py-16">
|
|
4920
|
+
<p className="text-sm text-muted-foreground">Loading auth…</p>
|
|
4921
|
+
</main>
|
|
4922
|
+
);
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
if (hasSignedInUser) {
|
|
4926
|
+
return (
|
|
4927
|
+
<main className="mx-auto flex min-h-[60vh] max-w-md flex-col justify-center gap-6 px-6 py-16">
|
|
4928
|
+
<div className="space-y-2">
|
|
4929
|
+
<p className="text-sm font-medium text-muted-foreground">Signed in</p>
|
|
4930
|
+
<h1 className="text-3xl font-semibold tracking-tight">
|
|
4931
|
+
{user?.name || user?.email || email}
|
|
4932
|
+
</h1>
|
|
4933
|
+
<p className="text-sm text-muted-foreground">
|
|
4934
|
+
{user?.email || email}
|
|
4935
|
+
</p>
|
|
4936
|
+
</div>
|
|
4937
|
+
<button
|
|
4938
|
+
className="rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition hover:opacity-90 disabled:opacity-60"
|
|
4939
|
+
disabled={isPending}
|
|
4940
|
+
onClick={() => signOut.mutate()}
|
|
4941
|
+
type="button"
|
|
4942
|
+
>
|
|
4943
|
+
{signOut.isPending ? 'Signing out…' : 'Sign out'}
|
|
4944
|
+
</button>
|
|
4945
|
+
</main>
|
|
4946
|
+
);
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4949
|
+
return (
|
|
4950
|
+
<main className="mx-auto flex min-h-[60vh] max-w-md flex-col justify-center gap-6 px-6 py-16">
|
|
4951
|
+
<div className="space-y-2">
|
|
4952
|
+
<p className="text-sm font-medium text-muted-foreground">Auth demo</p>
|
|
4953
|
+
<h1 className="text-3xl font-semibold tracking-tight">
|
|
4954
|
+
{mode === 'signup' ? 'Create an account' : 'Sign in'}
|
|
4955
|
+
</h1>
|
|
4956
|
+
<p className="text-sm text-muted-foreground">
|
|
4957
|
+
Minimal Better Auth wiring on top of the init baseline.
|
|
4958
|
+
</p>
|
|
4959
|
+
</div>
|
|
4960
|
+
|
|
4961
|
+
<form className="space-y-3" onSubmit={handleSubmit}>
|
|
4962
|
+
{mode === 'signup' ? (
|
|
4963
|
+
<input
|
|
4964
|
+
autoComplete="name"
|
|
4965
|
+
className="w-full rounded-md border bg-background px-3 py-2 text-sm"
|
|
4966
|
+
onChange={(event) => setName(event.target.value)}
|
|
4967
|
+
placeholder="Name"
|
|
4968
|
+
required
|
|
4969
|
+
type="text"
|
|
4970
|
+
value={name}
|
|
4971
|
+
/>
|
|
4972
|
+
) : null}
|
|
4973
|
+
<input
|
|
4974
|
+
autoComplete="email"
|
|
4975
|
+
className="w-full rounded-md border bg-background px-3 py-2 text-sm"
|
|
4976
|
+
onChange={(event) => setEmail(event.target.value)}
|
|
4977
|
+
placeholder="Email"
|
|
4978
|
+
required
|
|
4979
|
+
type="email"
|
|
4980
|
+
value={email}
|
|
4981
|
+
/>
|
|
4982
|
+
<input
|
|
4983
|
+
autoComplete={mode === 'signup' ? 'new-password' : 'current-password'}
|
|
4984
|
+
className="w-full rounded-md border bg-background px-3 py-2 text-sm"
|
|
4985
|
+
minLength={8}
|
|
4986
|
+
onChange={(event) => setPassword(event.target.value)}
|
|
4987
|
+
placeholder="Password"
|
|
4988
|
+
required
|
|
4989
|
+
type="password"
|
|
4990
|
+
value={password}
|
|
4991
|
+
/>
|
|
4992
|
+
<button
|
|
4993
|
+
className="w-full rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition hover:opacity-90 disabled:opacity-60"
|
|
4994
|
+
disabled={isPending}
|
|
4995
|
+
type="submit"
|
|
4996
|
+
>
|
|
4997
|
+
{isPending
|
|
4998
|
+
? 'Working…'
|
|
4999
|
+
: mode === 'signup'
|
|
5000
|
+
? 'Create account'
|
|
5001
|
+
: 'Sign in'}
|
|
5002
|
+
</button>
|
|
5003
|
+
</form>
|
|
5004
|
+
|
|
5005
|
+
<button
|
|
5006
|
+
className="text-left text-sm text-muted-foreground underline-offset-4 hover:underline"
|
|
5007
|
+
onClick={() => setMode(mode === 'signin' ? 'signup' : 'signin')}
|
|
5008
|
+
type="button"
|
|
5009
|
+
>
|
|
5010
|
+
{mode === 'signin'
|
|
5011
|
+
? "Don't have an account? Sign up"
|
|
5012
|
+
: 'Already have an account? Sign in'}
|
|
5013
|
+
</button>
|
|
5014
|
+
|
|
5015
|
+
{errorMessage ? (
|
|
5016
|
+
<p className="text-sm text-destructive">{errorMessage}</p>
|
|
5017
|
+
) : null}
|
|
5018
|
+
</main>
|
|
5019
|
+
);
|
|
5020
|
+
}
|
|
5021
|
+
`;
|
|
5022
|
+
|
|
5023
|
+
//#endregion
|
|
5024
|
+
//#region src/cli/registry/items/auth/auth-start-route.template.ts
|
|
5025
|
+
const AUTH_START_ROUTE_TEMPLATE = `import { createFileRoute } from '@tanstack/react-router';
|
|
5026
|
+
|
|
5027
|
+
import { handler } from '@/lib/convex/auth-server';
|
|
5028
|
+
|
|
5029
|
+
export const Route = createFileRoute('/api/auth/$' as never)({
|
|
5030
|
+
server: {
|
|
5031
|
+
handlers: {
|
|
5032
|
+
GET: ({ request }) => handler(request),
|
|
5033
|
+
POST: ({ request }) => handler(request),
|
|
5034
|
+
},
|
|
5035
|
+
},
|
|
5036
|
+
});
|
|
5037
|
+
`;
|
|
5038
|
+
|
|
5039
|
+
//#endregion
|
|
5040
|
+
//#region src/cli/registry/items/auth/auth-start-server.template.ts
|
|
5041
|
+
const AUTH_START_SERVER_TEMPLATE = `import { convexBetterAuthReactStart } from 'kitcn/auth/start';
|
|
5042
|
+
|
|
5043
|
+
export const {
|
|
5044
|
+
handler,
|
|
5045
|
+
getToken,
|
|
5046
|
+
fetchAuthQuery,
|
|
5047
|
+
fetchAuthMutation,
|
|
5048
|
+
fetchAuthAction,
|
|
5049
|
+
} = convexBetterAuthReactStart({
|
|
5050
|
+
convexUrl: import.meta.env.VITE_CONVEX_URL!,
|
|
5051
|
+
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
5052
|
+
});
|
|
5053
|
+
`;
|
|
5054
|
+
|
|
5055
|
+
//#endregion
|
|
5056
|
+
//#region src/cli/registry/items/auth/auth-start-server-call.template.ts
|
|
5057
|
+
const AUTH_START_SERVER_CALL_TEMPLATE = `import { api } from '@convex/api';
|
|
5058
|
+
import { getRequestHeaders } from '@tanstack/react-start/server';
|
|
5059
|
+
import { createCallerFactory } from 'kitcn/server';
|
|
5060
|
+
|
|
5061
|
+
import { getToken } from '@/lib/convex/auth-server';
|
|
5062
|
+
|
|
5063
|
+
const { createContext, createCaller } = createCallerFactory({
|
|
5064
|
+
api,
|
|
5065
|
+
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
5066
|
+
auth: {
|
|
5067
|
+
getToken: async () => {
|
|
5068
|
+
return {
|
|
5069
|
+
token: await getToken(),
|
|
5070
|
+
};
|
|
5071
|
+
},
|
|
5072
|
+
},
|
|
5073
|
+
});
|
|
5074
|
+
|
|
5075
|
+
type ServerCaller = ReturnType<typeof createCaller>;
|
|
5076
|
+
|
|
5077
|
+
async function makeContext() {
|
|
5078
|
+
const headers = await getRequestHeaders();
|
|
5079
|
+
return createContext({ headers });
|
|
5080
|
+
}
|
|
5081
|
+
|
|
5082
|
+
function createServerCaller(): ServerCaller {
|
|
5083
|
+
return createCaller(async () => {
|
|
5084
|
+
return await makeContext();
|
|
5085
|
+
});
|
|
5086
|
+
}
|
|
5087
|
+
|
|
5088
|
+
export function runServerCall<T>(fn: (caller: ServerCaller) => Promise<T> | T) {
|
|
5089
|
+
const caller = createServerCaller();
|
|
5090
|
+
return fn(caller);
|
|
5091
|
+
}
|
|
5092
|
+
`;
|
|
5093
|
+
|
|
4715
5094
|
//#endregion
|
|
4716
5095
|
//#region src/auth/auth-config.ts
|
|
4717
5096
|
const createPublicJwks = (jwks, options) => {
|
|
@@ -5493,11 +5872,21 @@ app.use(
|
|
|
5493
5872
|
updateReason: "Register auth middleware in http.ts.",
|
|
5494
5873
|
skipReason: "Auth middleware is already registered in http.ts."
|
|
5495
5874
|
});
|
|
5496
|
-
}
|
|
5497
|
-
function buildAuthProviderPlanFile(params) {
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5875
|
+
}
|
|
5876
|
+
function buildAuthProviderPlanFile(params) {
|
|
5877
|
+
const projectContext = params.roots.projectContext;
|
|
5878
|
+
if (!projectContext) throw new Error("Auth scaffolding requires a supported app baseline. Run `kitcn init --yes` in a supported app, or bootstrap one with `kitcn init -t <next|start|vite>` first.");
|
|
5879
|
+
if (projectContext.framework === "tanstack-start") return createPlanFile({
|
|
5880
|
+
kind: "scaffold",
|
|
5881
|
+
filePath: resolve(process.cwd(), projectContext.convexClientDir, "convex-provider.tsx"),
|
|
5882
|
+
content: AUTH_START_CONVEX_PROVIDER_TEMPLATE,
|
|
5883
|
+
managedBaselineContent: INIT_START_CONVEX_PROVIDER_TEMPLATE,
|
|
5884
|
+
createReason: "Create auth-aware kitcn provider for the app scaffold.",
|
|
5885
|
+
updateReason: "Update kitcn provider with auth-aware client wiring.",
|
|
5886
|
+
skipReason: "kitcn provider already matches the auth scaffold."
|
|
5887
|
+
});
|
|
5888
|
+
const providerPath = resolve(process.cwd(), projectContext.convexClientDir, "convex-provider.tsx");
|
|
5889
|
+
const isNextApp = projectContext.mode === "next-app";
|
|
5501
5890
|
return createPlanFile({
|
|
5502
5891
|
kind: "scaffold",
|
|
5503
5892
|
filePath: providerPath,
|
|
@@ -5533,6 +5922,54 @@ function buildAuthNextRoutePlanFile(params) {
|
|
|
5533
5922
|
skipReason: "The Next auth proxy route already exists."
|
|
5534
5923
|
});
|
|
5535
5924
|
}
|
|
5925
|
+
function buildAuthStartServerPlanFile(params) {
|
|
5926
|
+
const projectContext = params.roots.projectContext;
|
|
5927
|
+
if (!projectContext || projectContext.framework !== "tanstack-start") throw new Error("Auth scaffolding requires a supported TanStack Start shell.");
|
|
5928
|
+
return createPlanFile({
|
|
5929
|
+
kind: "scaffold",
|
|
5930
|
+
filePath: resolve(process.cwd(), projectContext.convexClientDir, "auth-server.ts"),
|
|
5931
|
+
content: AUTH_START_SERVER_TEMPLATE,
|
|
5932
|
+
createReason: "Create auth-aware Start server helpers.",
|
|
5933
|
+
updateReason: "Update Start server helpers with auth route support.",
|
|
5934
|
+
skipReason: "Start server helpers already include auth route support."
|
|
5935
|
+
});
|
|
5936
|
+
}
|
|
5937
|
+
function buildAuthStartRoutePlanFile(params) {
|
|
5938
|
+
const projectContext = params.roots.projectContext;
|
|
5939
|
+
if (!projectContext || projectContext.framework !== "tanstack-start") throw new Error("Auth scaffolding requires a supported TanStack Start shell.");
|
|
5940
|
+
return createPlanFile({
|
|
5941
|
+
kind: "scaffold",
|
|
5942
|
+
filePath: resolve(process.cwd(), projectContext.usesSrc ? "src" : "", "routes", "api", "auth", "$.ts"),
|
|
5943
|
+
content: AUTH_START_ROUTE_TEMPLATE,
|
|
5944
|
+
createReason: "Create the Start auth proxy route.",
|
|
5945
|
+
updateReason: "Update the Start auth proxy route.",
|
|
5946
|
+
skipReason: "The Start auth proxy route already exists."
|
|
5947
|
+
});
|
|
5948
|
+
}
|
|
5949
|
+
function buildAuthStartServerCallPlanFile(params) {
|
|
5950
|
+
const projectContext = params.roots.projectContext;
|
|
5951
|
+
if (!projectContext || projectContext.framework !== "tanstack-start") throw new Error("Auth scaffolding requires a supported TanStack Start shell.");
|
|
5952
|
+
return createPlanFile({
|
|
5953
|
+
kind: "scaffold",
|
|
5954
|
+
filePath: resolve(process.cwd(), projectContext.convexClientDir, "server.ts"),
|
|
5955
|
+
content: AUTH_START_SERVER_CALL_TEMPLATE,
|
|
5956
|
+
createReason: "Create auth-aware Start server caller helpers.",
|
|
5957
|
+
updateReason: "Update Start server caller helpers with auth token wiring.",
|
|
5958
|
+
skipReason: "Start server caller helpers already include auth token wiring."
|
|
5959
|
+
});
|
|
5960
|
+
}
|
|
5961
|
+
function buildAuthStartPagePlanFile(params) {
|
|
5962
|
+
const projectContext = params.roots.projectContext;
|
|
5963
|
+
if (!projectContext || projectContext.framework !== "tanstack-start") throw new Error("Auth scaffolding requires a supported TanStack Start shell.");
|
|
5964
|
+
return createPlanFile({
|
|
5965
|
+
kind: "scaffold",
|
|
5966
|
+
filePath: resolve(process.cwd(), projectContext.usesSrc ? "src" : "", "routes", "auth.tsx"),
|
|
5967
|
+
content: AUTH_START_PAGE_TEMPLATE,
|
|
5968
|
+
createReason: "Create the Start auth demo route.",
|
|
5969
|
+
updateReason: "Update the Start auth demo route.",
|
|
5970
|
+
skipReason: "The Start auth demo route already exists."
|
|
5971
|
+
});
|
|
5972
|
+
}
|
|
5536
5973
|
function buildAuthConvexLocalEnvPlanFile(params) {
|
|
5537
5974
|
const envPath = resolve(params.functionsDir, ".env");
|
|
5538
5975
|
return createPlanFile({
|
|
@@ -5669,6 +6106,13 @@ const authRegistryItem = defineInternalRegistryItem({
|
|
|
5669
6106
|
})),
|
|
5670
6107
|
resolveTemplates: ({ roots, templates }) => {
|
|
5671
6108
|
if (!roots.projectContext || roots.projectContext.mode === "next-app") return templates;
|
|
6109
|
+
if (roots.projectContext.framework === "tanstack-start") return templates.filter((template) => template.id !== "auth-page" && template.id !== "auth-page-convex").map((template) => {
|
|
6110
|
+
if (template.id === "auth-client") return {
|
|
6111
|
+
...template,
|
|
6112
|
+
content: AUTH_START_CLIENT_TEMPLATE
|
|
6113
|
+
};
|
|
6114
|
+
return template;
|
|
6115
|
+
});
|
|
5672
6116
|
return templates.filter((template) => template.id !== "auth-page" && template.id !== "auth-page-convex").map((template) => {
|
|
5673
6117
|
if (template.id === "auth-client") return {
|
|
5674
6118
|
...template,
|
|
@@ -5694,6 +6138,7 @@ const authRegistryItem = defineInternalRegistryItem({
|
|
|
5694
6138
|
buildAuthProviderPlanFile(params)
|
|
5695
6139
|
];
|
|
5696
6140
|
if (roots.projectContext?.mode === "next-app") files.push(buildAuthNextServerPlanFile(params), buildAuthNextRoutePlanFile(params));
|
|
6141
|
+
else if (roots.projectContext?.framework === "tanstack-start") files.push(buildAuthStartServerPlanFile(params), buildAuthStartRoutePlanFile(params), buildAuthStartServerCallPlanFile(params), buildAuthStartPagePlanFile(params));
|
|
5697
6142
|
return files;
|
|
5698
6143
|
},
|
|
5699
6144
|
buildSchemaRegistrationPlanFile: ({ applyScope, config, functionsDir, lockfile, overwrite, preset, preview, promptAdapter, roots, yes }) => buildAuthSchemaRegistrationPlanFile({
|
|
@@ -7379,6 +7824,8 @@ function renderInitConvexTsconfigTemplate(functionsDirRelative = "convex/functio
|
|
|
7379
7824
|
forceConsistentCasingInFileNames: true,
|
|
7380
7825
|
isolatedModules: true,
|
|
7381
7826
|
skipLibCheck: true,
|
|
7827
|
+
noUnusedLocals: false,
|
|
7828
|
+
noUnusedParameters: false,
|
|
7382
7829
|
noEmit: true,
|
|
7383
7830
|
jsx: "react-jsx",
|
|
7384
7831
|
lib: ["esnext", "dom"],
|
|
@@ -7577,7 +8024,10 @@ const INIT_NEXT_CONVEX_DEV_SCRIPT_NAME = "convex:dev";
|
|
|
7577
8024
|
const INIT_NEXT_CONVEX_DEV_SCRIPT = "kitcn dev";
|
|
7578
8025
|
const INIT_NEXT_CONVEX_TYPECHECK_SCRIPT_NAME = "typecheck:convex";
|
|
7579
8026
|
const getInitNextConvexTypecheckScript = (functionsDirRelative = "convex/functions") => `tsc --noEmit --project ${functionsDirRelative}/tsconfig.json`;
|
|
7580
|
-
const INIT_NEXT_PACKAGE_JSON_DEPENDENCIES = {
|
|
8027
|
+
const INIT_NEXT_PACKAGE_JSON_DEPENDENCIES = {
|
|
8028
|
+
"@opentelemetry/api": SUPPORTED_DEPENDENCY_VERSIONS.opentelemetryApi.exact,
|
|
8029
|
+
superjson: "2.2.6"
|
|
8030
|
+
};
|
|
7581
8031
|
const INIT_NEXT_PACKAGE_JSON_DEV_DEPENDENCIES = { "@types/bun": "latest" };
|
|
7582
8032
|
const getInitNextPackageJsonDevDependencies = (options) => ({
|
|
7583
8033
|
...INIT_NEXT_PACKAGE_JSON_DEV_DEPENDENCIES,
|
|
@@ -7786,7 +8236,10 @@ const INIT_REACT_CONVEX_DEV_SCRIPT_NAME = "convex:dev";
|
|
|
7786
8236
|
const INIT_REACT_CONVEX_DEV_SCRIPT = "kitcn dev";
|
|
7787
8237
|
const INIT_REACT_CONVEX_TYPECHECK_SCRIPT_NAME = "typecheck:convex";
|
|
7788
8238
|
const getInitReactConvexTypecheckScript = (functionsDirRelative = "convex/functions") => `tsc --noEmit --project ${functionsDirRelative}/tsconfig.json`;
|
|
7789
|
-
const INIT_REACT_PACKAGE_JSON_DEPENDENCIES = {
|
|
8239
|
+
const INIT_REACT_PACKAGE_JSON_DEPENDENCIES = {
|
|
8240
|
+
"@opentelemetry/api": SUPPORTED_DEPENDENCY_VERSIONS.opentelemetryApi.exact,
|
|
8241
|
+
superjson: "2.2.6"
|
|
8242
|
+
};
|
|
7790
8243
|
const INIT_REACT_PACKAGE_JSON_DEV_DEPENDENCIES = { "@types/bun": "latest" };
|
|
7791
8244
|
const getInitReactPackageJsonDevDependencies = (options) => ({
|
|
7792
8245
|
...INIT_REACT_PACKAGE_JSON_DEV_DEPENDENCIES,
|
|
@@ -7827,6 +8280,203 @@ export function Providers({ children }: { children: ReactNode }) {
|
|
|
7827
8280
|
}
|
|
7828
8281
|
`;
|
|
7829
8282
|
|
|
8283
|
+
//#endregion
|
|
8284
|
+
//#region src/cli/registry/init/start/init-start-crpc.template.ts
|
|
8285
|
+
const INIT_START_CRPC_TEMPLATE = `import { api } from '@convex/api';
|
|
8286
|
+
import { createCRPCContext } from 'kitcn/react';
|
|
8287
|
+
|
|
8288
|
+
export const { CRPCProvider, useCRPC, useCRPCClient } = createCRPCContext({
|
|
8289
|
+
api,
|
|
8290
|
+
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
8291
|
+
});
|
|
8292
|
+
`;
|
|
8293
|
+
|
|
8294
|
+
//#endregion
|
|
8295
|
+
//#region src/cli/registry/init/start/init-start-messages-page.template.ts
|
|
8296
|
+
const INIT_START_MESSAGES_PAGE_TEMPLATE = `'use client';
|
|
8297
|
+
|
|
8298
|
+
import { useMutation, useQuery } from '@tanstack/react-query';
|
|
8299
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
8300
|
+
import { type FormEvent, useState } from 'react';
|
|
8301
|
+
|
|
8302
|
+
import { Button } from '@/components/ui/button';
|
|
8303
|
+
import { useCRPC } from '@/lib/convex/crpc';
|
|
8304
|
+
|
|
8305
|
+
export const Route = createFileRoute('/')({
|
|
8306
|
+
component: ConvexMessagesPage,
|
|
8307
|
+
});
|
|
8308
|
+
|
|
8309
|
+
function ConvexMessagesPage() {
|
|
8310
|
+
const crpc = useCRPC();
|
|
8311
|
+
const [draft, setDraft] = useState('');
|
|
8312
|
+
const messagesQuery = useQuery(crpc.messages.list.queryOptions());
|
|
8313
|
+
const createMessage = useMutation(crpc.messages.create.mutationOptions());
|
|
8314
|
+
|
|
8315
|
+
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
|
|
8316
|
+
event.preventDefault();
|
|
8317
|
+
const body = draft.trim();
|
|
8318
|
+
if (!body) return;
|
|
8319
|
+
|
|
8320
|
+
try {
|
|
8321
|
+
await createMessage.mutateAsync({ body });
|
|
8322
|
+
setDraft('');
|
|
8323
|
+
} catch {}
|
|
8324
|
+
}
|
|
8325
|
+
|
|
8326
|
+
return (
|
|
8327
|
+
<main className="mx-auto flex min-h-svh w-full max-w-2xl flex-col gap-6 px-6 py-10 text-sm">
|
|
8328
|
+
<header className="space-y-2">
|
|
8329
|
+
<p className="font-mono text-xs uppercase tracking-[0.2em] text-muted-foreground">
|
|
8330
|
+
kitcn
|
|
8331
|
+
</p>
|
|
8332
|
+
<h1 className="font-medium text-2xl tracking-tight">Messages</h1>
|
|
8333
|
+
<p className="max-w-xl text-muted-foreground leading-6">
|
|
8334
|
+
This page is a tiny live query and mutation over kitcn. Start the
|
|
8335
|
+
backend, send a message, and watch the list update.
|
|
8336
|
+
</p>
|
|
8337
|
+
</header>
|
|
8338
|
+
|
|
8339
|
+
<form className="flex flex-col gap-3 sm:flex-row" onSubmit={handleSubmit}>
|
|
8340
|
+
<input
|
|
8341
|
+
className="min-h-10 flex-1 rounded-md border border-border bg-background px-3 py-2 outline-none transition-colors focus:border-primary"
|
|
8342
|
+
maxLength={120}
|
|
8343
|
+
onChange={(event) => setDraft(event.target.value)}
|
|
8344
|
+
placeholder="Write a message"
|
|
8345
|
+
value={draft}
|
|
8346
|
+
/>
|
|
8347
|
+
<Button disabled={createMessage.isPending || draft.trim().length === 0} type="submit">
|
|
8348
|
+
{createMessage.isPending ? 'Saving...' : 'Add message'}
|
|
8349
|
+
</Button>
|
|
8350
|
+
</form>
|
|
8351
|
+
|
|
8352
|
+
{messagesQuery.isPending ? (
|
|
8353
|
+
<p className="text-muted-foreground">Loading messages...</p>
|
|
8354
|
+
) : messagesQuery.isError ? (
|
|
8355
|
+
<div className="rounded-md border border-dashed border-border px-4 py-3 text-muted-foreground leading-6">
|
|
8356
|
+
Backend not ready. Start <code>kitcn dev</code> and refresh.
|
|
8357
|
+
</div>
|
|
8358
|
+
) : messagesQuery.data.length === 0 ? (
|
|
8359
|
+
<div className="rounded-md border border-dashed border-border px-4 py-6 text-muted-foreground">
|
|
8360
|
+
No messages yet. Add the first one.
|
|
8361
|
+
</div>
|
|
8362
|
+
) : (
|
|
8363
|
+
<ul className="space-y-3">
|
|
8364
|
+
{messagesQuery.data.map((message) => (
|
|
8365
|
+
<li
|
|
8366
|
+
className="rounded-md border border-border bg-background px-4 py-3"
|
|
8367
|
+
key={message.id}
|
|
8368
|
+
>
|
|
8369
|
+
<div className="flex items-start justify-between gap-3">
|
|
8370
|
+
<p className="leading-6">{message.body}</p>
|
|
8371
|
+
<time className="shrink-0 font-mono text-xs text-muted-foreground">
|
|
8372
|
+
{message.createdAt.toLocaleTimeString()}
|
|
8373
|
+
</time>
|
|
8374
|
+
</div>
|
|
8375
|
+
</li>
|
|
8376
|
+
))}
|
|
8377
|
+
</ul>
|
|
8378
|
+
)}
|
|
8379
|
+
</main>
|
|
8380
|
+
);
|
|
8381
|
+
}
|
|
8382
|
+
`;
|
|
8383
|
+
|
|
8384
|
+
//#endregion
|
|
8385
|
+
//#region src/cli/registry/init/start/init-start-root.template.ts
|
|
8386
|
+
const INIT_START_ROOT_TEMPLATE = `import {
|
|
8387
|
+
HeadContent,
|
|
8388
|
+
Outlet,
|
|
8389
|
+
Scripts,
|
|
8390
|
+
createRootRoute,
|
|
8391
|
+
} from '@tanstack/react-router';
|
|
8392
|
+
import { TanStackDevtools } from '@tanstack/react-devtools';
|
|
8393
|
+
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools';
|
|
8394
|
+
|
|
8395
|
+
import { Providers } from '@/components/providers';
|
|
8396
|
+
import appCss from '../styles.css?url';
|
|
8397
|
+
|
|
8398
|
+
export const Route = createRootRoute({
|
|
8399
|
+
head: () => ({
|
|
8400
|
+
meta: [
|
|
8401
|
+
{
|
|
8402
|
+
charSet: 'utf-8',
|
|
8403
|
+
},
|
|
8404
|
+
{
|
|
8405
|
+
name: 'viewport',
|
|
8406
|
+
content: 'width=device-width, initial-scale=1',
|
|
8407
|
+
},
|
|
8408
|
+
{
|
|
8409
|
+
title: 'TanStack Start Starter',
|
|
8410
|
+
},
|
|
8411
|
+
],
|
|
8412
|
+
links: [
|
|
8413
|
+
{
|
|
8414
|
+
rel: 'stylesheet',
|
|
8415
|
+
href: appCss,
|
|
8416
|
+
},
|
|
8417
|
+
],
|
|
8418
|
+
}),
|
|
8419
|
+
component: RootComponent,
|
|
8420
|
+
shellComponent: RootDocument,
|
|
8421
|
+
});
|
|
8422
|
+
|
|
8423
|
+
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
8424
|
+
return (
|
|
8425
|
+
<html lang="en">
|
|
8426
|
+
<head>
|
|
8427
|
+
<HeadContent />
|
|
8428
|
+
</head>
|
|
8429
|
+
<body>
|
|
8430
|
+
{children}
|
|
8431
|
+
<TanStackDevtools
|
|
8432
|
+
config={{
|
|
8433
|
+
position: 'bottom-right',
|
|
8434
|
+
}}
|
|
8435
|
+
plugins={[
|
|
8436
|
+
{
|
|
8437
|
+
name: 'Tanstack Router',
|
|
8438
|
+
render: <TanStackRouterDevtoolsPanel />,
|
|
8439
|
+
},
|
|
8440
|
+
]}
|
|
8441
|
+
/>
|
|
8442
|
+
<Scripts />
|
|
8443
|
+
</body>
|
|
8444
|
+
</html>
|
|
8445
|
+
);
|
|
8446
|
+
}
|
|
8447
|
+
|
|
8448
|
+
function RootComponent() {
|
|
8449
|
+
return (
|
|
8450
|
+
<Providers>
|
|
8451
|
+
<Outlet />
|
|
8452
|
+
</Providers>
|
|
8453
|
+
);
|
|
8454
|
+
}
|
|
8455
|
+
`;
|
|
8456
|
+
|
|
8457
|
+
//#endregion
|
|
8458
|
+
//#region src/cli/registry/init/start/init-start-router.template.ts
|
|
8459
|
+
const INIT_START_ROUTER_TEMPLATE = `import { createRouter } from '@tanstack/react-router';
|
|
8460
|
+
import { routeTree } from './routeTree.gen';
|
|
8461
|
+
|
|
8462
|
+
export function getRouter() {
|
|
8463
|
+
const router = createRouter({
|
|
8464
|
+
routeTree,
|
|
8465
|
+
scrollRestoration: true,
|
|
8466
|
+
defaultPreload: 'intent',
|
|
8467
|
+
defaultPreloadStaleTime: 0,
|
|
8468
|
+
});
|
|
8469
|
+
|
|
8470
|
+
return router;
|
|
8471
|
+
}
|
|
8472
|
+
|
|
8473
|
+
declare module '@tanstack/react-router' {
|
|
8474
|
+
interface Register {
|
|
8475
|
+
router: ReturnType<typeof getRouter>;
|
|
8476
|
+
}
|
|
8477
|
+
}
|
|
8478
|
+
`;
|
|
8479
|
+
|
|
7830
8480
|
//#endregion
|
|
7831
8481
|
//#region src/cli/registry/selection.ts
|
|
7832
8482
|
const getPluginDisplayHint = (descriptor) => descriptor.presets[0]?.description;
|
|
@@ -8288,6 +8938,7 @@ const realConvex = join(dirname(require.resolve("convex/package.json")), "bin/ma
|
|
|
8288
8938
|
const MISSING_BACKFILL_FUNCTION_RE = /could not find function|function .* was not found|unknown function/i;
|
|
8289
8939
|
const GITIGNORE_RUNTIME_ENTRIES = [".convex/", ".concave/"];
|
|
8290
8940
|
const TS_EXTENSION_RE = /\.ts$/;
|
|
8941
|
+
const LEADING_SLASHES_RE = /^\/+/;
|
|
8291
8942
|
const AGGREGATE_STATE_RELATIVE_PATH = join(".convex", "kitcn", "aggregate-backfill-state.json");
|
|
8292
8943
|
const AGGREGATE_STATE_VERSION = 1;
|
|
8293
8944
|
const INIT_SHADCN_PACKAGE_SPEC = "shadcn@4.0.1";
|
|
@@ -8323,7 +8974,11 @@ const VALID_SCOPES = new Set([
|
|
|
8323
8974
|
const VALID_BACKENDS = new Set(["convex", "concave"]);
|
|
8324
8975
|
const SUPPORTED_PLUGINS = new Set(getSupportedPluginKeys());
|
|
8325
8976
|
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8326
|
-
const SUPPORTED_INIT_TEMPLATES = [
|
|
8977
|
+
const SUPPORTED_INIT_TEMPLATES = [
|
|
8978
|
+
"next",
|
|
8979
|
+
"start",
|
|
8980
|
+
"vite"
|
|
8981
|
+
];
|
|
8327
8982
|
const REACT_APP_MOUNT_RE = /<App\s*\/>/;
|
|
8328
8983
|
const DOCS_BASE_URL = "https://kitcn.vercel.app/docs";
|
|
8329
8984
|
const CORE_DOC_TOPICS = {
|
|
@@ -8918,9 +9573,129 @@ function buildInitReactOwnedScaffoldFiles(context, functionsDirRelative, backend
|
|
|
8918
9573
|
}
|
|
8919
9574
|
];
|
|
8920
9575
|
}
|
|
9576
|
+
function buildInitStartOwnedScaffoldFiles(context, functionsDirRelative, backend, includeDemoFiles) {
|
|
9577
|
+
const rootPrefix = context.usesSrc ? "src" : "";
|
|
9578
|
+
const files = [
|
|
9579
|
+
{
|
|
9580
|
+
kind: "config",
|
|
9581
|
+
relativePath: "package.json",
|
|
9582
|
+
requiresExplicitOverwrite: false,
|
|
9583
|
+
content: ({ existingContent }) => renderInitReactPackageJsonTemplate(existingContent, {
|
|
9584
|
+
backend,
|
|
9585
|
+
functionsDirRelative
|
|
9586
|
+
}),
|
|
9587
|
+
createReason: "Create baseline package.json scripts for the Start scaffold.",
|
|
9588
|
+
updateReason: "Update package.json scripts for the Start scaffold.",
|
|
9589
|
+
skipReason: "package.json scripts already match the Start scaffold."
|
|
9590
|
+
},
|
|
9591
|
+
{
|
|
9592
|
+
kind: "env",
|
|
9593
|
+
relativePath: ".env.local",
|
|
9594
|
+
requiresExplicitOverwrite: false,
|
|
9595
|
+
content: ({ existingContent }) => renderInitReactEnvLocalTemplate(existingContent),
|
|
9596
|
+
createReason: "Create baseline .env.local for the Start scaffold.",
|
|
9597
|
+
updateReason: "Update baseline .env.local for the Start scaffold.",
|
|
9598
|
+
skipReason: ".env.local already matches the Start scaffold."
|
|
9599
|
+
},
|
|
9600
|
+
{
|
|
9601
|
+
kind: "scaffold",
|
|
9602
|
+
relativePath: `${context.componentsDir}/providers.tsx`,
|
|
9603
|
+
requiresExplicitOverwrite: true,
|
|
9604
|
+
content: INIT_REACT_PROVIDERS_TEMPLATE,
|
|
9605
|
+
createReason: `Create baseline ${context.componentsDir}/providers.tsx for the Start scaffold.`,
|
|
9606
|
+
updateReason: `Update ${context.componentsDir}/providers.tsx for the Start scaffold.`,
|
|
9607
|
+
skipReason: `${context.componentsDir}/providers.tsx already matches the Start scaffold.`
|
|
9608
|
+
},
|
|
9609
|
+
{
|
|
9610
|
+
kind: "scaffold",
|
|
9611
|
+
relativePath: `${context.convexClientDir}/query-client.ts`,
|
|
9612
|
+
requiresExplicitOverwrite: true,
|
|
9613
|
+
content: INIT_NEXT_QUERY_CLIENT_TEMPLATE,
|
|
9614
|
+
createReason: `Create baseline ${context.convexClientDir}/query-client.ts for the Start scaffold.`,
|
|
9615
|
+
updateReason: `Update ${context.convexClientDir}/query-client.ts for the Start scaffold.`,
|
|
9616
|
+
skipReason: `${context.convexClientDir}/query-client.ts already matches the Start scaffold.`
|
|
9617
|
+
},
|
|
9618
|
+
{
|
|
9619
|
+
kind: "scaffold",
|
|
9620
|
+
relativePath: `${context.convexClientDir}/crpc.tsx`,
|
|
9621
|
+
requiresExplicitOverwrite: true,
|
|
9622
|
+
content: INIT_START_CRPC_TEMPLATE,
|
|
9623
|
+
createReason: `Create baseline ${context.convexClientDir}/crpc.tsx for the Start scaffold.`,
|
|
9624
|
+
updateReason: `Update ${context.convexClientDir}/crpc.tsx for the Start scaffold.`,
|
|
9625
|
+
skipReason: `${context.convexClientDir}/crpc.tsx already matches the Start scaffold.`
|
|
9626
|
+
},
|
|
9627
|
+
{
|
|
9628
|
+
kind: "scaffold",
|
|
9629
|
+
relativePath: `${context.convexClientDir}/convex-provider.tsx`,
|
|
9630
|
+
requiresExplicitOverwrite: true,
|
|
9631
|
+
content: INIT_START_CONVEX_PROVIDER_TEMPLATE,
|
|
9632
|
+
preserveManagedContent: [AUTH_START_CONVEX_PROVIDER_TEMPLATE],
|
|
9633
|
+
createReason: `Create baseline ${context.convexClientDir}/convex-provider.tsx for the Start scaffold.`,
|
|
9634
|
+
updateReason: `Update ${context.convexClientDir}/convex-provider.tsx for the Start scaffold.`,
|
|
9635
|
+
skipReason: `${context.convexClientDir}/convex-provider.tsx already matches the Start scaffold.`
|
|
9636
|
+
},
|
|
9637
|
+
{
|
|
9638
|
+
kind: "scaffold",
|
|
9639
|
+
relativePath: trimLeadingSlashes(posix.join(rootPrefix, "router.tsx")),
|
|
9640
|
+
requiresExplicitOverwrite: true,
|
|
9641
|
+
content: INIT_START_ROUTER_TEMPLATE,
|
|
9642
|
+
createReason: `Create baseline ${trimLeadingSlashes(posix.join(rootPrefix, "router.tsx"))} for the Start scaffold.`,
|
|
9643
|
+
updateReason: `Update ${trimLeadingSlashes(posix.join(rootPrefix, "router.tsx"))} for the Start scaffold.`,
|
|
9644
|
+
skipReason: `${trimLeadingSlashes(posix.join(rootPrefix, "router.tsx"))} already matches the Start scaffold.`
|
|
9645
|
+
},
|
|
9646
|
+
{
|
|
9647
|
+
kind: "scaffold",
|
|
9648
|
+
relativePath: trimLeadingSlashes(posix.join(rootPrefix, "routes", "__root.tsx")),
|
|
9649
|
+
requiresExplicitOverwrite: true,
|
|
9650
|
+
content: INIT_START_ROOT_TEMPLATE,
|
|
9651
|
+
createReason: `Create baseline ${trimLeadingSlashes(posix.join(rootPrefix, "routes", "__root.tsx"))} for the Start scaffold.`,
|
|
9652
|
+
updateReason: `Update ${trimLeadingSlashes(posix.join(rootPrefix, "routes", "__root.tsx"))} for the Start scaffold.`,
|
|
9653
|
+
skipReason: `${trimLeadingSlashes(posix.join(rootPrefix, "routes", "__root.tsx"))} already matches the Start scaffold.`
|
|
9654
|
+
},
|
|
9655
|
+
{
|
|
9656
|
+
kind: "config",
|
|
9657
|
+
relativePath: join(functionsDirRelative, "tsconfig.json"),
|
|
9658
|
+
managedBaselineContent: getManagedConvexTsconfigBaselines(functionsDirRelative),
|
|
9659
|
+
requiresExplicitOverwrite: true,
|
|
9660
|
+
content: ({ existingContent }) => typeof existingContent === "string" ? patchInitConvexTsconfigContent(existingContent, functionsDirRelative) : renderInitConvexTsconfigTemplate(functionsDirRelative),
|
|
9661
|
+
createReason: `Create ${join(functionsDirRelative, "tsconfig.json")} for kitcn functions.`,
|
|
9662
|
+
updateReason: `Patch ${join(functionsDirRelative, "tsconfig.json")} for kitcn functions.`,
|
|
9663
|
+
skipReason: `${join(functionsDirRelative, "tsconfig.json")} already matches the kitcn functions project.`
|
|
9664
|
+
}
|
|
9665
|
+
];
|
|
9666
|
+
if (includeDemoFiles) files.push({
|
|
9667
|
+
kind: "scaffold",
|
|
9668
|
+
relativePath: trimLeadingSlashes(posix.join(rootPrefix, "routes", "index.tsx")),
|
|
9669
|
+
requiresExplicitOverwrite: false,
|
|
9670
|
+
content: INIT_START_MESSAGES_PAGE_TEMPLATE,
|
|
9671
|
+
createReason: `Create ${trimLeadingSlashes(posix.join(rootPrefix, "routes", "index.tsx"))} as the minimal kitcn demo route.`,
|
|
9672
|
+
updateReason: `Update ${trimLeadingSlashes(posix.join(rootPrefix, "routes", "index.tsx"))} for the kitcn demo route.`,
|
|
9673
|
+
skipReason: `${trimLeadingSlashes(posix.join(rootPrefix, "routes", "index.tsx"))} already matches the kitcn demo route.`
|
|
9674
|
+
}, {
|
|
9675
|
+
kind: "schema",
|
|
9676
|
+
relativePath: `${functionsDirRelative}/schema.ts`,
|
|
9677
|
+
requiresExplicitOverwrite: true,
|
|
9678
|
+
content: INIT_NEXT_SCHEMA_TEMPLATE,
|
|
9679
|
+
createReason: `Create ${functionsDirRelative}/schema.ts with the minimal kitcn demo schema.`,
|
|
9680
|
+
updateReason: `Update ${functionsDirRelative}/schema.ts with the minimal kitcn demo schema.`,
|
|
9681
|
+
skipReason: `${functionsDirRelative}/schema.ts already matches the kitcn demo schema.`
|
|
9682
|
+
}, {
|
|
9683
|
+
kind: "scaffold",
|
|
9684
|
+
relativePath: `${functionsDirRelative}/messages.ts`,
|
|
9685
|
+
requiresExplicitOverwrite: true,
|
|
9686
|
+
content: renderInitNextMessagesTemplate(functionsDirRelative),
|
|
9687
|
+
createReason: `Create ${functionsDirRelative}/messages.ts for the kitcn demo route.`,
|
|
9688
|
+
updateReason: `Update ${functionsDirRelative}/messages.ts for the kitcn demo route.`,
|
|
9689
|
+
skipReason: `${functionsDirRelative}/messages.ts already matches the kitcn demo route.`
|
|
9690
|
+
});
|
|
9691
|
+
return files;
|
|
9692
|
+
}
|
|
8921
9693
|
function detectImportQuote(source) {
|
|
8922
9694
|
return source.match(INIT_NEXT_IMPORT_QUOTE_RE)?.[1] === "'" ? "'" : "\"";
|
|
8923
9695
|
}
|
|
9696
|
+
function trimLeadingSlashes(value) {
|
|
9697
|
+
return value.replace(LEADING_SLASHES_RE, "");
|
|
9698
|
+
}
|
|
8924
9699
|
function detectStatementTerminator(source) {
|
|
8925
9700
|
return INIT_NEXT_IMPORT_SEMICOLON_RE.test(source) ? ";" : "";
|
|
8926
9701
|
}
|
|
@@ -8963,6 +9738,25 @@ function patchInitTsconfigContent(source, context) {
|
|
|
8963
9738
|
}
|
|
8964
9739
|
}, null, 2)}\n`;
|
|
8965
9740
|
}
|
|
9741
|
+
function patchInitStartTsconfigContent(source, context) {
|
|
9742
|
+
const parsedResult = ts.parseConfigFileTextToJson("tsconfig.json", source);
|
|
9743
|
+
if (parsedResult.error || parsedResult.config === void 0) throw new Error("Could not patch tsconfig.json: expected valid JSON or JSONC scaffold output.");
|
|
9744
|
+
const parsed = parsedResult.config;
|
|
9745
|
+
if (!isPlainObject(parsed)) throw new Error("Could not patch tsconfig.json: expected a top-level JSON object.");
|
|
9746
|
+
const compilerOptions = isPlainObject(parsed.compilerOptions) ? { ...parsed.compilerOptions } : {};
|
|
9747
|
+
const paths = isPlainObject(compilerOptions.paths) ? { ...compilerOptions.paths } : {};
|
|
9748
|
+
if (!("@/*" in paths)) paths["@/*"] = [context.tsconfigAliasPath];
|
|
9749
|
+
paths["@convex/*"] = ["./convex/shared/*"];
|
|
9750
|
+
return `${JSON.stringify({
|
|
9751
|
+
...parsed,
|
|
9752
|
+
compilerOptions: {
|
|
9753
|
+
...compilerOptions,
|
|
9754
|
+
strictFunctionTypes: false,
|
|
9755
|
+
paths
|
|
9756
|
+
},
|
|
9757
|
+
...context.usesSrc ? { include: ["src"] } : {}
|
|
9758
|
+
}, null, 2)}\n`;
|
|
9759
|
+
}
|
|
8966
9760
|
function patchInitConvexTsconfigContent(source, functionsDirRelative) {
|
|
8967
9761
|
const parsedResult = ts.parseConfigFileTextToJson("tsconfig.json", source);
|
|
8968
9762
|
if (parsedResult.error || parsedResult.config === void 0) throw new Error("Could not patch Convex tsconfig.json: expected valid JSON or JSONC scaffold output.");
|
|
@@ -9074,6 +9868,7 @@ function patchInitReactMainContent(source) {
|
|
|
9074
9868
|
}
|
|
9075
9869
|
function patchInitReactViteConfigContent(source) {
|
|
9076
9870
|
if (source.includes("'@convex'") || source.includes("\"@convex\"")) return source.endsWith("\n") ? source : `${source}\n`;
|
|
9871
|
+
if (source.includes("viteTsConfigPaths(") || source.includes("tsConfigPaths(")) return source.endsWith("\n") ? source : `${source}\n`;
|
|
9077
9872
|
if (!source.includes("alias: {")) throw new Error("Could not patch vite.config.ts: expected a resolve.alias block.");
|
|
9078
9873
|
const nextSource = source.replace("alias: {", `alias: {\n '@convex': path.resolve(__dirname, './convex/shared'),`);
|
|
9079
9874
|
return nextSource.endsWith("\n") ? nextSource : `${nextSource}\n`;
|
|
@@ -9133,7 +9928,7 @@ function buildInitReactRootTsconfigPlanFile(context) {
|
|
|
9133
9928
|
kind: "config",
|
|
9134
9929
|
filePath,
|
|
9135
9930
|
requiresExplicitOverwrite: false,
|
|
9136
|
-
content: patchInitTsconfigContent(fs.readFileSync(filePath, "utf8"), context),
|
|
9931
|
+
content: context.framework === "tanstack-start" ? patchInitStartTsconfigContent(fs.readFileSync(filePath, "utf8"), context) : patchInitTsconfigContent(fs.readFileSync(filePath, "utf8"), context),
|
|
9137
9932
|
updateReason: "Patch tsconfig.json to keep the app alias and add @convex/*.",
|
|
9138
9933
|
createReason: "Patch tsconfig.json to keep the app alias and add @convex/*.",
|
|
9139
9934
|
skipReason: "tsconfig.json already includes the kitcn alias."
|
|
@@ -9225,7 +10020,7 @@ function buildTemplateInitializationPlanFiles(params) {
|
|
|
9225
10020
|
allowUnsupported: true
|
|
9226
10021
|
});
|
|
9227
10022
|
if (!projectContext) return [];
|
|
9228
|
-
const plannedOwnedFiles = (projectContext.mode === "next-app" ? buildInitNextOwnedScaffoldFiles(projectContext, params.functionsDirRelative, params.backend, params.includeDemoFiles) : buildInitReactOwnedScaffoldFiles(projectContext, params.functionsDirRelative, params.backend)).map((file) => {
|
|
10023
|
+
const plannedOwnedFiles = (projectContext.mode === "next-app" ? buildInitNextOwnedScaffoldFiles(projectContext, params.functionsDirRelative, params.backend, params.includeDemoFiles) : projectContext.framework === "tanstack-start" ? buildInitStartOwnedScaffoldFiles(projectContext, params.functionsDirRelative, params.backend, params.includeDemoFiles) : buildInitReactOwnedScaffoldFiles(projectContext, params.functionsDirRelative, params.backend)).map((file) => {
|
|
9229
10024
|
const filePath = resolve(process.cwd(), file.relativePath);
|
|
9230
10025
|
const existingContent = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : void 0;
|
|
9231
10026
|
const nextContent = typeof file.content === "function" ? file.content({ existingContent }) : file.content;
|
|
@@ -9255,6 +10050,11 @@ function buildTemplateInitializationPlanFiles(params) {
|
|
|
9255
10050
|
buildInitNextLayoutPlanFile(projectContext)
|
|
9256
10051
|
];
|
|
9257
10052
|
}
|
|
10053
|
+
if (projectContext.framework === "tanstack-start") return [
|
|
10054
|
+
...plannedOwnedFiles,
|
|
10055
|
+
buildInitReactRootTsconfigPlanFile(projectContext),
|
|
10056
|
+
...buildInitReactViteConfigPlanFile(projectContext)
|
|
10057
|
+
];
|
|
9258
10058
|
return [
|
|
9259
10059
|
...plannedOwnedFiles,
|
|
9260
10060
|
buildInitReactRootTsconfigPlanFile(projectContext),
|
|
@@ -9483,7 +10283,7 @@ async function runScaffoldCommandFlow(params) {
|
|
|
9483
10283
|
template: params.template
|
|
9484
10284
|
});
|
|
9485
10285
|
const applyResult = await applyPluginInstallPlanFiles(initPlan.files, {
|
|
9486
|
-
overwrite: Boolean(params.overwrite),
|
|
10286
|
+
overwrite: Boolean(params.overwrite) || params.template !== void 0,
|
|
9487
10287
|
yes: params.yes || Boolean(params.defaults),
|
|
9488
10288
|
promptAdapter: params.promptAdapter
|
|
9489
10289
|
});
|
|
@@ -9533,7 +10333,7 @@ async function runInitCommandFlow(params) {
|
|
|
9533
10333
|
allowUnsupported: true
|
|
9534
10334
|
});
|
|
9535
10335
|
if (template !== void 0 || params.initArgs.defaults || params.initArgs.name !== void 0) {
|
|
9536
|
-
if (!template) throw new Error("Fresh app scaffolding requires `kitcn init -t <next|vite>`.");
|
|
10336
|
+
if (!template) throw new Error("Fresh app scaffolding requires `kitcn init -t <next|start|vite>`.");
|
|
9537
10337
|
if (existingProjectContext) throw new Error(`Existing supported app scaffold detected. Run \`kitcn init --yes\` in ${normalizePath(relative(process.cwd(), projectDir) || ".")} to adopt the current project.`);
|
|
9538
10338
|
return runScaffoldCommandFlow({
|
|
9539
10339
|
allowCodegenBootstrapFallback: !params.initArgs.json,
|
|
@@ -9555,7 +10355,7 @@ async function runInitCommandFlow(params) {
|
|
|
9555
10355
|
realConcavePath: params.realConcavePath
|
|
9556
10356
|
});
|
|
9557
10357
|
}
|
|
9558
|
-
if (!existingProjectContext) throw new Error("Could not detect a supported app scaffold. Use `kitcn init -t <next|vite>` for a fresh app.");
|
|
10358
|
+
if (!existingProjectContext) throw new Error("Could not detect a supported app scaffold. Use `kitcn init -t <next|start|vite>` for a fresh app.");
|
|
9559
10359
|
return runScaffoldCommandFlow({
|
|
9560
10360
|
allowCodegenBootstrapFallback: !params.initArgs.json,
|
|
9561
10361
|
projectDir,
|
|
@@ -10008,7 +10808,7 @@ async function runConvexInitIfNeeded(params) {
|
|
|
10008
10808
|
stdout: "",
|
|
10009
10809
|
stderr: ""
|
|
10010
10810
|
};
|
|
10011
|
-
const
|
|
10811
|
+
const agentModeOverride = params.yes && !hasRemoteConvexInitTargetArgs(params.targetArgs) ? "anonymous" : params.env?.CONVEX_AGENT_MODE;
|
|
10012
10812
|
const result = normalizeConvexCommandResult(await params.execaFn(params.backendAdapter.command, [
|
|
10013
10813
|
...params.backendAdapter.argsPrefix,
|
|
10014
10814
|
"init",
|
|
@@ -10017,7 +10817,7 @@ async function runConvexInitIfNeeded(params) {
|
|
|
10017
10817
|
cwd: process.cwd(),
|
|
10018
10818
|
env: createBackendCommandEnv({
|
|
10019
10819
|
...params.env,
|
|
10020
|
-
CONVEX_AGENT_MODE:
|
|
10820
|
+
...agentModeOverride ? { CONVEX_AGENT_MODE: agentModeOverride } : {}
|
|
10021
10821
|
}),
|
|
10022
10822
|
reject: false,
|
|
10023
10823
|
stdio: "pipe"
|
|
@@ -11953,6 +12753,7 @@ const handleAddCommand = async (argv, deps = {}) => {
|
|
|
11953
12753
|
templates: selectedTemplates
|
|
11954
12754
|
})) throw new Error(AUTH_SCHEMA_ONLY_MISSING_ERROR);
|
|
11955
12755
|
}
|
|
12756
|
+
if (rawConvexAuthPreset && !addArgs.dryRun) assertRawConvexAuthDeploymentReady();
|
|
11956
12757
|
if (!addArgs.dryRun) await applyPlanningDependencyInstall(pluginDescriptor.planningDependencies ?? [], execaFn);
|
|
11957
12758
|
const plan = filterPluginInstallPlanForAddScope({
|
|
11958
12759
|
plan: await buildPluginInstallPlan({
|
|
@@ -11995,7 +12796,6 @@ const handleAddCommand = async (argv, deps = {}) => {
|
|
|
11995
12796
|
else logger.write(formatPlanSummary(plan));
|
|
11996
12797
|
return 0;
|
|
11997
12798
|
}
|
|
11998
|
-
if (rawConvexAuthPreset) assertRawConvexAuthDeploymentReady();
|
|
11999
12799
|
const applyResult = await applyPluginInstallPlanFiles(plan.files, {
|
|
12000
12800
|
overwrite: addArgs.overwrite,
|
|
12001
12801
|
yes: addArgs.yes,
|
|
@@ -12618,7 +13418,7 @@ const INIT_LOCAL_BOOTSTRAP_PROMPT = "Run one-shot local Convex bootstrap after i
|
|
|
12618
13418
|
const INIT_HELP_TEXT = `Usage: kitcn init [options]
|
|
12619
13419
|
|
|
12620
13420
|
Options:
|
|
12621
|
-
--template, -t App template ("next" or "vite") for fresh app scaffolding
|
|
13421
|
+
--template, -t App template ("next", "start", or "vite") for fresh app scaffolding
|
|
12622
13422
|
--cwd Target directory (or parent when used with --name)
|
|
12623
13423
|
--name Project name when scaffolding a fresh app
|
|
12624
13424
|
--prod Forward to \`convex init\`
|
|
@@ -13088,7 +13888,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
13088
13888
|
const HELP_FLAGS = new Set(["--help", "-h"]);
|
|
13089
13889
|
const VERSION_FLAGS = new Set(["--version", "-v"]);
|
|
13090
13890
|
const packageJson = readOwnPackageJson(import.meta.url);
|
|
13091
|
-
const REMOVED_CREATE_MESSAGE = "Removed `kitcn create`. Use `kitcn init -t <next|vite>` for fresh app scaffolding.";
|
|
13891
|
+
const REMOVED_CREATE_MESSAGE = "Removed `kitcn create`. Use `kitcn init -t <next|start|vite>` for fresh app scaffolding.";
|
|
13092
13892
|
const LOCAL_NODE_REEXEC_ENV = "KITCN_NODE_REEXEC";
|
|
13093
13893
|
const LOCAL_NODE_REEXEC_COMMANDS = new Set([
|
|
13094
13894
|
"add",
|