sv 0.11.3 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-BWQarWDB.mjs → add-CrUK5jc7.mjs} +656 -834
- package/dist/{add-nRRWTjzp.d.mts → add-DbK6niIm.d.mts} +7 -4
- package/dist/bin.mjs +18 -17
- package/dist/{chunk-BjMGrMj9.mjs → chunk-BcJDCUAU.mjs} +2 -2
- package/dist/{core-CnPhgWST.d.mts → core-DjIj3YV4.d.mts} +45 -12
- package/dist/lib/core.d.mts +2 -2
- package/dist/lib/core.mjs +2 -2
- package/dist/lib/index.d.mts +3 -3
- package/dist/lib/index.mjs +3 -3
- package/dist/lib/testing.d.mts +5 -4
- package/dist/lib/testing.mjs +18 -10254
- package/dist/{package-manager-DkCPtZM1.mjs → package-manager-DYfxv5nk.mjs} +37 -20
- package/dist/shared.json +2 -2
- package/dist/templates/addon/package.json +3 -3
- package/dist/templates/demo/package.json +4 -4
- package/dist/templates/library/package.json +5 -5
- package/dist/templates/minimal/package.json +4 -4
- package/dist/templates/svelte/assets/DOT-gitignore +24 -0
- package/dist/templates/svelte/assets/public/vite.svg +1 -0
- package/dist/templates/svelte/assets/src/assets/svelte.svg +1 -0
- package/dist/templates/svelte/files.types=checkjs.json +1 -0
- package/dist/templates/svelte/files.types=none.json +42 -0
- package/dist/templates/svelte/files.types=typescript.json +50 -0
- package/dist/templates/svelte/meta.json +4 -0
- package/dist/{utils-DjBRIDJG.mjs → utils-CnfD6Z1s.mjs} +3030 -3563
- package/package.json +5 -7
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { _ as
|
|
3
|
-
import { $ as
|
|
1
|
+
import { r as __require, t as __commonJSMin } from "./chunk-BcJDCUAU.mjs";
|
|
2
|
+
import { _ as getSharedFiles, a as installOption, c as up$1, d as Option, g as dist, h as sanitizeName, i as installDependencies, m as templates, n as addPnpmBuildDependencies, o as packageManagerPrompt, p as create$1, r as detectPackageManager, s as any, t as AGENT_NAMES, u as Command } from "./package-manager-DYfxv5nk.mjs";
|
|
3
|
+
import { $ as createPrinter, A as addNamespace$1, B as appendFromString, C as createDefault, Ct as Rt, D as addDefault, E as declaration, Et as qt, F as overrideProperties, G as parseExpression, H as createLiteral, I as property, J as addSlot, K as parseStatement, L as append, M as remove, N as createCall, O as addEmpty, Ot as Ct, P as create$2, R as create$3, S as addNamespace, St as R, T as createIdentifier, Tt as kt, U as createSpread, V as appendStatement, W as hasTypeProperty, Y as ensureScript, Z as addAtRule, _t as Lt, a as getPackageJson, at as defineAddon, b as addGlobalAppInterface, bt as Pt, c as writeFile, ct as walk, et as addEslintConfigPrettier, f as packageScriptsUpsert, ft as q, gt as Ie, h as addAttribute, ht as resolveCommand, i as formatFiles, it as splitVersion, j as find, k as addNamed, l as parse$1, m as upsert, n as commonFilePaths, nt as getNodeTypesVersion, o as installPackages, ot as defineAddonOptions, q as addFragment, r as fileExists, rt as isVersionUnsupportedBelow, s as readFile, st as getErrorHint, t as color, tt as addToDemoPage, u as arrayUpsert, ut as dedent_default, v as addPlugin, vt as Mt, w as createNamed, wt as Wt, x as addHooksHandle, xt as Qt, y as getConfig, yt as Nt, z as addJsDocTypeComment } from "./utils-CnfD6Z1s.mjs";
|
|
4
4
|
import fs, { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import path, { dirname, join } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import process$1 from "node:process";
|
|
8
8
|
import { promisify } from "node:util";
|
|
9
9
|
import { exec } from "node:child_process";
|
|
10
|
+
import crypto from "node:crypto";
|
|
10
11
|
import { platform } from "node:os";
|
|
11
12
|
import { pipeline } from "node:stream/promises";
|
|
12
13
|
import { createGunzip } from "node:zlib";
|
|
@@ -610,7 +611,431 @@ function pipe(...pipe$1) {
|
|
|
610
611
|
}
|
|
611
612
|
|
|
612
613
|
//#endregion
|
|
613
|
-
//#region lib/addons/
|
|
614
|
+
//#region lib/addons/better-auth.ts
|
|
615
|
+
const options$7 = defineAddonOptions().add("demo", {
|
|
616
|
+
question: "Which demo would you like to include?",
|
|
617
|
+
type: "multiselect",
|
|
618
|
+
default: ["password"],
|
|
619
|
+
options: [{
|
|
620
|
+
value: "password",
|
|
621
|
+
label: "Email & Password"
|
|
622
|
+
}, {
|
|
623
|
+
value: "github",
|
|
624
|
+
label: "GitHub OAuth"
|
|
625
|
+
}],
|
|
626
|
+
required: false
|
|
627
|
+
}).build();
|
|
628
|
+
var better_auth_default = defineAddon({
|
|
629
|
+
id: "better-auth",
|
|
630
|
+
shortDescription: "auth library",
|
|
631
|
+
homepage: "https://www.better-auth.com",
|
|
632
|
+
options: options$7,
|
|
633
|
+
setup: ({ kit, dependencyVersion, unsupported, dependsOn, runsAfter }) => {
|
|
634
|
+
if (!kit) unsupported("Requires SvelteKit");
|
|
635
|
+
if (!dependencyVersion("drizzle-orm")) dependsOn("drizzle");
|
|
636
|
+
runsAfter("tailwindcss");
|
|
637
|
+
},
|
|
638
|
+
run: ({ sv, language, options: options$8, kit, dependencyVersion, files }) => {
|
|
639
|
+
if (!kit) throw new Error("SvelteKit is required");
|
|
640
|
+
const demoPassword = options$8.demo.includes("password");
|
|
641
|
+
const demoGithub = options$8.demo.includes("github");
|
|
642
|
+
const hasDemo = demoPassword || demoGithub;
|
|
643
|
+
let drizzleDialect;
|
|
644
|
+
sv.devDependency("better-auth", "^1.4.18");
|
|
645
|
+
sv.file(`drizzle.config.${language}`, (content) => {
|
|
646
|
+
const { ast, generateCode } = parse$1.script(content);
|
|
647
|
+
const isProp = (name$1, node) => node.key.type === "Identifier" && node.key.name === name$1;
|
|
648
|
+
walk(ast, null, { Property(node) {
|
|
649
|
+
if (isProp("dialect", node) && node.value.type === "Literal" && typeof node.value.value === "string") drizzleDialect = node.value.value;
|
|
650
|
+
} });
|
|
651
|
+
if (!drizzleDialect) throw new Error("Failed to detect DB dialect in your `drizzle.config.[js|ts]` file");
|
|
652
|
+
return generateCode();
|
|
653
|
+
});
|
|
654
|
+
sv.file(".env", (content) => generateEnvFileContent$1(content, demoGithub, false));
|
|
655
|
+
sv.file(".env.example", (content) => generateEnvFileContent$1(content, demoGithub, true));
|
|
656
|
+
sv.file(`${kit?.libDirectory}/server/auth.${language}`, (content) => {
|
|
657
|
+
const { ast, generateCode, comments } = parse$1.script(content);
|
|
658
|
+
addNamed(ast, {
|
|
659
|
+
from: "$lib/server/db",
|
|
660
|
+
imports: ["db"]
|
|
661
|
+
});
|
|
662
|
+
addNamed(ast, {
|
|
663
|
+
from: "$app/server",
|
|
664
|
+
imports: ["getRequestEvent"]
|
|
665
|
+
});
|
|
666
|
+
addNamed(ast, {
|
|
667
|
+
from: "$env/dynamic/private",
|
|
668
|
+
imports: ["env"]
|
|
669
|
+
});
|
|
670
|
+
addNamed(ast, {
|
|
671
|
+
from: "better-auth/svelte-kit",
|
|
672
|
+
imports: ["sveltekitCookies"]
|
|
673
|
+
});
|
|
674
|
+
addNamed(ast, {
|
|
675
|
+
from: "better-auth/adapters/drizzle",
|
|
676
|
+
imports: ["drizzleAdapter"]
|
|
677
|
+
});
|
|
678
|
+
addNamed(ast, {
|
|
679
|
+
from: "better-auth",
|
|
680
|
+
imports: ["betterAuth"]
|
|
681
|
+
});
|
|
682
|
+
const authConfig = dedent_default`
|
|
683
|
+
export const auth = betterAuth({
|
|
684
|
+
baseURL: env.ORIGIN,
|
|
685
|
+
secret: env.BETTER_AUTH_SECRET,
|
|
686
|
+
database: drizzleAdapter(db, {
|
|
687
|
+
provider: '${{
|
|
688
|
+
mysql: "mysql",
|
|
689
|
+
postgresql: "pg",
|
|
690
|
+
sqlite: "sqlite",
|
|
691
|
+
turso: "sqlite"
|
|
692
|
+
}[drizzleDialect]}'
|
|
693
|
+
}),
|
|
694
|
+
emailAndPassword: {
|
|
695
|
+
enabled: true
|
|
696
|
+
},${demoGithub ? `
|
|
697
|
+
socialProviders: {
|
|
698
|
+
github: {
|
|
699
|
+
clientId: env.GITHUB_CLIENT_ID,
|
|
700
|
+
clientSecret: env.GITHUB_CLIENT_SECRET,
|
|
701
|
+
},
|
|
702
|
+
},` : ""}
|
|
703
|
+
plugins: [sveltekitCookies(getRequestEvent)], // make sure this is the last plugin in the array
|
|
704
|
+
});`;
|
|
705
|
+
appendFromString(ast, {
|
|
706
|
+
code: authConfig,
|
|
707
|
+
comments
|
|
708
|
+
});
|
|
709
|
+
return generateCode();
|
|
710
|
+
});
|
|
711
|
+
const authConfigPath = `${kit?.libDirectory}/server/auth.${language}`;
|
|
712
|
+
const authSchemaPath = `${kit?.libDirectory}/server/db/auth.schema.${language}`;
|
|
713
|
+
sv.file(files.package, (content) => {
|
|
714
|
+
const { data, generateCode } = parse$1.json(content);
|
|
715
|
+
packageScriptsUpsert(data, "auth:schema", `npx @better-auth/cli generate --config ${authConfigPath} --output ${authSchemaPath} --yes`);
|
|
716
|
+
return generateCode();
|
|
717
|
+
});
|
|
718
|
+
sv.file(`${kit?.libDirectory}/server/db/auth.schema.${language}`, (content) => {
|
|
719
|
+
if (content) return content;
|
|
720
|
+
return dedent_default`
|
|
721
|
+
// If you see this file, you have not run the auth:schema script yet, but you should!
|
|
722
|
+
`;
|
|
723
|
+
});
|
|
724
|
+
sv.file(`${kit?.libDirectory}/server/db/schema.${language}`, (content) => {
|
|
725
|
+
const { ast, generateCode } = parse$1.script(content);
|
|
726
|
+
addNamespace(ast, { from: "./auth.schema" });
|
|
727
|
+
return generateCode();
|
|
728
|
+
});
|
|
729
|
+
sv.file("src/app.d.ts", (content) => {
|
|
730
|
+
const { ast, generateCode } = parse$1.script(content);
|
|
731
|
+
addNamed(ast, {
|
|
732
|
+
imports: ["User", "Session"],
|
|
733
|
+
from: "better-auth",
|
|
734
|
+
isType: true
|
|
735
|
+
});
|
|
736
|
+
const locals = addGlobalAppInterface(ast, { name: "Locals" });
|
|
737
|
+
if (!locals) throw new Error("Failed detecting `locals` interface in `src/app.d.ts`");
|
|
738
|
+
const user = locals.body.body.find((prop) => hasTypeProperty(prop, { name: "user" }));
|
|
739
|
+
const session = locals.body.body.find((prop) => hasTypeProperty(prop, { name: "session" }));
|
|
740
|
+
function addProps(name$1, value, optional$1 = false) {
|
|
741
|
+
return {
|
|
742
|
+
type: "TSPropertySignature",
|
|
743
|
+
key: {
|
|
744
|
+
type: "Identifier",
|
|
745
|
+
name: name$1
|
|
746
|
+
},
|
|
747
|
+
computed: false,
|
|
748
|
+
optional: optional$1,
|
|
749
|
+
typeAnnotation: {
|
|
750
|
+
type: "TSTypeAnnotation",
|
|
751
|
+
typeAnnotation: {
|
|
752
|
+
type: "TSTypeReference",
|
|
753
|
+
typeName: {
|
|
754
|
+
type: "Identifier",
|
|
755
|
+
name: value
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
if (!user) locals.body.body.push(addProps("user", "User", true));
|
|
762
|
+
if (!session) locals.body.body.push(addProps("session", "Session", true));
|
|
763
|
+
return generateCode();
|
|
764
|
+
});
|
|
765
|
+
sv.file(`src/hooks.server.${language}`, (content) => {
|
|
766
|
+
const { ast, generateCode, comments } = parse$1.script(content);
|
|
767
|
+
addNamed(ast, {
|
|
768
|
+
imports: ["svelteKitHandler"],
|
|
769
|
+
from: "better-auth/svelte-kit"
|
|
770
|
+
});
|
|
771
|
+
addNamed(ast, {
|
|
772
|
+
imports: ["auth"],
|
|
773
|
+
from: "$lib/server/auth"
|
|
774
|
+
});
|
|
775
|
+
addNamed(ast, {
|
|
776
|
+
imports: ["building"],
|
|
777
|
+
from: "$app/environment"
|
|
778
|
+
});
|
|
779
|
+
const handleContent = dedent_default`
|
|
780
|
+
async ({ event, resolve }) => {
|
|
781
|
+
// Fetch current session from Better Auth
|
|
782
|
+
const session = await auth.api.getSession({
|
|
783
|
+
headers: event.request.headers
|
|
784
|
+
});
|
|
785
|
+
// Make session and user available on server
|
|
786
|
+
if (session) {
|
|
787
|
+
event.locals.session = session.session;
|
|
788
|
+
event.locals.user = session.user;
|
|
789
|
+
}
|
|
790
|
+
return svelteKitHandler({ event, resolve, auth, building });
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
export const handle = sequence(handleBetterAuth, handleSession);
|
|
794
|
+
`;
|
|
795
|
+
addHooksHandle(ast, {
|
|
796
|
+
language,
|
|
797
|
+
newHandleName: "handleBetterAuth",
|
|
798
|
+
handleContent,
|
|
799
|
+
comments
|
|
800
|
+
});
|
|
801
|
+
return generateCode();
|
|
802
|
+
});
|
|
803
|
+
if (hasDemo) {
|
|
804
|
+
sv.file(`${kit?.routesDirectory}/demo/+page.svelte`, (content) => {
|
|
805
|
+
return addToDemoPage(content, "better-auth", language);
|
|
806
|
+
});
|
|
807
|
+
sv.file(`${kit.routesDirectory}/demo/better-auth/login/+page.server.${language}`, (content) => {
|
|
808
|
+
if (content) {
|
|
809
|
+
const filePath = `${kit.routesDirectory}/demo/better-auth/login/+page.server.${language}`;
|
|
810
|
+
R.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
811
|
+
return content;
|
|
812
|
+
}
|
|
813
|
+
const [ts] = createPrinter(language === "ts");
|
|
814
|
+
const signInEmailAction = demoPassword ? `
|
|
815
|
+
signInEmail: async (event) => {
|
|
816
|
+
const formData = await event.request.formData();
|
|
817
|
+
const email = formData.get('email')?.toString() ?? '';
|
|
818
|
+
const password = formData.get('password')?.toString() ?? '';
|
|
819
|
+
|
|
820
|
+
try {
|
|
821
|
+
await auth.api.signInEmail({
|
|
822
|
+
body: {
|
|
823
|
+
email,
|
|
824
|
+
password,
|
|
825
|
+
callbackURL: '/auth/verification-success'
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
} catch (error) {
|
|
829
|
+
if (error instanceof APIError) {
|
|
830
|
+
return fail(400, { message: error.message || 'Signin failed' });
|
|
831
|
+
}
|
|
832
|
+
return fail(500, { message: 'Unexpected error' });
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
return redirect(302, '/demo/better-auth');
|
|
836
|
+
},
|
|
837
|
+
signUpEmail: async (event) => {
|
|
838
|
+
const formData = await event.request.formData();
|
|
839
|
+
const email = formData.get('email')?.toString() ?? '';
|
|
840
|
+
const password = formData.get('password')?.toString() ?? '';
|
|
841
|
+
const name = formData.get('name')?.toString() ?? '';
|
|
842
|
+
|
|
843
|
+
try {
|
|
844
|
+
await auth.api.signUpEmail({
|
|
845
|
+
body: {
|
|
846
|
+
email,
|
|
847
|
+
password,
|
|
848
|
+
name,
|
|
849
|
+
callbackURL: '/auth/verification-success'
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
} catch (error) {
|
|
853
|
+
if (error instanceof APIError) {
|
|
854
|
+
return fail(400, { message: error.message || 'Registration failed' });
|
|
855
|
+
}
|
|
856
|
+
return fail(500, { message: 'Unexpected error' });
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return redirect(302, '/demo/better-auth');
|
|
860
|
+
},` : "";
|
|
861
|
+
const signInSocialAction = demoGithub ? `
|
|
862
|
+
signInSocial: async (event) => {
|
|
863
|
+
const formData = await event.request.formData();
|
|
864
|
+
const provider = formData.get('provider')?.toString() ?? 'github';
|
|
865
|
+
const callbackURL = formData.get('callbackURL')?.toString() ?? '/demo/better-auth';
|
|
866
|
+
|
|
867
|
+
const result = await auth.api.signInSocial({
|
|
868
|
+
body: {
|
|
869
|
+
provider: provider${ts(" as \"github\"")},
|
|
870
|
+
callbackURL
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
if (result.url) {
|
|
875
|
+
return redirect(302, result.url);
|
|
876
|
+
}
|
|
877
|
+
return fail(400, { message: 'Social sign-in failed' });
|
|
878
|
+
},` : "";
|
|
879
|
+
const needsAPIError = demoPassword;
|
|
880
|
+
return dedent_default`
|
|
881
|
+
import { fail, redirect } from '@sveltejs/kit';
|
|
882
|
+
${ts("import type { Actions } from './$types';")}
|
|
883
|
+
${ts("import type { PageServerLoad } from './$types';")}
|
|
884
|
+
import { auth } from '$lib/server/auth';
|
|
885
|
+
${needsAPIError ? "import { APIError } from 'better-auth';" : ""}
|
|
886
|
+
|
|
887
|
+
export const load${ts(": PageServerLoad")} = async (event) => {
|
|
888
|
+
if (event.locals.user) {
|
|
889
|
+
return redirect(302, '/demo/better-auth');
|
|
890
|
+
}
|
|
891
|
+
return {};
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
export const actions${ts(": Actions")} = {${signInEmailAction}${signInSocialAction}
|
|
895
|
+
};
|
|
896
|
+
`;
|
|
897
|
+
});
|
|
898
|
+
sv.file(`${kit.routesDirectory}/demo/better-auth/login/+page.svelte`, (content) => {
|
|
899
|
+
if (content) {
|
|
900
|
+
const filePath = `${kit.routesDirectory}/demo/better-auth/login/+page.svelte`;
|
|
901
|
+
R.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
902
|
+
return content;
|
|
903
|
+
}
|
|
904
|
+
const tailwind = dependencyVersion("@tailwindcss/vite") !== void 0;
|
|
905
|
+
const input = tailwind ? " class=\"mt-1 px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"" : "";
|
|
906
|
+
const btn = tailwind ? " class=\"bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition\"" : "";
|
|
907
|
+
const svelte5 = !!dependencyVersion("svelte")?.startsWith("5");
|
|
908
|
+
const [ts, s5] = createPrinter(language === "ts", svelte5);
|
|
909
|
+
const passwordForm = demoPassword ? `
|
|
910
|
+
<form method="post" action="?/signInEmail" use:enhance>
|
|
911
|
+
<label>
|
|
912
|
+
Email
|
|
913
|
+
<input type="email" name="email"${input} />
|
|
914
|
+
</label>
|
|
915
|
+
<label>
|
|
916
|
+
Password
|
|
917
|
+
<input type="password" name="password"${input} />
|
|
918
|
+
</label>
|
|
919
|
+
<label>
|
|
920
|
+
Name (for registration)
|
|
921
|
+
<input name="name"${input} />
|
|
922
|
+
</label>
|
|
923
|
+
<button${btn}>Login</button>
|
|
924
|
+
<button formaction="?/signUpEmail"${btn}>Register</button>
|
|
925
|
+
</form>
|
|
926
|
+
${tailwind ? `<p class="text-red-500">{form?.message ?? ''}</p>` : `<p style="color: red">{form?.message ?? ''}</p>`}` : "";
|
|
927
|
+
const separator = demoPassword && demoGithub ? `\n\n <hr ${tailwind ? "class=\"my-4\"" : ""} />` : "";
|
|
928
|
+
const githubForm = demoGithub ? `
|
|
929
|
+
<form method="post" action="?/signInSocial" use:enhance>
|
|
930
|
+
<input type="hidden" name="provider" value="github" />
|
|
931
|
+
<input type="hidden" name="callbackURL" value="/demo/better-auth" />
|
|
932
|
+
<button${btn}>Sign in with GitHub</button>
|
|
933
|
+
</form>` : "";
|
|
934
|
+
return dedent_default`
|
|
935
|
+
<script ${ts("lang='ts'")}>
|
|
936
|
+
import { enhance } from '$app/forms';
|
|
937
|
+
${ts("import type { ActionData } from './$types';\n")}
|
|
938
|
+
${s5(`let { form }${ts(": { form: ActionData }")} = $props();`, `export let form${ts(": ActionData")};`)}
|
|
939
|
+
<\/script>
|
|
940
|
+
|
|
941
|
+
<h1>Login</h1>${passwordForm}${separator}${githubForm}
|
|
942
|
+
`;
|
|
943
|
+
});
|
|
944
|
+
sv.file(`${kit.routesDirectory}/demo/better-auth/+page.server.${language}`, (content) => {
|
|
945
|
+
if (content) {
|
|
946
|
+
const filePath = `${kit.routesDirectory}/demo/better-auth/+page.server.${language}`;
|
|
947
|
+
R.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
948
|
+
return content;
|
|
949
|
+
}
|
|
950
|
+
const [ts] = createPrinter(language === "ts");
|
|
951
|
+
return dedent_default`
|
|
952
|
+
import { redirect } from '@sveltejs/kit';
|
|
953
|
+
${ts("import type { Actions } from './$types';")}
|
|
954
|
+
${ts("import type { PageServerLoad } from './$types';")}
|
|
955
|
+
import { auth } from '$lib/server/auth';
|
|
956
|
+
|
|
957
|
+
export const load${ts(": PageServerLoad")} = async (event) => {
|
|
958
|
+
if (!event.locals.user) {
|
|
959
|
+
return redirect(302, '/demo/better-auth/login');
|
|
960
|
+
}
|
|
961
|
+
return { user: event.locals.user };
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
export const actions${ts(": Actions")} = {
|
|
965
|
+
signOut: async (event) => {
|
|
966
|
+
await auth.api.signOut({
|
|
967
|
+
headers: event.request.headers
|
|
968
|
+
});
|
|
969
|
+
return redirect(302, '/demo/better-auth/login');
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
`;
|
|
973
|
+
});
|
|
974
|
+
sv.file(`${kit.routesDirectory}/demo/better-auth/+page.svelte`, (content) => {
|
|
975
|
+
if (content) {
|
|
976
|
+
const filePath = `${kit.routesDirectory}/demo/better-auth/+page.svelte`;
|
|
977
|
+
R.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
978
|
+
return content;
|
|
979
|
+
}
|
|
980
|
+
const tailwind = dependencyVersion("@tailwindcss/vite") !== void 0;
|
|
981
|
+
const twBtnClasses = "class=\"bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition\"";
|
|
982
|
+
const svelte5 = !!dependencyVersion("svelte")?.startsWith("5");
|
|
983
|
+
const [ts, s5] = createPrinter(language === "ts", svelte5);
|
|
984
|
+
return dedent_default`
|
|
985
|
+
<script ${ts("lang='ts'")}>
|
|
986
|
+
import { enhance } from '$app/forms';
|
|
987
|
+
${ts("import type { PageServerData } from './$types';\n")}
|
|
988
|
+
${s5(`let { data }${ts(": { data: PageServerData }")} = $props();`, `export let data${ts(": PageServerData")};`)}
|
|
989
|
+
<\/script>
|
|
990
|
+
|
|
991
|
+
<h1>Hi, {data.user.name}!</h1>
|
|
992
|
+
<p>Your user ID is {data.user.id}.</p>
|
|
993
|
+
<form method="post" action="?/signOut" use:enhance>
|
|
994
|
+
<button ${tailwind ? twBtnClasses : ""}>Sign out</button>
|
|
995
|
+
</form>
|
|
996
|
+
`;
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
},
|
|
1000
|
+
nextSteps: ({ options: options$8, packageManager }) => {
|
|
1001
|
+
const { command: authCmd, args: authArgs } = resolveCommand(packageManager, "run", ["auth:schema"]);
|
|
1002
|
+
const { command: dbCmd, args: dbArgs } = resolveCommand(packageManager, "run", ["db:push"]);
|
|
1003
|
+
const steps = [
|
|
1004
|
+
`Run ${color.command(`${authCmd} ${authArgs.join(" ")}`)} to generate the auth schema`,
|
|
1005
|
+
`Run ${color.command(`${dbCmd} ${dbArgs.join(" ")}`)} to update your database`,
|
|
1006
|
+
`Check ${color.env("ORIGIN")} & ${color.env("BETTER_AUTH_SECRET")} in ${color.path(".env")} and adjust it to your needs`
|
|
1007
|
+
];
|
|
1008
|
+
if (options$8.demo.includes("github")) steps.push(`Set your ${color.env("GITHUB_CLIENT_ID")} and ${color.env("GITHUB_CLIENT_SECRET")} in ${color.path(".env")}`);
|
|
1009
|
+
if (options$8.demo.length > 0) steps.push(`Visit ${color.route("/demo/better-auth")} route to view the demo`);
|
|
1010
|
+
return steps;
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
function generateEnvFileContent$1(content, demoGithub, isExample) {
|
|
1014
|
+
content = upsert(content, "ORIGIN", {
|
|
1015
|
+
value: isExample ? `""` : `"http://localhost:5173"`,
|
|
1016
|
+
separator: true
|
|
1017
|
+
});
|
|
1018
|
+
content = upsert(content, "BETTER_AUTH_SECRET", {
|
|
1019
|
+
value: isExample ? `""` : `"${crypto.randomUUID()}"`,
|
|
1020
|
+
comment: [
|
|
1021
|
+
"Better Auth",
|
|
1022
|
+
"For production use 32 characters and generated with high entropy",
|
|
1023
|
+
"https://www.better-auth.com/docs/installation"
|
|
1024
|
+
],
|
|
1025
|
+
separator: true
|
|
1026
|
+
});
|
|
1027
|
+
if (demoGithub) {
|
|
1028
|
+
content = upsert(content, "GITHUB_CLIENT_ID", {
|
|
1029
|
+
value: `""`,
|
|
1030
|
+
comment: "GitHub OAuth\n# https://www.better-auth.com/docs/authentication/github"
|
|
1031
|
+
});
|
|
1032
|
+
content = upsert(content, "GITHUB_CLIENT_SECRET", { value: `""` });
|
|
1033
|
+
}
|
|
1034
|
+
return content;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
//#endregion
|
|
1038
|
+
//#region lib/addons/devtools-json.ts
|
|
614
1039
|
var devtools_json_default = defineAddon({
|
|
615
1040
|
id: "devtools-json",
|
|
616
1041
|
shortDescription: "devtools json",
|
|
@@ -632,13 +1057,13 @@ var devtools_json_default = defineAddon({
|
|
|
632
1057
|
});
|
|
633
1058
|
|
|
634
1059
|
//#endregion
|
|
635
|
-
//#region lib/addons/drizzle
|
|
1060
|
+
//#region lib/addons/drizzle.ts
|
|
636
1061
|
const PORTS = {
|
|
637
1062
|
mysql: "3306",
|
|
638
1063
|
postgresql: "5432",
|
|
639
1064
|
sqlite: ""
|
|
640
1065
|
};
|
|
641
|
-
const options$
|
|
1066
|
+
const options$6 = defineAddonOptions().add("database", {
|
|
642
1067
|
question: "Which database would you like to use?",
|
|
643
1068
|
type: "select",
|
|
644
1069
|
default: "sqlite",
|
|
@@ -717,7 +1142,7 @@ var drizzle_default = defineAddon({
|
|
|
717
1142
|
id: "drizzle",
|
|
718
1143
|
shortDescription: "database orm",
|
|
719
1144
|
homepage: "https://orm.drizzle.team",
|
|
720
|
-
options: options$
|
|
1145
|
+
options: options$6,
|
|
721
1146
|
setup: ({ kit, unsupported, runsAfter }) => {
|
|
722
1147
|
runsAfter("prettier");
|
|
723
1148
|
if (!kit) return unsupported("Requires SvelteKit");
|
|
@@ -732,21 +1157,21 @@ var drizzle_default = defineAddon({
|
|
|
732
1157
|
database: path.resolve(baseDBPath, `index.${language}`)
|
|
733
1158
|
};
|
|
734
1159
|
for (const [fileType, filePath] of Object.entries(paths)) if (fs.existsSync(filePath)) return cancel(`Preexisting ${fileType} file at '${filePath}'`);
|
|
735
|
-
sv.devDependency("drizzle-orm", "^0.45.
|
|
1160
|
+
sv.devDependency("drizzle-orm", "^0.45.1");
|
|
736
1161
|
sv.devDependency("drizzle-kit", "^0.31.8");
|
|
737
1162
|
sv.devDependency("@types/node", getNodeTypesVersion());
|
|
738
|
-
if (options$8.mysql === "mysql2") sv.dependency("mysql2", "^3.
|
|
1163
|
+
if (options$8.mysql === "mysql2") sv.dependency("mysql2", "^3.16.3");
|
|
739
1164
|
if (options$8.mysql === "planetscale") sv.dependency("@planetscale/database", "^1.19.0");
|
|
740
1165
|
if (options$8.postgresql === "neon") sv.dependency("@neondatabase/serverless", "^1.0.2");
|
|
741
|
-
if (options$8.postgresql === "postgres.js") sv.dependency("postgres", "^3.4.
|
|
1166
|
+
if (options$8.postgresql === "postgres.js") sv.dependency("postgres", "^3.4.8");
|
|
742
1167
|
if (options$8.sqlite === "better-sqlite3") {
|
|
743
|
-
sv.dependency("better-sqlite3", "^12.
|
|
1168
|
+
sv.dependency("better-sqlite3", "^12.6.2");
|
|
744
1169
|
sv.devDependency("@types/better-sqlite3", "^7.6.13");
|
|
745
1170
|
sv.pnpmBuildDependency("better-sqlite3");
|
|
746
1171
|
}
|
|
747
|
-
if (options$8.sqlite === "libsql" || options$8.sqlite === "turso") sv.devDependency("@libsql/client", "^0.
|
|
748
|
-
sv.file(".env", (content) => generateEnvFileContent(content, options$8));
|
|
749
|
-
sv.file(".env.example", (content) => generateEnvFileContent(content, options$8));
|
|
1172
|
+
if (options$8.sqlite === "libsql" || options$8.sqlite === "turso") sv.devDependency("@libsql/client", "^0.17.0");
|
|
1173
|
+
sv.file(".env", (content) => generateEnvFileContent(content, options$8, false));
|
|
1174
|
+
sv.file(".env.example", (content) => generateEnvFileContent(content, options$8, true));
|
|
750
1175
|
if (options$8.docker && (options$8.mysql === "mysql2" || options$8.postgresql === "postgres.js")) {
|
|
751
1176
|
const composeFileOptions = [
|
|
752
1177
|
"docker-compose.yml",
|
|
@@ -806,13 +1231,11 @@ var drizzle_default = defineAddon({
|
|
|
806
1231
|
return generateCode();
|
|
807
1232
|
});
|
|
808
1233
|
if (Boolean(dependencyVersion("prettier"))) sv.file(files.prettierignore, (content) => {
|
|
809
|
-
|
|
810
|
-
return content;
|
|
1234
|
+
return upsert(content, "/drizzle/");
|
|
811
1235
|
});
|
|
812
1236
|
if (options$8.database === "sqlite") sv.file(files.gitignore, (content) => {
|
|
813
1237
|
if (content.length === 0) return content;
|
|
814
|
-
|
|
815
|
-
return content;
|
|
1238
|
+
return upsert(content, "*.db", { comment: "SQLite" });
|
|
816
1239
|
});
|
|
817
1240
|
sv.file(paths["drizzle config"], (content) => {
|
|
818
1241
|
const { ast, generateCode } = parse$1.script(content);
|
|
@@ -836,7 +1259,7 @@ var drizzle_default = defineAddon({
|
|
|
836
1259
|
});
|
|
837
1260
|
sv.file(paths["database schema"], (content) => {
|
|
838
1261
|
const { ast, generateCode } = parse$1.script(content);
|
|
839
|
-
let
|
|
1262
|
+
let taskSchemaExpression;
|
|
840
1263
|
if (options$8.database === "sqlite") {
|
|
841
1264
|
addNamed(ast, {
|
|
842
1265
|
from: "drizzle-orm/sqlite-core",
|
|
@@ -846,10 +1269,11 @@ var drizzle_default = defineAddon({
|
|
|
846
1269
|
"text"
|
|
847
1270
|
]
|
|
848
1271
|
});
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1272
|
+
taskSchemaExpression = parseExpression(`sqliteTable('task', {
|
|
1273
|
+
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
1274
|
+
title: text('title').notNull(),
|
|
1275
|
+
priority: integer('priority').notNull().default(1)
|
|
1276
|
+
})`);
|
|
853
1277
|
}
|
|
854
1278
|
if (options$8.database === "mysql") {
|
|
855
1279
|
addNamed(ast, {
|
|
@@ -857,13 +1281,15 @@ var drizzle_default = defineAddon({
|
|
|
857
1281
|
imports: [
|
|
858
1282
|
"mysqlTable",
|
|
859
1283
|
"serial",
|
|
860
|
-
"int"
|
|
1284
|
+
"int",
|
|
1285
|
+
"text"
|
|
861
1286
|
]
|
|
862
1287
|
});
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1288
|
+
taskSchemaExpression = parseExpression(`mysqlTable('task', {
|
|
1289
|
+
id: serial('id').primaryKey(),
|
|
1290
|
+
title: text('title').notNull(),
|
|
1291
|
+
priority: int('priority').notNull().default(1)
|
|
1292
|
+
})`);
|
|
867
1293
|
}
|
|
868
1294
|
if (options$8.database === "postgresql") {
|
|
869
1295
|
addNamed(ast, {
|
|
@@ -871,23 +1297,25 @@ var drizzle_default = defineAddon({
|
|
|
871
1297
|
imports: [
|
|
872
1298
|
"pgTable",
|
|
873
1299
|
"serial",
|
|
874
|
-
"integer"
|
|
1300
|
+
"integer",
|
|
1301
|
+
"text"
|
|
875
1302
|
]
|
|
876
1303
|
});
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
|
|
1304
|
+
taskSchemaExpression = parseExpression(`pgTable('task', {
|
|
1305
|
+
id: serial('id').primaryKey(),
|
|
1306
|
+
title: text('title').notNull(),
|
|
1307
|
+
priority: integer('priority').notNull().default(1)
|
|
1308
|
+
})`);
|
|
1309
|
+
}
|
|
1310
|
+
if (!taskSchemaExpression) throw new Error("unreachable state...");
|
|
1311
|
+
const taskIdentifier = declaration(ast, {
|
|
884
1312
|
kind: "const",
|
|
885
|
-
name: "
|
|
886
|
-
value:
|
|
1313
|
+
name: "task",
|
|
1314
|
+
value: taskSchemaExpression
|
|
887
1315
|
});
|
|
888
1316
|
createNamed(ast, {
|
|
889
|
-
name: "
|
|
890
|
-
fallback:
|
|
1317
|
+
name: "task",
|
|
1318
|
+
fallback: taskIdentifier
|
|
891
1319
|
});
|
|
892
1320
|
return generateCode();
|
|
893
1321
|
});
|
|
@@ -897,7 +1325,7 @@ var drizzle_default = defineAddon({
|
|
|
897
1325
|
from: "$env/dynamic/private",
|
|
898
1326
|
imports: ["env"]
|
|
899
1327
|
});
|
|
900
|
-
addNamespace(ast, {
|
|
1328
|
+
addNamespace$1(ast, {
|
|
901
1329
|
from: "./schema",
|
|
902
1330
|
as: "schema"
|
|
903
1331
|
});
|
|
@@ -925,12 +1353,7 @@ var drizzle_default = defineAddon({
|
|
|
925
1353
|
imports: ["drizzle"]
|
|
926
1354
|
});
|
|
927
1355
|
if (options$8.sqlite === "turso") {
|
|
928
|
-
|
|
929
|
-
from: "$app/environment",
|
|
930
|
-
imports: ["dev"]
|
|
931
|
-
});
|
|
932
|
-
const authTokenCheck = parseStatement("if (!dev && !env.DATABASE_AUTH_TOKEN) throw new Error('DATABASE_AUTH_TOKEN is not set');");
|
|
933
|
-
ast.body.push(authTokenCheck);
|
|
1356
|
+
ast.body.push(parseStatement("if (!env.DATABASE_AUTH_TOKEN) throw new Error('DATABASE_AUTH_TOKEN is not set');"));
|
|
934
1357
|
clientExpression = parseExpression("createClient({ url: env.DATABASE_URL, authToken: env.DATABASE_AUTH_TOKEN })");
|
|
935
1358
|
} else clientExpression = parseExpression("createClient({ url: env.DATABASE_URL })");
|
|
936
1359
|
}
|
|
@@ -1000,7 +1423,7 @@ var drizzle_default = defineAddon({
|
|
|
1000
1423
|
});
|
|
1001
1424
|
},
|
|
1002
1425
|
nextSteps: ({ options: options$8, packageManager }) => {
|
|
1003
|
-
const steps = [
|
|
1426
|
+
const steps = [];
|
|
1004
1427
|
if (options$8.docker) {
|
|
1005
1428
|
const { command: command$1, args: args$1 } = resolveCommand(packageManager, "run", ["db:start"]);
|
|
1006
1429
|
steps.push(`Run ${color.command(`${command$1} ${args$1.join(" ")}`)} to start the docker container`);
|
|
@@ -1010,45 +1433,39 @@ var drizzle_default = defineAddon({
|
|
|
1010
1433
|
return steps;
|
|
1011
1434
|
}
|
|
1012
1435
|
});
|
|
1013
|
-
function generateEnvFileContent(content, opts) {
|
|
1436
|
+
function generateEnvFileContent(content, opts, isExample) {
|
|
1014
1437
|
const DB_URL_KEY = "DATABASE_URL";
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
}
|
|
1041
|
-
function addEnvComment(content, comment) {
|
|
1042
|
-
const commented = `# ${comment}`;
|
|
1043
|
-
if (!content.includes(commented)) content = appendEnvContent(content, commented);
|
|
1438
|
+
let value;
|
|
1439
|
+
const comment = ["Drizzle"];
|
|
1440
|
+
if (opts.docker) value = `"${opts.database === "mysql" ? "mysql" : "postgres"}://root:mysecretpassword@localhost:${PORTS[opts.database]}/local"`;
|
|
1441
|
+
else if (opts.sqlite === "better-sqlite3" || opts.sqlite === "libsql") value = opts.sqlite === "libsql" ? "file:local.db" : "local.db";
|
|
1442
|
+
else if (opts.sqlite === "turso") {
|
|
1443
|
+
value = "\"libsql://db-name-user.turso.io\"";
|
|
1444
|
+
comment.push("Replace with your DB credentials!", {
|
|
1445
|
+
text: "A local DB can also be used in dev as well",
|
|
1446
|
+
mode: "append"
|
|
1447
|
+
}, {
|
|
1448
|
+
text: `${DB_URL_KEY}="file:local.db"`,
|
|
1449
|
+
mode: "append"
|
|
1450
|
+
});
|
|
1451
|
+
} else if (opts.database === "mysql") {
|
|
1452
|
+
value = "\"mysql://user:password@host:port/db-name\"";
|
|
1453
|
+
comment.push("Replace with your DB credentials!");
|
|
1454
|
+
} else if (opts.database === "postgresql") {
|
|
1455
|
+
value = "\"postgres://user:password@host:port/db-name\"";
|
|
1456
|
+
comment.push("Replace with your DB credentials!");
|
|
1457
|
+
} else value = "";
|
|
1458
|
+
content = upsert(content, DB_URL_KEY, {
|
|
1459
|
+
value,
|
|
1460
|
+
comment,
|
|
1461
|
+
separator: true
|
|
1462
|
+
});
|
|
1463
|
+
if (opts.sqlite === "turso") content = upsert(content, "DATABASE_AUTH_TOKEN", { value: isExample ? `""` : `"${crypto.randomUUID()}"` });
|
|
1044
1464
|
return content;
|
|
1045
1465
|
}
|
|
1046
|
-
function appendEnvContent(existing, content) {
|
|
1047
|
-
return (!existing.length || existing.endsWith("\n") ? existing : existing + "\n") + content + "\n";
|
|
1048
|
-
}
|
|
1049
1466
|
|
|
1050
1467
|
//#endregion
|
|
1051
|
-
//#region lib/addons/eslint
|
|
1468
|
+
//#region lib/addons/eslint.ts
|
|
1052
1469
|
var eslint_default = defineAddon({
|
|
1053
1470
|
id: "eslint",
|
|
1054
1471
|
shortDescription: "linter",
|
|
@@ -1057,13 +1474,13 @@ var eslint_default = defineAddon({
|
|
|
1057
1474
|
run: ({ sv, language, dependencyVersion, files }) => {
|
|
1058
1475
|
const typescript = language === "ts";
|
|
1059
1476
|
const prettierInstalled = Boolean(dependencyVersion("prettier"));
|
|
1060
|
-
sv.devDependency("eslint", "^9.39.
|
|
1061
|
-
sv.devDependency("@eslint/compat", "^
|
|
1062
|
-
sv.devDependency("eslint-plugin-svelte", "^3.
|
|
1063
|
-
sv.devDependency("globals", "^
|
|
1064
|
-
sv.devDependency("@eslint/js", "^9.39.
|
|
1477
|
+
sv.devDependency("eslint", "^9.39.2");
|
|
1478
|
+
sv.devDependency("@eslint/compat", "^2.0.2");
|
|
1479
|
+
sv.devDependency("eslint-plugin-svelte", "^3.14.0");
|
|
1480
|
+
sv.devDependency("globals", "^17.3.0");
|
|
1481
|
+
sv.devDependency("@eslint/js", "^9.39.2");
|
|
1065
1482
|
sv.devDependency("@types/node", getNodeTypesVersion());
|
|
1066
|
-
if (typescript) sv.devDependency("typescript-eslint", "^8.
|
|
1483
|
+
if (typescript) sv.devDependency("typescript-eslint", "^8.54.0");
|
|
1067
1484
|
if (prettierInstalled) sv.devDependency("eslint-config-prettier", "^10.1.8");
|
|
1068
1485
|
sv.file(files.package, (content) => {
|
|
1069
1486
|
const { data, generateCode } = parse$1.json(content);
|
|
@@ -1077,7 +1494,7 @@ var eslint_default = defineAddon({
|
|
|
1077
1494
|
from: "./svelte.config.js",
|
|
1078
1495
|
as: "svelteConfig"
|
|
1079
1496
|
});
|
|
1080
|
-
const gitIgnorePathStatement = parseStatement("\nconst gitignorePath =
|
|
1497
|
+
const gitIgnorePathStatement = parseStatement("\nconst gitignorePath = path.resolve(import.meta.dirname, '.gitignore');");
|
|
1081
1498
|
appendStatement(ast, { statement: gitIgnorePathStatement });
|
|
1082
1499
|
const ignoresConfig = parseExpression("includeIgnoreFile(gitignorePath)");
|
|
1083
1500
|
eslintConfigs.push(ignoresConfig);
|
|
@@ -1145,7 +1562,7 @@ var eslint_default = defineAddon({
|
|
|
1145
1562
|
}
|
|
1146
1563
|
const { value: defaultExport, astNode } = createDefault(ast, { fallback: exportExpression });
|
|
1147
1564
|
if (defaultExport !== exportExpression) {
|
|
1148
|
-
|
|
1565
|
+
R.warn("An eslint config is already defined. Skipping initialization.");
|
|
1149
1566
|
return content;
|
|
1150
1567
|
}
|
|
1151
1568
|
if (!typescript) addJsDocTypeComment(astNode, comments, { type: "import('eslint').Linter.Config[]" });
|
|
@@ -1173,9 +1590,9 @@ var eslint_default = defineAddon({
|
|
|
1173
1590
|
from: "@eslint/compat",
|
|
1174
1591
|
imports: ["includeIgnoreFile"]
|
|
1175
1592
|
});
|
|
1176
|
-
|
|
1177
|
-
from: "node:
|
|
1178
|
-
|
|
1593
|
+
addDefault(ast, {
|
|
1594
|
+
from: "node:path",
|
|
1595
|
+
as: "path"
|
|
1179
1596
|
});
|
|
1180
1597
|
return generateCode();
|
|
1181
1598
|
});
|
|
@@ -1184,607 +1601,7 @@ var eslint_default = defineAddon({
|
|
|
1184
1601
|
});
|
|
1185
1602
|
|
|
1186
1603
|
//#endregion
|
|
1187
|
-
//#region lib/addons/
|
|
1188
|
-
const TABLE_TYPE = {
|
|
1189
|
-
mysql: "mysqlTable",
|
|
1190
|
-
postgresql: "pgTable",
|
|
1191
|
-
sqlite: "sqliteTable",
|
|
1192
|
-
turso: "sqliteTable"
|
|
1193
|
-
};
|
|
1194
|
-
let drizzleDialect;
|
|
1195
|
-
let schemaPath;
|
|
1196
|
-
const options$6 = defineAddonOptions().add("demo", {
|
|
1197
|
-
type: "boolean",
|
|
1198
|
-
default: true,
|
|
1199
|
-
question: `Do you want to include a demo? ${color.optional("(includes a login/register page)")}`
|
|
1200
|
-
}).build();
|
|
1201
|
-
var lucia_default = defineAddon({
|
|
1202
|
-
id: "lucia",
|
|
1203
|
-
shortDescription: "auth guide",
|
|
1204
|
-
homepage: "https://lucia-auth.com",
|
|
1205
|
-
options: options$6,
|
|
1206
|
-
setup: ({ kit, dependencyVersion, unsupported, dependsOn, runsAfter }) => {
|
|
1207
|
-
if (!kit) unsupported("Requires SvelteKit");
|
|
1208
|
-
if (!dependencyVersion("drizzle-orm")) dependsOn("drizzle");
|
|
1209
|
-
runsAfter("tailwindcss");
|
|
1210
|
-
},
|
|
1211
|
-
run: ({ sv, language, options: options$8, kit, dependencyVersion }) => {
|
|
1212
|
-
const typescript = language === "ts";
|
|
1213
|
-
sv.devDependency("@oslojs/crypto", "^1.0.1");
|
|
1214
|
-
sv.devDependency("@oslojs/encoding", "^1.1.0");
|
|
1215
|
-
if (options$8.demo) sv.dependency("@node-rs/argon2", "^2.0.2");
|
|
1216
|
-
sv.file(`drizzle.config.${language}`, (content) => {
|
|
1217
|
-
const { ast, generateCode } = parse$1.script(content);
|
|
1218
|
-
const isProp = (name$1, node) => node.key.type === "Identifier" && node.key.name === name$1;
|
|
1219
|
-
walk(ast, null, { Property(node) {
|
|
1220
|
-
if (isProp("dialect", node) && node.value.type === "Literal" && typeof node.value.value === "string") drizzleDialect = node.value.value;
|
|
1221
|
-
if (isProp("schema", node) && node.value.type === "Literal" && typeof node.value.value === "string") schemaPath = node.value.value;
|
|
1222
|
-
} });
|
|
1223
|
-
if (!drizzleDialect) throw new Error("Failed to detect DB dialect in your `drizzle.config.[js|ts]` file");
|
|
1224
|
-
if (!schemaPath) throw new Error("Failed to find schema path in your `drizzle.config.[js|ts]` file");
|
|
1225
|
-
return generateCode();
|
|
1226
|
-
});
|
|
1227
|
-
sv.file(schemaPath, (content) => {
|
|
1228
|
-
const { ast, generateCode } = parse$1.script(content);
|
|
1229
|
-
const createTable = (name$1) => createCall({
|
|
1230
|
-
name: TABLE_TYPE[drizzleDialect],
|
|
1231
|
-
args: [name$1]
|
|
1232
|
-
});
|
|
1233
|
-
const userDecl = declaration(ast, {
|
|
1234
|
-
kind: "const",
|
|
1235
|
-
name: "user",
|
|
1236
|
-
value: createTable("user")
|
|
1237
|
-
});
|
|
1238
|
-
const sessionDecl = declaration(ast, {
|
|
1239
|
-
kind: "const",
|
|
1240
|
-
name: "session",
|
|
1241
|
-
value: createTable("session")
|
|
1242
|
-
});
|
|
1243
|
-
const user = createNamed(ast, {
|
|
1244
|
-
name: "user",
|
|
1245
|
-
fallback: userDecl
|
|
1246
|
-
});
|
|
1247
|
-
const session = createNamed(ast, {
|
|
1248
|
-
name: "session",
|
|
1249
|
-
fallback: sessionDecl
|
|
1250
|
-
});
|
|
1251
|
-
const userTable = getCallExpression(user);
|
|
1252
|
-
const sessionTable = getCallExpression(session);
|
|
1253
|
-
if (!userTable || !sessionTable) throw new Error("failed to find call expression of `user` or `session`");
|
|
1254
|
-
if (userTable.arguments.length === 1) userTable.arguments.push(create$2({}));
|
|
1255
|
-
if (sessionTable.arguments.length === 1) sessionTable.arguments.push(create$2({}));
|
|
1256
|
-
const userAttributes = userTable.arguments[1];
|
|
1257
|
-
const sessionAttributes = sessionTable.arguments[1];
|
|
1258
|
-
if (userAttributes?.type !== "ObjectExpression" || sessionAttributes?.type !== "ObjectExpression") throw new Error("unexpected shape of `user` or `session` table definition");
|
|
1259
|
-
if (drizzleDialect === "sqlite" || drizzleDialect === "turso") {
|
|
1260
|
-
addNamed(ast, {
|
|
1261
|
-
from: "drizzle-orm/sqlite-core",
|
|
1262
|
-
imports: [
|
|
1263
|
-
"sqliteTable",
|
|
1264
|
-
"text",
|
|
1265
|
-
"integer"
|
|
1266
|
-
]
|
|
1267
|
-
});
|
|
1268
|
-
overrideProperties(userAttributes, { id: parseExpression("text('id').primaryKey()") });
|
|
1269
|
-
if (options$8.demo) overrideProperties(userAttributes, {
|
|
1270
|
-
username: parseExpression("text('username').notNull().unique()"),
|
|
1271
|
-
passwordHash: parseExpression("text('password_hash').notNull()")
|
|
1272
|
-
});
|
|
1273
|
-
overrideProperties(sessionAttributes, {
|
|
1274
|
-
id: parseExpression("text('id').primaryKey()"),
|
|
1275
|
-
userId: parseExpression("text('user_id').notNull().references(() => user.id)"),
|
|
1276
|
-
expiresAt: parseExpression("integer('expires_at', { mode: 'timestamp' }).notNull()")
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1279
|
-
if (drizzleDialect === "mysql") {
|
|
1280
|
-
addNamed(ast, {
|
|
1281
|
-
from: "drizzle-orm/mysql-core",
|
|
1282
|
-
imports: [
|
|
1283
|
-
"mysqlTable",
|
|
1284
|
-
"varchar",
|
|
1285
|
-
"datetime"
|
|
1286
|
-
]
|
|
1287
|
-
});
|
|
1288
|
-
overrideProperties(userAttributes, { id: parseExpression("varchar('id', { length: 255 }).primaryKey()") });
|
|
1289
|
-
if (options$8.demo) overrideProperties(userAttributes, {
|
|
1290
|
-
username: parseExpression("varchar('username', { length: 32 }).notNull().unique()"),
|
|
1291
|
-
passwordHash: parseExpression("varchar('password_hash', { length: 255 }).notNull()")
|
|
1292
|
-
});
|
|
1293
|
-
overrideProperties(sessionAttributes, {
|
|
1294
|
-
id: parseExpression("varchar('id', { length: 255 }).primaryKey()"),
|
|
1295
|
-
userId: parseExpression("varchar('user_id', { length: 255 }).notNull().references(() => user.id)"),
|
|
1296
|
-
expiresAt: parseExpression("datetime('expires_at').notNull()")
|
|
1297
|
-
});
|
|
1298
|
-
}
|
|
1299
|
-
if (drizzleDialect === "postgresql") {
|
|
1300
|
-
addNamed(ast, {
|
|
1301
|
-
from: "drizzle-orm/pg-core",
|
|
1302
|
-
imports: [
|
|
1303
|
-
"pgTable",
|
|
1304
|
-
"text",
|
|
1305
|
-
"timestamp"
|
|
1306
|
-
]
|
|
1307
|
-
});
|
|
1308
|
-
overrideProperties(userAttributes, { id: parseExpression("text('id').primaryKey()") });
|
|
1309
|
-
if (options$8.demo) overrideProperties(userAttributes, {
|
|
1310
|
-
username: parseExpression("text('username').notNull().unique()"),
|
|
1311
|
-
passwordHash: parseExpression("text('password_hash').notNull()")
|
|
1312
|
-
});
|
|
1313
|
-
overrideProperties(sessionAttributes, {
|
|
1314
|
-
id: parseExpression("text('id').primaryKey()"),
|
|
1315
|
-
userId: parseExpression("text('user_id').notNull().references(() => user.id)"),
|
|
1316
|
-
expiresAt: parseExpression("timestamp('expires_at', { withTimezone: true, mode: 'date' }).notNull()")
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
let code = generateCode();
|
|
1320
|
-
if (typescript) {
|
|
1321
|
-
if (!code.includes("export type Session =")) code += "\n\nexport type Session = typeof session.$inferSelect;";
|
|
1322
|
-
if (!code.includes("export type User =")) code += "\n\nexport type User = typeof user.$inferSelect;";
|
|
1323
|
-
}
|
|
1324
|
-
return code;
|
|
1325
|
-
});
|
|
1326
|
-
sv.file(`${kit?.libDirectory}/server/auth.${language}`, (content) => {
|
|
1327
|
-
const { ast, generateCode } = parse$1.script(content);
|
|
1328
|
-
addNamespace(ast, {
|
|
1329
|
-
from: "$lib/server/db/schema",
|
|
1330
|
-
as: "table"
|
|
1331
|
-
});
|
|
1332
|
-
addNamed(ast, {
|
|
1333
|
-
from: "$lib/server/db",
|
|
1334
|
-
imports: ["db"]
|
|
1335
|
-
});
|
|
1336
|
-
addNamed(ast, {
|
|
1337
|
-
from: "@oslojs/encoding",
|
|
1338
|
-
imports: ["encodeBase64url", "encodeHexLowerCase"]
|
|
1339
|
-
});
|
|
1340
|
-
addNamed(ast, {
|
|
1341
|
-
from: "@oslojs/crypto/sha2",
|
|
1342
|
-
imports: ["sha256"]
|
|
1343
|
-
});
|
|
1344
|
-
addNamed(ast, {
|
|
1345
|
-
from: "drizzle-orm",
|
|
1346
|
-
imports: ["eq"]
|
|
1347
|
-
});
|
|
1348
|
-
if (typescript) addNamed(ast, {
|
|
1349
|
-
from: "@sveltejs/kit",
|
|
1350
|
-
imports: ["RequestEvent"],
|
|
1351
|
-
isType: true
|
|
1352
|
-
});
|
|
1353
|
-
const ms = new MagicString(generateCode().trim());
|
|
1354
|
-
const [ts] = createPrinter(typescript);
|
|
1355
|
-
if (!ms.original.includes("const DAY_IN_MS")) ms.append("\n\nconst DAY_IN_MS = 1000 * 60 * 60 * 24;");
|
|
1356
|
-
if (!ms.original.includes("export const sessionCookieName")) ms.append("\n\nexport const sessionCookieName = 'auth-session';");
|
|
1357
|
-
if (!ms.original.includes("export function generateSessionToken")) {
|
|
1358
|
-
const generateSessionToken = dedent_default`
|
|
1359
|
-
export function generateSessionToken() {
|
|
1360
|
-
const bytes = crypto.getRandomValues(new Uint8Array(18));
|
|
1361
|
-
const token = encodeBase64url(bytes);
|
|
1362
|
-
return token;
|
|
1363
|
-
}`;
|
|
1364
|
-
ms.append(`\n\n${generateSessionToken}`);
|
|
1365
|
-
}
|
|
1366
|
-
if (!ms.original.includes("async function createSession")) {
|
|
1367
|
-
const createSession = dedent_default`
|
|
1368
|
-
${ts("", "/**")}
|
|
1369
|
-
${ts("", " * @param {string} token")}
|
|
1370
|
-
${ts("", " * @param {string} userId")}
|
|
1371
|
-
${ts("", " */")}
|
|
1372
|
-
export async function createSession(token${ts(": string")}, userId${ts(": string")}) {
|
|
1373
|
-
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
1374
|
-
const session${ts(": table.Session")} = {
|
|
1375
|
-
id: sessionId,
|
|
1376
|
-
userId,
|
|
1377
|
-
expiresAt: new Date(Date.now() + DAY_IN_MS * 30)
|
|
1378
|
-
};
|
|
1379
|
-
await db.insert(table.session).values(session);
|
|
1380
|
-
return session;
|
|
1381
|
-
}`;
|
|
1382
|
-
ms.append(`\n\n${createSession}`);
|
|
1383
|
-
}
|
|
1384
|
-
if (!ms.original.includes("async function validateSessionToken")) {
|
|
1385
|
-
const validateSessionToken = dedent_default`
|
|
1386
|
-
${ts("", "/** @param {string} token */")}
|
|
1387
|
-
export async function validateSessionToken(token${ts(": string")}) {
|
|
1388
|
-
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
1389
|
-
const [result] = await db
|
|
1390
|
-
.select({
|
|
1391
|
-
// Adjust user table here to tweak returned data
|
|
1392
|
-
user: { id: table.user.id, username: table.user.username },
|
|
1393
|
-
session: table.session
|
|
1394
|
-
})
|
|
1395
|
-
.from(table.session)
|
|
1396
|
-
.innerJoin(table.user, eq(table.session.userId, table.user.id))
|
|
1397
|
-
.where(eq(table.session.id, sessionId));
|
|
1398
|
-
|
|
1399
|
-
if (!result) {
|
|
1400
|
-
return { session: null, user: null };
|
|
1401
|
-
}
|
|
1402
|
-
const { session, user } = result;
|
|
1403
|
-
|
|
1404
|
-
const sessionExpired = Date.now() >= session.expiresAt.getTime();
|
|
1405
|
-
if (sessionExpired) {
|
|
1406
|
-
await db.delete(table.session).where(eq(table.session.id, session.id));
|
|
1407
|
-
return { session: null, user: null };
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
const renewSession = Date.now() >= session.expiresAt.getTime() - DAY_IN_MS * 15;
|
|
1411
|
-
if (renewSession) {
|
|
1412
|
-
session.expiresAt = new Date(Date.now() + DAY_IN_MS * 30);
|
|
1413
|
-
await db
|
|
1414
|
-
.update(table.session)
|
|
1415
|
-
.set({ expiresAt: session.expiresAt })
|
|
1416
|
-
.where(eq(table.session.id, session.id));
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
return { session, user };
|
|
1420
|
-
}`;
|
|
1421
|
-
ms.append(`\n\n${validateSessionToken}`);
|
|
1422
|
-
}
|
|
1423
|
-
if (typescript && !ms.original.includes("export type SessionValidationResult")) ms.append(`\n\nexport type SessionValidationResult = Awaited<ReturnType<typeof validateSessionToken>>;`);
|
|
1424
|
-
if (!ms.original.includes("async function invalidateSession")) {
|
|
1425
|
-
const invalidateSession = dedent_default`
|
|
1426
|
-
${ts("", "/** @param {string} sessionId */")}
|
|
1427
|
-
export async function invalidateSession(sessionId${ts(": string")}) {
|
|
1428
|
-
await db.delete(table.session).where(eq(table.session.id, sessionId));
|
|
1429
|
-
}`;
|
|
1430
|
-
ms.append(`\n\n${invalidateSession}`);
|
|
1431
|
-
}
|
|
1432
|
-
if (!ms.original.includes("export function setSessionTokenCookie")) {
|
|
1433
|
-
const setSessionTokenCookie = dedent_default`
|
|
1434
|
-
${ts("", "/**")}
|
|
1435
|
-
${ts("", " * @param {import(\"@sveltejs/kit\").RequestEvent} event")}
|
|
1436
|
-
${ts("", " * @param {string} token")}
|
|
1437
|
-
${ts("", " * @param {Date} expiresAt")}
|
|
1438
|
-
${ts("", " */")}
|
|
1439
|
-
export function setSessionTokenCookie(event${ts(": RequestEvent")}, token${ts(": string")}, expiresAt${ts(": Date")}) {
|
|
1440
|
-
event.cookies.set(sessionCookieName, token, {
|
|
1441
|
-
expires: expiresAt,
|
|
1442
|
-
path: '/'
|
|
1443
|
-
});
|
|
1444
|
-
}`;
|
|
1445
|
-
ms.append(`\n\n${setSessionTokenCookie}`);
|
|
1446
|
-
}
|
|
1447
|
-
if (!ms.original.includes("export function deleteSessionTokenCookie")) {
|
|
1448
|
-
const deleteSessionTokenCookie = dedent_default`
|
|
1449
|
-
${ts("", "/** @param {import(\"@sveltejs/kit\").RequestEvent} event */")}
|
|
1450
|
-
export function deleteSessionTokenCookie(event${ts(": RequestEvent")}) {
|
|
1451
|
-
event.cookies.delete(sessionCookieName, {
|
|
1452
|
-
path: '/'
|
|
1453
|
-
});
|
|
1454
|
-
}`;
|
|
1455
|
-
ms.append(`\n\n${deleteSessionTokenCookie}`);
|
|
1456
|
-
}
|
|
1457
|
-
return ms.toString();
|
|
1458
|
-
});
|
|
1459
|
-
if (typescript) sv.file("src/app.d.ts", (content) => {
|
|
1460
|
-
const { ast, generateCode } = parse$1.script(content);
|
|
1461
|
-
const locals = addGlobalAppInterface(ast, { name: "Locals" });
|
|
1462
|
-
if (!locals) throw new Error("Failed detecting `locals` interface in `src/app.d.ts`");
|
|
1463
|
-
const user = locals.body.body.find((prop) => hasTypeProperty(prop, { name: "user" }));
|
|
1464
|
-
const session = locals.body.body.find((prop) => hasTypeProperty(prop, { name: "session" }));
|
|
1465
|
-
if (!user) locals.body.body.push(createLuciaType("user"));
|
|
1466
|
-
if (!session) locals.body.body.push(createLuciaType("session"));
|
|
1467
|
-
return generateCode();
|
|
1468
|
-
});
|
|
1469
|
-
sv.file(`src/hooks.server.${language}`, (content) => {
|
|
1470
|
-
const { ast, generateCode } = parse$1.script(content);
|
|
1471
|
-
addNamespace(ast, {
|
|
1472
|
-
from: "$lib/server/auth",
|
|
1473
|
-
as: "auth"
|
|
1474
|
-
});
|
|
1475
|
-
addHooksHandle(ast, {
|
|
1476
|
-
language,
|
|
1477
|
-
newHandleName: "handleAuth",
|
|
1478
|
-
handleContent: getAuthHandleContent()
|
|
1479
|
-
});
|
|
1480
|
-
return generateCode();
|
|
1481
|
-
});
|
|
1482
|
-
if (options$8.demo) {
|
|
1483
|
-
sv.file(`${kit?.routesDirectory}/demo/+page.svelte`, (content) => {
|
|
1484
|
-
return addToDemoPage(content, "lucia", language);
|
|
1485
|
-
});
|
|
1486
|
-
sv.file(`${kit.routesDirectory}/demo/lucia/login/+page.server.${language}`, (content) => {
|
|
1487
|
-
if (content) {
|
|
1488
|
-
const filePath = `${kit.routesDirectory}/demo/lucia/login/+page.server.${typescript ? "ts" : "js"}`;
|
|
1489
|
-
T.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
1490
|
-
return content;
|
|
1491
|
-
}
|
|
1492
|
-
const [ts] = createPrinter(typescript);
|
|
1493
|
-
return dedent_default`
|
|
1494
|
-
import { hash, verify } from '@node-rs/argon2';
|
|
1495
|
-
import { encodeBase32LowerCase } from '@oslojs/encoding';
|
|
1496
|
-
import { fail, redirect } from '@sveltejs/kit';
|
|
1497
|
-
import { eq } from 'drizzle-orm';
|
|
1498
|
-
import * as auth from '$lib/server/auth';
|
|
1499
|
-
import { db } from '$lib/server/db';
|
|
1500
|
-
import * as table from '$lib/server/db/schema';
|
|
1501
|
-
${ts("import type { Actions, PageServerLoad } from './$types';\n")}
|
|
1502
|
-
export const load${ts(": PageServerLoad")} = async (event) => {
|
|
1503
|
-
if (event.locals.user) {
|
|
1504
|
-
return redirect(302, '/demo/lucia');
|
|
1505
|
-
}
|
|
1506
|
-
return {};
|
|
1507
|
-
};
|
|
1508
|
-
|
|
1509
|
-
export const actions${ts(": Actions")} = {
|
|
1510
|
-
login: async (event) => {
|
|
1511
|
-
const formData = await event.request.formData();
|
|
1512
|
-
const username = formData.get('username');
|
|
1513
|
-
const password = formData.get('password');
|
|
1514
|
-
|
|
1515
|
-
if (!validateUsername(username)) {
|
|
1516
|
-
return fail(400, { message: 'Invalid username (min 3, max 31 characters, alphanumeric only)' });
|
|
1517
|
-
}
|
|
1518
|
-
if (!validatePassword(password)) {
|
|
1519
|
-
return fail(400, { message: 'Invalid password (min 6, max 255 characters)' });
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
const results = await db
|
|
1523
|
-
.select()
|
|
1524
|
-
.from(table.user)
|
|
1525
|
-
.where(eq(table.user.username, username));
|
|
1526
|
-
|
|
1527
|
-
const existingUser = results.at(0);
|
|
1528
|
-
if (!existingUser) {
|
|
1529
|
-
return fail(400, { message: 'Incorrect username or password' });
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
const validPassword = await verify(existingUser.passwordHash, password, {
|
|
1533
|
-
memoryCost: 19456,
|
|
1534
|
-
timeCost: 2,
|
|
1535
|
-
outputLen: 32,
|
|
1536
|
-
parallelism: 1,
|
|
1537
|
-
});
|
|
1538
|
-
if (!validPassword) {
|
|
1539
|
-
return fail(400, { message: 'Incorrect username or password' });
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
const sessionToken = auth.generateSessionToken();
|
|
1543
|
-
const session = await auth.createSession(sessionToken, existingUser.id);
|
|
1544
|
-
auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
|
1545
|
-
|
|
1546
|
-
return redirect(302, '/demo/lucia');
|
|
1547
|
-
},
|
|
1548
|
-
register: async (event) => {
|
|
1549
|
-
const formData = await event.request.formData();
|
|
1550
|
-
const username = formData.get('username');
|
|
1551
|
-
const password = formData.get('password');
|
|
1552
|
-
|
|
1553
|
-
if (!validateUsername(username)) {
|
|
1554
|
-
return fail(400, { message: 'Invalid username' });
|
|
1555
|
-
}
|
|
1556
|
-
if (!validatePassword(password)) {
|
|
1557
|
-
return fail(400, { message: 'Invalid password' });
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
const userId = generateUserId();
|
|
1561
|
-
const passwordHash = await hash(password, {
|
|
1562
|
-
// recommended minimum parameters
|
|
1563
|
-
memoryCost: 19456,
|
|
1564
|
-
timeCost: 2,
|
|
1565
|
-
outputLen: 32,
|
|
1566
|
-
parallelism: 1,
|
|
1567
|
-
});
|
|
1568
|
-
|
|
1569
|
-
try {
|
|
1570
|
-
await db.insert(table.user).values({ id: userId, username, passwordHash });
|
|
1571
|
-
|
|
1572
|
-
const sessionToken = auth.generateSessionToken();
|
|
1573
|
-
const session = await auth.createSession(sessionToken, userId);
|
|
1574
|
-
auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
|
1575
|
-
} catch {
|
|
1576
|
-
return fail(500, { message: 'An error has occurred' });
|
|
1577
|
-
}
|
|
1578
|
-
return redirect(302, '/demo/lucia');
|
|
1579
|
-
},
|
|
1580
|
-
};
|
|
1581
|
-
|
|
1582
|
-
function generateUserId() {
|
|
1583
|
-
// ID with 120 bits of entropy, or about the same as UUID v4.
|
|
1584
|
-
const bytes = crypto.getRandomValues(new Uint8Array(15));
|
|
1585
|
-
const id = encodeBase32LowerCase(bytes);
|
|
1586
|
-
return id;
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
function validateUsername(username${ts(": unknown")})${ts(": username is string")} {
|
|
1590
|
-
return (
|
|
1591
|
-
typeof username === 'string' &&
|
|
1592
|
-
username.length >= 3 &&
|
|
1593
|
-
username.length <= 31 &&
|
|
1594
|
-
/^[a-z0-9_-]+$/.test(username)
|
|
1595
|
-
);
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
function validatePassword(password${ts(": unknown")})${ts(": password is string")} {
|
|
1599
|
-
return (
|
|
1600
|
-
typeof password === 'string' &&
|
|
1601
|
-
password.length >= 6 &&
|
|
1602
|
-
password.length <= 255
|
|
1603
|
-
);
|
|
1604
|
-
}
|
|
1605
|
-
`;
|
|
1606
|
-
});
|
|
1607
|
-
sv.file(`${kit.routesDirectory}/demo/lucia/login/+page.svelte`, (content) => {
|
|
1608
|
-
if (content) {
|
|
1609
|
-
const filePath = `${kit.routesDirectory}/demo/lucia/login/+page.svelte`;
|
|
1610
|
-
T.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
1611
|
-
return content;
|
|
1612
|
-
}
|
|
1613
|
-
const tailwind = dependencyVersion("@tailwindcss/vite") !== void 0;
|
|
1614
|
-
const twInputClasses = "class=\"mt-1 px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"";
|
|
1615
|
-
const twBtnClasses = "class=\"bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition\"";
|
|
1616
|
-
const [ts, s5] = createPrinter(typescript, !!dependencyVersion("svelte")?.startsWith("5"));
|
|
1617
|
-
return dedent_default`
|
|
1618
|
-
<script ${ts("lang='ts'")}>
|
|
1619
|
-
import { enhance } from '$app/forms';
|
|
1620
|
-
${ts("import type { ActionData } from './$types';\n")}
|
|
1621
|
-
${s5(`let { form }${ts(": { form: ActionData }")} = $props();`, `export let form${ts(": ActionData")};`)}
|
|
1622
|
-
<\/script>
|
|
1623
|
-
|
|
1624
|
-
<h1>Login/Register</h1>
|
|
1625
|
-
<form method="post" action="?/login" use:enhance>
|
|
1626
|
-
<label>
|
|
1627
|
-
Username
|
|
1628
|
-
<input
|
|
1629
|
-
name="username"
|
|
1630
|
-
${tailwind ? twInputClasses : ""}
|
|
1631
|
-
/>
|
|
1632
|
-
</label>
|
|
1633
|
-
<label>
|
|
1634
|
-
Password
|
|
1635
|
-
<input
|
|
1636
|
-
type="password"
|
|
1637
|
-
name="password"
|
|
1638
|
-
${tailwind ? twInputClasses : ""}
|
|
1639
|
-
/>
|
|
1640
|
-
</label>
|
|
1641
|
-
<button ${tailwind ? twBtnClasses : ""}
|
|
1642
|
-
>Login</button>
|
|
1643
|
-
<button
|
|
1644
|
-
formaction="?/register"
|
|
1645
|
-
${tailwind ? twBtnClasses : ""}
|
|
1646
|
-
>Register</button>
|
|
1647
|
-
</form>
|
|
1648
|
-
<p style='color: red'>{form?.message ?? ''}</p>
|
|
1649
|
-
`;
|
|
1650
|
-
});
|
|
1651
|
-
sv.file(`${kit.routesDirectory}/demo/lucia/+page.server.${language}`, (content) => {
|
|
1652
|
-
if (content) {
|
|
1653
|
-
const filePath = `${kit.routesDirectory}/demo/lucia/+page.server.${typescript ? "ts" : "js"}`;
|
|
1654
|
-
T.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
1655
|
-
return content;
|
|
1656
|
-
}
|
|
1657
|
-
const [ts] = createPrinter(typescript);
|
|
1658
|
-
return dedent_default`
|
|
1659
|
-
import * as auth from '$lib/server/auth';
|
|
1660
|
-
import { fail, redirect } from '@sveltejs/kit';
|
|
1661
|
-
import { getRequestEvent } from '$app/server';
|
|
1662
|
-
${ts("import type { Actions, PageServerLoad } from './$types';\n")}
|
|
1663
|
-
export const load${ts(": PageServerLoad")} = async () => {
|
|
1664
|
-
const user = requireLogin()
|
|
1665
|
-
return { user };
|
|
1666
|
-
};
|
|
1667
|
-
|
|
1668
|
-
export const actions${ts(": Actions")} = {
|
|
1669
|
-
logout: async (event) => {
|
|
1670
|
-
if (!event.locals.session) {
|
|
1671
|
-
return fail(401);
|
|
1672
|
-
}
|
|
1673
|
-
await auth.invalidateSession(event.locals.session.id);
|
|
1674
|
-
auth.deleteSessionTokenCookie(event);
|
|
1675
|
-
|
|
1676
|
-
return redirect(302, '/demo/lucia/login');
|
|
1677
|
-
},
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
function requireLogin() {
|
|
1681
|
-
const { locals } = getRequestEvent();
|
|
1682
|
-
|
|
1683
|
-
if (!locals.user) {
|
|
1684
|
-
return redirect(302, "/demo/lucia/login");
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
return locals.user;
|
|
1688
|
-
}
|
|
1689
|
-
`;
|
|
1690
|
-
});
|
|
1691
|
-
sv.file(`${kit.routesDirectory}/demo/lucia/+page.svelte`, (content) => {
|
|
1692
|
-
if (content) {
|
|
1693
|
-
const filePath = `${kit.routesDirectory}/demo/lucia/+page.svelte`;
|
|
1694
|
-
T.warn(`Existing ${color.warning(filePath)} file. Could not update.`);
|
|
1695
|
-
return content;
|
|
1696
|
-
}
|
|
1697
|
-
const [ts, s5] = createPrinter(typescript, !!dependencyVersion("svelte")?.startsWith("5"));
|
|
1698
|
-
return dedent_default`
|
|
1699
|
-
<script ${ts("lang='ts'")}>
|
|
1700
|
-
import { enhance } from '$app/forms';
|
|
1701
|
-
${ts("import type { PageServerData } from './$types';\n")}
|
|
1702
|
-
${s5(`let { data }${ts(": { data: PageServerData }")} = $props();`, `export let data${ts(": PageServerData")};`)}
|
|
1703
|
-
<\/script>
|
|
1704
|
-
|
|
1705
|
-
<h1>Hi, {data.user.username}!</h1>
|
|
1706
|
-
<p>Your user ID is {data.user.id}.</p>
|
|
1707
|
-
<form method='post' action='?/logout' use:enhance>
|
|
1708
|
-
<button>Sign out</button>
|
|
1709
|
-
</form>
|
|
1710
|
-
`;
|
|
1711
|
-
});
|
|
1712
|
-
}
|
|
1713
|
-
},
|
|
1714
|
-
nextSteps: ({ options: options$8, packageManager }) => {
|
|
1715
|
-
const { command, args } = resolveCommand(packageManager, "run", ["db:push"]);
|
|
1716
|
-
const steps = [`Run ${color.command(`${command} ${args.join(" ")}`)} to update your database schema`];
|
|
1717
|
-
if (options$8.demo) steps.push(`Visit ${color.route("/demo/lucia")} route to view the demo`);
|
|
1718
|
-
return steps;
|
|
1719
|
-
}
|
|
1720
|
-
});
|
|
1721
|
-
function createLuciaType(name$1) {
|
|
1722
|
-
return {
|
|
1723
|
-
type: "TSPropertySignature",
|
|
1724
|
-
key: {
|
|
1725
|
-
type: "Identifier",
|
|
1726
|
-
name: name$1
|
|
1727
|
-
},
|
|
1728
|
-
computed: false,
|
|
1729
|
-
typeAnnotation: {
|
|
1730
|
-
type: "TSTypeAnnotation",
|
|
1731
|
-
typeAnnotation: {
|
|
1732
|
-
type: "TSIndexedAccessType",
|
|
1733
|
-
objectType: {
|
|
1734
|
-
type: "TSImportType",
|
|
1735
|
-
argument: {
|
|
1736
|
-
type: "Literal",
|
|
1737
|
-
value: "$lib/server/auth"
|
|
1738
|
-
},
|
|
1739
|
-
qualifier: {
|
|
1740
|
-
type: "Identifier",
|
|
1741
|
-
name: "SessionValidationResult"
|
|
1742
|
-
}
|
|
1743
|
-
},
|
|
1744
|
-
indexType: {
|
|
1745
|
-
type: "TSLiteralType",
|
|
1746
|
-
literal: {
|
|
1747
|
-
type: "Literal",
|
|
1748
|
-
value: name$1
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
};
|
|
1754
|
-
}
|
|
1755
|
-
function getAuthHandleContent() {
|
|
1756
|
-
return `
|
|
1757
|
-
async ({ event, resolve }) => {
|
|
1758
|
-
const sessionToken = event.cookies.get(auth.sessionCookieName);
|
|
1759
|
-
if (!sessionToken) {
|
|
1760
|
-
event.locals.user = null;
|
|
1761
|
-
event.locals.session = null;
|
|
1762
|
-
return resolve(event);
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
const { session, user } = await auth.validateSessionToken(sessionToken);
|
|
1766
|
-
if (session) {
|
|
1767
|
-
auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
|
1768
|
-
} else {
|
|
1769
|
-
auth.deleteSessionTokenCookie(event);
|
|
1770
|
-
}
|
|
1771
|
-
|
|
1772
|
-
event.locals.user = user;
|
|
1773
|
-
event.locals.session = session;
|
|
1774
|
-
|
|
1775
|
-
return resolve(event);
|
|
1776
|
-
};`;
|
|
1777
|
-
}
|
|
1778
|
-
function getCallExpression(ast) {
|
|
1779
|
-
let callExpression;
|
|
1780
|
-
walk(ast, null, { CallExpression(node) {
|
|
1781
|
-
callExpression ??= node;
|
|
1782
|
-
} });
|
|
1783
|
-
return callExpression;
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
//#endregion
|
|
1787
|
-
//#region lib/addons/mcp/index.ts
|
|
1604
|
+
//#region lib/addons/mcp.ts
|
|
1788
1605
|
const options$5 = defineAddonOptions().add("ide", {
|
|
1789
1606
|
question: "Which client would you like to use?",
|
|
1790
1607
|
type: "multiselect",
|
|
@@ -1919,7 +1736,7 @@ var mcp_default = defineAddon({
|
|
|
1919
1736
|
return generateCode();
|
|
1920
1737
|
});
|
|
1921
1738
|
}
|
|
1922
|
-
if (filesExistingAlready.length > 0)
|
|
1739
|
+
if (filesExistingAlready.length > 0) R.warn(`${filesExistingAlready.map((path$2) => color.path(path$2)).join(", ")} already exists, we didn't touch ${filesExistingAlready.length > 1 ? "them" : "it"}. See ${color.website("https://svelte.dev/docs/mcp/overview#Usage")} for manual setup.`);
|
|
1923
1740
|
},
|
|
1924
1741
|
nextSteps({ options: options$8 }) {
|
|
1925
1742
|
const steps = [];
|
|
@@ -1929,7 +1746,7 @@ var mcp_default = defineAddon({
|
|
|
1929
1746
|
});
|
|
1930
1747
|
|
|
1931
1748
|
//#endregion
|
|
1932
|
-
//#region lib/addons/mdsvex
|
|
1749
|
+
//#region lib/addons/mdsvex.ts
|
|
1933
1750
|
var mdsvex_default = defineAddon({
|
|
1934
1751
|
id: "mdsvex",
|
|
1935
1752
|
shortDescription: "svelte + markdown",
|
|
@@ -1971,7 +1788,7 @@ var mdsvex_default = defineAddon({
|
|
|
1971
1788
|
});
|
|
1972
1789
|
|
|
1973
1790
|
//#endregion
|
|
1974
|
-
//#region lib/addons/paraglide
|
|
1791
|
+
//#region lib/addons/paraglide.ts
|
|
1975
1792
|
const DEFAULT_INLANG_PROJECT = {
|
|
1976
1793
|
$schema: "https://inlang.com/schema/project-settings",
|
|
1977
1794
|
modules: ["https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js", "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"],
|
|
@@ -2007,7 +1824,7 @@ var paraglide_default = defineAddon({
|
|
|
2007
1824
|
run: ({ sv, options: options$8, files, language, kit }) => {
|
|
2008
1825
|
if (!kit) throw new Error("SvelteKit is required");
|
|
2009
1826
|
const paraglideOutDir = "src/lib/paraglide";
|
|
2010
|
-
sv.devDependency("@inlang/paraglide-js", "^2.
|
|
1827
|
+
sv.devDependency("@inlang/paraglide-js", "^2.10.0");
|
|
2011
1828
|
sv.file(files.viteConfig, (content) => {
|
|
2012
1829
|
const { ast, generateCode } = parse$1.script(content);
|
|
2013
1830
|
const vitePluginName = "paraglideVitePlugin";
|
|
@@ -2036,11 +1853,11 @@ var paraglide_default = defineAddon({
|
|
|
2036
1853
|
if (createNamed(ast, {
|
|
2037
1854
|
name: "reroute",
|
|
2038
1855
|
fallback: rerouteIdentifier
|
|
2039
|
-
}).declaration !== rerouteIdentifier)
|
|
1856
|
+
}).declaration !== rerouteIdentifier) R.warn("Adding the reroute hook automatically failed. Add it manually");
|
|
2040
1857
|
return generateCode();
|
|
2041
1858
|
});
|
|
2042
1859
|
sv.file(`src/hooks.server.${language}`, (content) => {
|
|
2043
|
-
const { ast, generateCode } = parse$1.script(content);
|
|
1860
|
+
const { ast, generateCode, comments } = parse$1.script(content);
|
|
2044
1861
|
addNamed(ast, {
|
|
2045
1862
|
from: "$lib/paraglide/server",
|
|
2046
1863
|
imports: ["paraglideMiddleware"]
|
|
@@ -2053,7 +1870,8 @@ var paraglide_default = defineAddon({
|
|
|
2053
1870
|
return resolve(event, {
|
|
2054
1871
|
transformPageChunk: ({ html }) => html.replace('%paraglide.lang%', locale)
|
|
2055
1872
|
});
|
|
2056
|
-
})
|
|
1873
|
+
});`,
|
|
1874
|
+
comments
|
|
2057
1875
|
});
|
|
2058
1876
|
return generateCode();
|
|
2059
1877
|
});
|
|
@@ -2061,7 +1879,7 @@ var paraglide_default = defineAddon({
|
|
|
2061
1879
|
const { ast, generateCode } = parse$1.html(content);
|
|
2062
1880
|
const htmlNode = ast.nodes.find((child) => child.type === "RegularElement" && child.name === "html");
|
|
2063
1881
|
if (!htmlNode) {
|
|
2064
|
-
|
|
1882
|
+
R.warn("Could not find <html> node in app.html. You'll need to add the language placeholder manually");
|
|
2065
1883
|
return generateCode();
|
|
2066
1884
|
}
|
|
2067
1885
|
addAttribute(htmlNode, "lang", "%paraglide.lang%");
|
|
@@ -2069,7 +1887,8 @@ var paraglide_default = defineAddon({
|
|
|
2069
1887
|
});
|
|
2070
1888
|
sv.file(files.gitignore, (content) => {
|
|
2071
1889
|
if (!content) return content;
|
|
2072
|
-
|
|
1890
|
+
content = upsert(content, paraglideOutDir, { comment: "Paraglide" });
|
|
1891
|
+
content = upsert(content, "project.inlang/cache/");
|
|
2073
1892
|
return content;
|
|
2074
1893
|
});
|
|
2075
1894
|
sv.file("project.inlang/settings.json", (content) => {
|
|
@@ -2151,14 +1970,14 @@ function parseLanguageTagInput(input) {
|
|
|
2151
1970
|
}
|
|
2152
1971
|
|
|
2153
1972
|
//#endregion
|
|
2154
|
-
//#region lib/addons/playwright
|
|
1973
|
+
//#region lib/addons/playwright.ts
|
|
2155
1974
|
var playwright_default = defineAddon({
|
|
2156
1975
|
id: "playwright",
|
|
2157
1976
|
shortDescription: "browser testing",
|
|
2158
1977
|
homepage: "https://playwright.dev",
|
|
2159
1978
|
options: {},
|
|
2160
1979
|
run: ({ sv, language, files }) => {
|
|
2161
|
-
sv.devDependency("@playwright/test", "^1.
|
|
1980
|
+
sv.devDependency("@playwright/test", "^1.58.1");
|
|
2162
1981
|
sv.file(files.package, (content) => {
|
|
2163
1982
|
const { data, generateCode } = parse$1.json(content);
|
|
2164
1983
|
packageScriptsUpsert(data, "test:e2e", "playwright test");
|
|
@@ -2167,8 +1986,7 @@ var playwright_default = defineAddon({
|
|
|
2167
1986
|
});
|
|
2168
1987
|
sv.file(files.gitignore, (content) => {
|
|
2169
1988
|
if (!content) return content;
|
|
2170
|
-
|
|
2171
|
-
return "test-results\n" + content.trim();
|
|
1989
|
+
return upsert(content, "test-results", { comment: "Playwright" });
|
|
2172
1990
|
});
|
|
2173
1991
|
sv.file(`e2e/demo.test.${language}`, (content) => {
|
|
2174
1992
|
if (content) return content;
|
|
@@ -2199,14 +2017,14 @@ var playwright_default = defineAddon({
|
|
|
2199
2017
|
});
|
|
2200
2018
|
overrideProperties(defaultExport.arguments[0], config);
|
|
2201
2019
|
} else if (defaultExport.type === "ObjectExpression") overrideProperties(defaultExport, config);
|
|
2202
|
-
else
|
|
2020
|
+
else R.warn("Unexpected playwright config for playwright add-on. Could not update.");
|
|
2203
2021
|
return generateCode();
|
|
2204
2022
|
});
|
|
2205
2023
|
}
|
|
2206
2024
|
});
|
|
2207
2025
|
|
|
2208
2026
|
//#endregion
|
|
2209
|
-
//#region lib/addons/prettier
|
|
2027
|
+
//#region lib/addons/prettier.ts
|
|
2210
2028
|
var prettier_default = defineAddon({
|
|
2211
2029
|
id: "prettier",
|
|
2212
2030
|
shortDescription: "formatter",
|
|
@@ -2215,8 +2033,8 @@ var prettier_default = defineAddon({
|
|
|
2215
2033
|
run: ({ sv, dependencyVersion, files }) => {
|
|
2216
2034
|
const tailwindcssInstalled = Boolean(dependencyVersion("tailwindcss"));
|
|
2217
2035
|
if (tailwindcssInstalled) sv.devDependency("prettier-plugin-tailwindcss", "^0.7.2");
|
|
2218
|
-
sv.devDependency("prettier", "^3.
|
|
2219
|
-
sv.devDependency("prettier-plugin-svelte", "^3.4.
|
|
2036
|
+
sv.devDependency("prettier", "^3.8.1");
|
|
2037
|
+
sv.devDependency("prettier-plugin-svelte", "^3.4.1");
|
|
2220
2038
|
sv.file(files.prettierignore, (content) => {
|
|
2221
2039
|
if (content) return content;
|
|
2222
2040
|
return dedent_default`
|
|
@@ -2236,7 +2054,7 @@ var prettier_default = defineAddon({
|
|
|
2236
2054
|
try {
|
|
2237
2055
|
({data, generateCode} = parse$1.json(content));
|
|
2238
2056
|
} catch {
|
|
2239
|
-
|
|
2057
|
+
R.warn(`A ${color.warning(".prettierrc")} config already exists and cannot be parsed as JSON. Skipping initialization.`);
|
|
2240
2058
|
return content;
|
|
2241
2059
|
}
|
|
2242
2060
|
if (Object.keys(data).length === 0) {
|
|
@@ -2262,12 +2080,11 @@ var prettier_default = defineAddon({
|
|
|
2262
2080
|
const eslintInstalled = hasEslint(eslintVersion);
|
|
2263
2081
|
sv.file(files.package, (content) => {
|
|
2264
2082
|
const { data, generateCode } = parse$1.json(content);
|
|
2265
|
-
|
|
2266
|
-
packageScriptsUpsert(data, "lint", cmd);
|
|
2083
|
+
packageScriptsUpsert(data, "lint", "prettier --check .", { mode: "prepend" });
|
|
2267
2084
|
packageScriptsUpsert(data, "format", "prettier --write .");
|
|
2268
2085
|
return generateCode();
|
|
2269
2086
|
});
|
|
2270
|
-
if (eslintVersion?.startsWith(SUPPORTED_ESLINT_VERSION) === false)
|
|
2087
|
+
if (eslintVersion?.startsWith(SUPPORTED_ESLINT_VERSION) === false) R.warn(`An older major version of ${color.warning("eslint")} was detected. Skipping ${color.warning("eslint-config-prettier")} installation.`);
|
|
2271
2088
|
if (eslintInstalled) {
|
|
2272
2089
|
sv.devDependency("eslint-config-prettier", "^10.1.8");
|
|
2273
2090
|
sv.file(files.eslintConfig, addEslintConfigPrettier);
|
|
@@ -2280,7 +2097,7 @@ function hasEslint(version$1) {
|
|
|
2280
2097
|
}
|
|
2281
2098
|
|
|
2282
2099
|
//#endregion
|
|
2283
|
-
//#region lib/addons/storybook
|
|
2100
|
+
//#region lib/addons/storybook.ts
|
|
2284
2101
|
var storybook_default = defineAddon({
|
|
2285
2102
|
id: "storybook",
|
|
2286
2103
|
shortDescription: "frontend workshop",
|
|
@@ -2303,7 +2120,7 @@ var storybook_default = defineAddon({
|
|
|
2303
2120
|
});
|
|
2304
2121
|
|
|
2305
2122
|
//#endregion
|
|
2306
|
-
//#region lib/addons/sveltekit-adapter
|
|
2123
|
+
//#region lib/addons/sveltekit-adapter.ts
|
|
2307
2124
|
const adapters = [
|
|
2308
2125
|
{
|
|
2309
2126
|
id: "auto",
|
|
@@ -2313,7 +2130,7 @@ const adapters = [
|
|
|
2313
2130
|
{
|
|
2314
2131
|
id: "node",
|
|
2315
2132
|
package: "@sveltejs/adapter-node",
|
|
2316
|
-
version: "^5.
|
|
2133
|
+
version: "^5.5.2"
|
|
2317
2134
|
},
|
|
2318
2135
|
{
|
|
2319
2136
|
id: "static",
|
|
@@ -2323,12 +2140,12 @@ const adapters = [
|
|
|
2323
2140
|
{
|
|
2324
2141
|
id: "vercel",
|
|
2325
2142
|
package: "@sveltejs/adapter-vercel",
|
|
2326
|
-
version: "^6.
|
|
2143
|
+
version: "^6.3.1"
|
|
2327
2144
|
},
|
|
2328
2145
|
{
|
|
2329
2146
|
id: "cloudflare",
|
|
2330
2147
|
package: "@sveltejs/adapter-cloudflare",
|
|
2331
|
-
version: "^7.2.
|
|
2148
|
+
version: "^7.2.6"
|
|
2332
2149
|
},
|
|
2333
2150
|
{
|
|
2334
2151
|
id: "netlify",
|
|
@@ -2410,7 +2227,7 @@ var sveltekit_adapter_default = defineAddon({
|
|
|
2410
2227
|
return generateCode();
|
|
2411
2228
|
});
|
|
2412
2229
|
if (adapter.package === "@sveltejs/adapter-cloudflare") {
|
|
2413
|
-
sv.devDependency("wrangler", "^4.
|
|
2230
|
+
sv.devDependency("wrangler", "^4.63.0");
|
|
2414
2231
|
const configFormat = fileExists(cwd$1, "wrangler.toml") ? "toml" : "jsonc";
|
|
2415
2232
|
sv.file(`wrangler.${configFormat}`, (content) => {
|
|
2416
2233
|
const { data, generateCode } = configFormat === "jsonc" ? parse$1.json(content) : parse$1.toml(content);
|
|
@@ -2437,7 +2254,8 @@ var sveltekit_adapter_default = defineAddon({
|
|
|
2437
2254
|
const jsconfig = fileExists(cwd$1, "jsconfig.json");
|
|
2438
2255
|
if (language === "ts" || jsconfig) {
|
|
2439
2256
|
sv.file(files.gitignore, (content) => {
|
|
2440
|
-
|
|
2257
|
+
if (content.length === 0) return content;
|
|
2258
|
+
return upsert(content, "/worker-configuration.d.ts", { comment: "Cloudflare Types" });
|
|
2441
2259
|
});
|
|
2442
2260
|
sv.file(files.package, (content) => {
|
|
2443
2261
|
const { data, generateCode } = parse$1.json(content);
|
|
@@ -2493,7 +2311,7 @@ function createCloudflarePlatformType(name$1, value, optional$1 = false) {
|
|
|
2493
2311
|
}
|
|
2494
2312
|
|
|
2495
2313
|
//#endregion
|
|
2496
|
-
//#region lib/addons/tailwindcss
|
|
2314
|
+
//#region lib/addons/tailwindcss.ts
|
|
2497
2315
|
const plugins = [{
|
|
2498
2316
|
id: "typography",
|
|
2499
2317
|
package: "@tailwindcss/typography",
|
|
@@ -2501,7 +2319,7 @@ const plugins = [{
|
|
|
2501
2319
|
}, {
|
|
2502
2320
|
id: "forms",
|
|
2503
2321
|
package: "@tailwindcss/forms",
|
|
2504
|
-
version: "^0.5.
|
|
2322
|
+
version: "^0.5.11"
|
|
2505
2323
|
}];
|
|
2506
2324
|
const options$2 = defineAddonOptions().add("plugins", {
|
|
2507
2325
|
type: "multiselect",
|
|
@@ -2522,8 +2340,8 @@ var tailwindcss_default = defineAddon({
|
|
|
2522
2340
|
options: options$2,
|
|
2523
2341
|
run: ({ sv, options: options$8, files, kit, dependencyVersion, language }) => {
|
|
2524
2342
|
const prettierInstalled = Boolean(dependencyVersion("prettier"));
|
|
2525
|
-
sv.devDependency("tailwindcss", "^4.1.
|
|
2526
|
-
sv.devDependency("@tailwindcss/vite", "^4.1.
|
|
2343
|
+
sv.devDependency("tailwindcss", "^4.1.18");
|
|
2344
|
+
sv.devDependency("@tailwindcss/vite", "^4.1.18");
|
|
2527
2345
|
sv.pnpmBuildDependency("@tailwindcss/oxide");
|
|
2528
2346
|
if (prettierInstalled) sv.devDependency("prettier-plugin-tailwindcss", "^0.7.2");
|
|
2529
2347
|
for (const plugin of plugins) {
|
|
@@ -2606,7 +2424,7 @@ var tailwindcss_default = defineAddon({
|
|
|
2606
2424
|
});
|
|
2607
2425
|
|
|
2608
2426
|
//#endregion
|
|
2609
|
-
//#region lib/addons/vitest-addon
|
|
2427
|
+
//#region lib/addons/vitest-addon.ts
|
|
2610
2428
|
const options$1 = defineAddonOptions().add("usages", {
|
|
2611
2429
|
question: "What do you want to use vitest for?",
|
|
2612
2430
|
type: "multiselect",
|
|
@@ -2630,16 +2448,16 @@ var vitest_addon_default = defineAddon({
|
|
|
2630
2448
|
const unitTesting = options$8.usages.includes("unit");
|
|
2631
2449
|
const componentTesting = options$8.usages.includes("component");
|
|
2632
2450
|
vitestV3Installed = (dependencyVersion("vitest") ?? "").replaceAll("^", "").replaceAll("~", "")?.startsWith("3.");
|
|
2633
|
-
sv.devDependency("vitest", "^4.0.
|
|
2451
|
+
sv.devDependency("vitest", "^4.0.18");
|
|
2634
2452
|
if (componentTesting) {
|
|
2635
|
-
sv.devDependency("@vitest/browser-playwright", "^4.0.
|
|
2636
|
-
sv.devDependency("vitest-browser-svelte", "^2.0.
|
|
2637
|
-
sv.devDependency("playwright", "^1.
|
|
2453
|
+
sv.devDependency("@vitest/browser-playwright", "^4.0.18");
|
|
2454
|
+
sv.devDependency("vitest-browser-svelte", "^2.0.2");
|
|
2455
|
+
sv.devDependency("playwright", "^1.58.1");
|
|
2638
2456
|
}
|
|
2639
2457
|
sv.file(files.package, (content) => {
|
|
2640
2458
|
const { data, generateCode } = parse$1.json(content);
|
|
2641
2459
|
packageScriptsUpsert(data, "test:unit", "vitest");
|
|
2642
|
-
packageScriptsUpsert(data, "test", "npm run test:unit -- --run");
|
|
2460
|
+
packageScriptsUpsert(data, "test", "npm run test:unit -- --run", { mode: "prepend" });
|
|
2643
2461
|
return generateCode();
|
|
2644
2462
|
});
|
|
2645
2463
|
if (unitTesting) sv.file(`src/demo.spec.${language}`, (content) => {
|
|
@@ -2754,7 +2572,7 @@ var vitest_addon_default = defineAddon({
|
|
|
2754
2572
|
});
|
|
2755
2573
|
|
|
2756
2574
|
//#endregion
|
|
2757
|
-
//#region lib/addons/
|
|
2575
|
+
//#region lib/addons/_engine/official.ts
|
|
2758
2576
|
const officialAddons$1 = {
|
|
2759
2577
|
prettier: prettier_default,
|
|
2760
2578
|
eslint: eslint_default,
|
|
@@ -2764,7 +2582,7 @@ const officialAddons$1 = {
|
|
|
2764
2582
|
sveltekitAdapter: sveltekit_adapter_default,
|
|
2765
2583
|
devtoolsJson: devtools_json_default,
|
|
2766
2584
|
drizzle: drizzle_default,
|
|
2767
|
-
|
|
2585
|
+
betterAuth: better_auth_default,
|
|
2768
2586
|
mdsvex: mdsvex_default,
|
|
2769
2587
|
paraglide: paraglide_default,
|
|
2770
2588
|
storybook: storybook_default,
|
|
@@ -3005,7 +2823,7 @@ async function createWorkspace({ cwd: cwd$1, packageManager, override }) {
|
|
|
3005
2823
|
const stylesheet = kit ? `${kit.routesDirectory}/layout.css` : "src/app.css";
|
|
3006
2824
|
return {
|
|
3007
2825
|
cwd: resolvedCwd,
|
|
3008
|
-
packageManager: packageManager ??
|
|
2826
|
+
packageManager: packageManager ?? await detectPackageManager(cwd$1),
|
|
3009
2827
|
language: typescript ? "ts" : "js",
|
|
3010
2828
|
files: {
|
|
3011
2829
|
viteConfig,
|
|
@@ -3037,7 +2855,9 @@ function findWorkspaceRoot(cwd$1) {
|
|
|
3037
2855
|
const { data } = getPackageJson(directory);
|
|
3038
2856
|
if (data.workspaces) return directory;
|
|
3039
2857
|
}
|
|
3040
|
-
|
|
2858
|
+
const parent = path.dirname(directory);
|
|
2859
|
+
if (directory.includes(".test-output") && !parent.includes(".test-output")) break;
|
|
2860
|
+
directory = parent;
|
|
3041
2861
|
}
|
|
3042
2862
|
return cwd$1;
|
|
3043
2863
|
}
|
|
@@ -3083,7 +2903,7 @@ function parseKitOptions(cwd$1) {
|
|
|
3083
2903
|
//#endregion
|
|
3084
2904
|
//#region package.json
|
|
3085
2905
|
var name = "sv";
|
|
3086
|
-
var version = "0.
|
|
2906
|
+
var version = "0.12.0";
|
|
3087
2907
|
|
|
3088
2908
|
//#endregion
|
|
3089
2909
|
//#region lib/cli/utils/errors.ts
|
|
@@ -3098,7 +2918,6 @@ var UnsupportedError = class extends Error {
|
|
|
3098
2918
|
|
|
3099
2919
|
//#endregion
|
|
3100
2920
|
//#region lib/cli/utils/common.ts
|
|
3101
|
-
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
3102
2921
|
const NO_PREFIX = "--no-";
|
|
3103
2922
|
let options = [];
|
|
3104
2923
|
function getLongFlag(flags) {
|
|
@@ -3129,37 +2948,33 @@ const helpConfig = {
|
|
|
3129
2948
|
if (options.some((o) => getLongFlag(o.flags) === noVariant)) return `--[no-]${longFlag.slice(2)}`;
|
|
3130
2949
|
return option.flags;
|
|
3131
2950
|
},
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
styleDescriptionText: (str) => import_picocolors.default.gray(str),
|
|
3135
|
-
styleOptionText: (str) => import_picocolors.default.white(str),
|
|
3136
|
-
styleArgumentText: (str) => import_picocolors.default.white(str),
|
|
3137
|
-
styleSubcommandText: (str) => import_picocolors.default.red(str)
|
|
2951
|
+
styleCommandText: (str) => color.success(str),
|
|
2952
|
+
styleDescriptionText: (str) => color.optional(str)
|
|
3138
2953
|
};
|
|
3139
2954
|
function formatDescription(arg) {
|
|
3140
2955
|
let output = arg.description;
|
|
3141
|
-
if (arg.defaultValue !== void 0 && String(arg.defaultValue)) output +=
|
|
3142
|
-
if (arg.argChoices !== void 0 && String(arg.argChoices)) output +=
|
|
2956
|
+
if (arg.defaultValue !== void 0 && String(arg.defaultValue)) output += color.dim(` (default: ${JSON.stringify(arg.defaultValue)})`);
|
|
2957
|
+
if (arg.argChoices !== void 0 && String(arg.argChoices)) output += color.dim(` (choices: ${arg.argChoices.join(", ")})`);
|
|
3143
2958
|
return output;
|
|
3144
2959
|
}
|
|
3145
2960
|
async function runCommand(action) {
|
|
3146
2961
|
try {
|
|
3147
|
-
|
|
2962
|
+
Nt(`Welcome to the Svelte CLI! ${color.optional(`(v${version})`)}`);
|
|
3148
2963
|
const minimumVersion = "18.3.0";
|
|
3149
|
-
if (isVersionUnsupportedBelow(process$1.versions.node, minimumVersion))
|
|
2964
|
+
if (isVersionUnsupportedBelow(process$1.versions.node, minimumVersion)) R.warn(`You are using Node.js ${color.error(process$1.versions.node)}, please upgrade to Node.js ${color.success(minimumVersion)} or higher.`);
|
|
3150
2965
|
await action();
|
|
3151
|
-
|
|
2966
|
+
Wt("You're all set!");
|
|
3152
2967
|
} catch (e) {
|
|
3153
2968
|
if (e instanceof UnsupportedError) {
|
|
3154
2969
|
const padding = getPadding(e.reasons.map((r) => r.id));
|
|
3155
|
-
const message = e.reasons.map((r) => ` ${r.id.padEnd(padding)} ${
|
|
3156
|
-
|
|
3157
|
-
|
|
2970
|
+
const message = e.reasons.map((r) => ` ${r.id.padEnd(padding)} ${color.error(r.reason)}`).join("\n");
|
|
2971
|
+
R.error(`${e.name}\n\n${message}`);
|
|
2972
|
+
R.message();
|
|
3158
2973
|
} else if (e instanceof Error) {
|
|
3159
|
-
|
|
3160
|
-
|
|
2974
|
+
R.error(e.stack ?? String(e));
|
|
2975
|
+
R.message();
|
|
3161
2976
|
}
|
|
3162
|
-
|
|
2977
|
+
Pt("Operation failed.");
|
|
3163
2978
|
}
|
|
3164
2979
|
}
|
|
3165
2980
|
function getPadding(lines) {
|
|
@@ -3190,7 +3005,8 @@ function buildAndLogArgs(agent, command, args, lastArgs = []) {
|
|
|
3190
3005
|
else allArgs.push("--install", agent);
|
|
3191
3006
|
const res = resolveCommand(agent ?? "npm", "execute", [...allArgs, ...lastArgs]);
|
|
3192
3007
|
const message = [res.command, ...res.args].join(" ");
|
|
3193
|
-
|
|
3008
|
+
R.message(color.optional(color.dim(`To skip prompts next time, run:`)));
|
|
3009
|
+
R.info(color.optional(message), { spacing: -1 });
|
|
3194
3010
|
return message;
|
|
3195
3011
|
}
|
|
3196
3012
|
function updateReadme(projectPath, command) {
|
|
@@ -3211,9 +3027,9 @@ ${command}\n\`\`\`
|
|
|
3211
3027
|
fs.writeFileSync(readmePath, content);
|
|
3212
3028
|
}
|
|
3213
3029
|
function errorAndExit(message) {
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3030
|
+
R.error(message);
|
|
3031
|
+
R.message();
|
|
3032
|
+
Pt("Operation failed.");
|
|
3217
3033
|
process$1.exit(1);
|
|
3218
3034
|
}
|
|
3219
3035
|
const normalizePosix = (dir) => {
|
|
@@ -3250,31 +3066,30 @@ const create = new Command("create").description("scaffolds a new SvelteKit proj
|
|
|
3250
3066
|
const cwd$1 = parse(ProjectPathSchema, projectPath);
|
|
3251
3067
|
const options$8 = parse(OptionsSchema$1, opts);
|
|
3252
3068
|
if (options$8.fromPlayground && !validatePlaygroundUrl(options$8.fromPlayground)) {
|
|
3253
|
-
console.error(
|
|
3069
|
+
console.error(color.error(`Error: Invalid playground URL: ${options$8.fromPlayground}`));
|
|
3254
3070
|
process$1.exit(1);
|
|
3255
3071
|
}
|
|
3256
3072
|
runCommand(async () => {
|
|
3257
3073
|
const { directory, addOnNextSteps, packageManager } = await createProject(cwd$1, options$8);
|
|
3258
|
-
const highlight = (str) => import_picocolors.default.bold(import_picocolors.default.cyan(str));
|
|
3259
3074
|
let i = 1;
|
|
3260
3075
|
const initialSteps = ["📁 Project steps", ""];
|
|
3261
3076
|
const relative = path.relative(process$1.cwd(), directory);
|
|
3262
|
-
const pm = packageManager ??
|
|
3077
|
+
const pm = packageManager ?? await detectPackageManager(directory);
|
|
3263
3078
|
if (relative !== "") {
|
|
3264
3079
|
const pathHasSpaces = relative.includes(" ");
|
|
3265
|
-
initialSteps.push(` ${i++}: ${
|
|
3080
|
+
initialSteps.push(` ${i++}: ${color.command(`cd ${pathHasSpaces ? `"${relative}"` : relative}`)}`);
|
|
3266
3081
|
}
|
|
3267
3082
|
if (!packageManager) {
|
|
3268
3083
|
const { args: args$1, command: command$1 } = resolveCommand(pm, "install", []);
|
|
3269
|
-
initialSteps.push(` ${i++}: ${
|
|
3084
|
+
initialSteps.push(` ${i++}: ${color.command(`${command$1} ${args$1.join(" ")}`)}`);
|
|
3270
3085
|
}
|
|
3271
3086
|
const { args, command } = resolveCommand(pm, "run", ["dev", "--open"]);
|
|
3272
3087
|
const pmRunCmd = `${command} ${args.join(" ")}`;
|
|
3273
3088
|
const steps = [
|
|
3274
3089
|
...initialSteps,
|
|
3275
|
-
` ${i++}: ${
|
|
3090
|
+
` ${i++}: ${color.command(pmRunCmd)}`,
|
|
3276
3091
|
"",
|
|
3277
|
-
`To close the dev server, hit ${
|
|
3092
|
+
`To close the dev server, hit ${color.command("Ctrl-C")}`
|
|
3278
3093
|
];
|
|
3279
3094
|
if (addOnNextSteps.length > 0) {
|
|
3280
3095
|
steps.push("", "🧩 Add-on steps", "");
|
|
@@ -3283,17 +3098,17 @@ const create = new Command("create").description("scaffolds a new SvelteKit proj
|
|
|
3283
3098
|
steps.push(` ${indented}`);
|
|
3284
3099
|
}
|
|
3285
3100
|
}
|
|
3286
|
-
steps.push("", `Stuck? Visit us at ${
|
|
3287
|
-
|
|
3101
|
+
steps.push("", `Stuck? Visit us at ${color.website("https://svelte.dev/chat")}`);
|
|
3102
|
+
kt(steps.join("\n"), "What's next?", { format: (line) => line });
|
|
3288
3103
|
});
|
|
3289
3104
|
}).showHelpAfterError(true);
|
|
3290
3105
|
async function createProject(cwd$1, options$8) {
|
|
3291
|
-
if (options$8.fromPlayground)
|
|
3292
|
-
const { directory, template, language } = await
|
|
3106
|
+
if (options$8.fromPlayground) R.warn("Svelte maintainers have not reviewed playgrounds for malicious code. Use at your discretion.");
|
|
3107
|
+
const { directory, template, language } = await Rt({
|
|
3293
3108
|
directory: () => {
|
|
3294
3109
|
const defaultPath = "./";
|
|
3295
3110
|
if (cwd$1) return Promise.resolve(normalizePosix(cwd$1));
|
|
3296
|
-
return
|
|
3111
|
+
return Qt({
|
|
3297
3112
|
message: "Where would you like your project to be created?",
|
|
3298
3113
|
placeholder: ` (hit Enter to use '${defaultPath}')`,
|
|
3299
3114
|
defaultValue: defaultPath
|
|
@@ -3303,12 +3118,12 @@ async function createProject(cwd$1, options$8) {
|
|
|
3303
3118
|
if (!options$8.dirCheck) return;
|
|
3304
3119
|
if (!fs.existsSync(directory$1)) return;
|
|
3305
3120
|
if (!fs.readdirSync(directory$1).some((file) => !file.startsWith(".git"))) return;
|
|
3306
|
-
const force = await
|
|
3121
|
+
const force = await Mt({
|
|
3307
3122
|
message: "Directory not empty. Continue?",
|
|
3308
3123
|
initialValue: false
|
|
3309
3124
|
});
|
|
3310
|
-
if (
|
|
3311
|
-
|
|
3125
|
+
if (Ct(force) || !force) {
|
|
3126
|
+
Pt("Exiting.");
|
|
3312
3127
|
process$1.exit(0);
|
|
3313
3128
|
}
|
|
3314
3129
|
},
|
|
@@ -3316,7 +3131,7 @@ async function createProject(cwd$1, options$8) {
|
|
|
3316
3131
|
if (options$8.template) return Promise.resolve(options$8.template);
|
|
3317
3132
|
if (options$8.fromPlayground) return Promise.resolve("minimal");
|
|
3318
3133
|
const availableTemplates = templates.filter((t) => t.name !== "addon");
|
|
3319
|
-
return
|
|
3134
|
+
return qt({
|
|
3320
3135
|
message: "Which template would you like?",
|
|
3321
3136
|
initialValue: "minimal",
|
|
3322
3137
|
options: availableTemplates.map((t) => ({
|
|
@@ -3329,7 +3144,7 @@ async function createProject(cwd$1, options$8) {
|
|
|
3329
3144
|
language: (o) => {
|
|
3330
3145
|
if (options$8.types) return Promise.resolve(options$8.types);
|
|
3331
3146
|
if (o.results.template === "addon") return Promise.resolve("none");
|
|
3332
|
-
return
|
|
3147
|
+
return qt({
|
|
3333
3148
|
message: "Add type checking with TypeScript?",
|
|
3334
3149
|
initialValue: "typescript",
|
|
3335
3150
|
options: [
|
|
@@ -3349,7 +3164,7 @@ async function createProject(cwd$1, options$8) {
|
|
|
3349
3164
|
});
|
|
3350
3165
|
}
|
|
3351
3166
|
}, { onCancel: () => {
|
|
3352
|
-
|
|
3167
|
+
Pt("Operation cancelled.");
|
|
3353
3168
|
process$1.exit(0);
|
|
3354
3169
|
} });
|
|
3355
3170
|
const projectPath = path.resolve(directory);
|
|
@@ -3389,12 +3204,12 @@ async function createProject(cwd$1, options$8) {
|
|
|
3389
3204
|
types: language
|
|
3390
3205
|
});
|
|
3391
3206
|
if (options$8.fromPlayground) await createProjectFromPlayground(options$8.fromPlayground, projectPath);
|
|
3392
|
-
|
|
3393
|
-
let addOnNextSteps = [];
|
|
3207
|
+
R.success("Project created");
|
|
3394
3208
|
let argsFormattedAddons = [];
|
|
3395
3209
|
let addOnFilesToFormat = [];
|
|
3210
|
+
let addOnSuccessfulAddons = [];
|
|
3396
3211
|
if (template !== "addon" && (options$8.addOns || options$8.add.length > 0)) {
|
|
3397
|
-
const {
|
|
3212
|
+
const { argsFormattedAddons: argsFormatted$1, filesToFormat, successfulAddons } = await runAddonsApply({
|
|
3398
3213
|
answers,
|
|
3399
3214
|
options: {
|
|
3400
3215
|
cwd: projectPath,
|
|
@@ -3410,7 +3225,7 @@ async function createProject(cwd$1, options$8) {
|
|
|
3410
3225
|
});
|
|
3411
3226
|
argsFormattedAddons = argsFormatted$1;
|
|
3412
3227
|
addOnFilesToFormat = filesToFormat;
|
|
3413
|
-
|
|
3228
|
+
addOnSuccessfulAddons = successfulAddons;
|
|
3414
3229
|
}
|
|
3415
3230
|
const packageManager = options$8.install === false ? null : options$8.install === true ? await packageManagerPrompt(projectPath) : options$8.install;
|
|
3416
3231
|
const argsFormatted = [];
|
|
@@ -3421,6 +3236,8 @@ async function createProject(cwd$1, options$8) {
|
|
|
3421
3236
|
if (argsFormattedAddons.length > 0) argsFormatted.push("--add", ...argsFormattedAddons);
|
|
3422
3237
|
const prompt = buildAndLogArgs(packageManager, "create", argsFormatted, [directory]);
|
|
3423
3238
|
updateReadme(directory, prompt);
|
|
3239
|
+
if (packageManager) workspace.packageManager = packageManager;
|
|
3240
|
+
const addOnNextSteps = getNextSteps(addOnSuccessfulAddons, workspace, answers);
|
|
3424
3241
|
await addPnpmBuildDependencies(projectPath, packageManager, ["esbuild"]);
|
|
3425
3242
|
if (packageManager) {
|
|
3426
3243
|
await installDependencies(packageManager, projectPath);
|
|
@@ -3443,14 +3260,14 @@ async function createProjectFromPlayground(url, cwd$1) {
|
|
|
3443
3260
|
}
|
|
3444
3261
|
async function confirmExternalDependencies(dependencies) {
|
|
3445
3262
|
if (dependencies.length === 0) return false;
|
|
3446
|
-
const dependencyList = dependencies.map(
|
|
3447
|
-
|
|
3448
|
-
const installDeps = await
|
|
3263
|
+
const dependencyList = dependencies.map(color.warning).join(", ");
|
|
3264
|
+
R.warn(`The following external dependencies were found in the playground:\n\n${dependencyList}`);
|
|
3265
|
+
const installDeps = await Mt({
|
|
3449
3266
|
message: "Do you want to install these external dependencies?",
|
|
3450
3267
|
initialValue: false
|
|
3451
3268
|
});
|
|
3452
|
-
if (
|
|
3453
|
-
|
|
3269
|
+
if (Ct(installDeps)) {
|
|
3270
|
+
Pt("Operation cancelled.");
|
|
3454
3271
|
process$1.exit(0);
|
|
3455
3272
|
}
|
|
3456
3273
|
return installDeps;
|
|
@@ -6381,7 +6198,7 @@ const add$1 = new Command("add").description("applies specified add-ons into a p
|
|
|
6381
6198
|
workspace,
|
|
6382
6199
|
fromCommand: "add"
|
|
6383
6200
|
});
|
|
6384
|
-
if (nextSteps.length > 0)
|
|
6201
|
+
if (nextSteps.length > 0) kt(nextSteps.join("\n"), "Next steps", { format: (line) => line });
|
|
6385
6202
|
});
|
|
6386
6203
|
});
|
|
6387
6204
|
/**
|
|
@@ -6477,18 +6294,18 @@ async function promptAddonQuestions({ options: options$8, loadedAddons, workspac
|
|
|
6477
6294
|
if (addons.length > 0) setupResults = setupAddons(addons, workspace);
|
|
6478
6295
|
if (addons.length === 0) {
|
|
6479
6296
|
const results = setupAddons(officialAddons.map((a) => createLoadedAddon(a)), workspace);
|
|
6480
|
-
const addonOptions$1 = officialAddons.filter(({ id }) => results[id].unsupported.length === 0).map(({ id, homepage, shortDescription }) => ({
|
|
6297
|
+
const addonOptions$1 = officialAddons.filter(({ id, hidden }) => results[id].unsupported.length === 0 && !hidden).map(({ id, homepage, shortDescription }) => ({
|
|
6481
6298
|
label: id,
|
|
6482
6299
|
value: id,
|
|
6483
6300
|
hint: `${shortDescription} - ${homepage}`
|
|
6484
6301
|
}));
|
|
6485
|
-
const selected = await
|
|
6486
|
-
message: `What would you like to add to your project? ${
|
|
6302
|
+
const selected = await Lt({
|
|
6303
|
+
message: `What would you like to add to your project? ${color.dim("(use arrow keys / space bar)")}`,
|
|
6487
6304
|
options: addonOptions$1,
|
|
6488
6305
|
required: false
|
|
6489
6306
|
});
|
|
6490
|
-
if (
|
|
6491
|
-
|
|
6307
|
+
if (Ct(selected)) {
|
|
6308
|
+
Pt("Operation cancelled.");
|
|
6492
6309
|
process$1.exit(1);
|
|
6493
6310
|
}
|
|
6494
6311
|
for (const id of selected) {
|
|
@@ -6534,8 +6351,8 @@ async function promptAddonQuestions({ options: options$8, loadedAddons, workspac
|
|
|
6534
6351
|
answers[depId] = {};
|
|
6535
6352
|
continue;
|
|
6536
6353
|
}
|
|
6537
|
-
if (await
|
|
6538
|
-
|
|
6354
|
+
if (await Mt({ message: `The ${color.addon(addonId)} add-on requires ${color.addon(depId)} to also be setup. ${color.success("Include it?")}` }) !== true) {
|
|
6355
|
+
Pt("Operation cancelled.");
|
|
6539
6356
|
process$1.exit(1);
|
|
6540
6357
|
}
|
|
6541
6358
|
answers[depId] = {};
|
|
@@ -6558,14 +6375,14 @@ async function promptAddonQuestions({ options: options$8, loadedAddons, workspac
|
|
|
6558
6375
|
});
|
|
6559
6376
|
}
|
|
6560
6377
|
if (fails.length > 0) {
|
|
6561
|
-
const message = fails.map(({ name: name$1, message: message$1 }) =>
|
|
6562
|
-
|
|
6563
|
-
const force = await
|
|
6378
|
+
const message = fails.map(({ name: name$1, message: message$1 }) => color.warning(`${name$1} (${message$1})`)).join("\n- ");
|
|
6379
|
+
kt(`- ${message}`, "Verifications not met", { format: (line) => line });
|
|
6380
|
+
const force = await Mt({
|
|
6564
6381
|
message: "Verifications failed. Do you wish to continue?",
|
|
6565
6382
|
initialValue: false
|
|
6566
6383
|
});
|
|
6567
|
-
if (
|
|
6568
|
-
|
|
6384
|
+
if (Ct(force) || !force) {
|
|
6385
|
+
Pt("Operation cancelled.");
|
|
6569
6386
|
process$1.exit(1);
|
|
6570
6387
|
}
|
|
6571
6388
|
}
|
|
@@ -6579,23 +6396,23 @@ async function promptAddonQuestions({ options: options$8, loadedAddons, workspac
|
|
|
6579
6396
|
if (question.condition?.(values) === false || values[questionId] !== void 0) continue;
|
|
6580
6397
|
let answer;
|
|
6581
6398
|
const message = questionPrefix + question.question;
|
|
6582
|
-
if (question.type === "boolean") answer = await
|
|
6399
|
+
if (question.type === "boolean") answer = await Mt({
|
|
6583
6400
|
message,
|
|
6584
6401
|
initialValue: question.default
|
|
6585
6402
|
});
|
|
6586
|
-
if (question.type === "select") answer = await
|
|
6403
|
+
if (question.type === "select") answer = await qt({
|
|
6587
6404
|
message,
|
|
6588
6405
|
initialValue: question.default,
|
|
6589
6406
|
options: question.options
|
|
6590
6407
|
});
|
|
6591
|
-
if (question.type === "multiselect") answer = await
|
|
6408
|
+
if (question.type === "multiselect") answer = await Lt({
|
|
6592
6409
|
message,
|
|
6593
6410
|
initialValues: question.default,
|
|
6594
6411
|
required: question.required,
|
|
6595
6412
|
options: question.options
|
|
6596
6413
|
});
|
|
6597
6414
|
if (question.type === "string" || question.type === "number") {
|
|
6598
|
-
answer = await
|
|
6415
|
+
answer = await Qt({
|
|
6599
6416
|
message,
|
|
6600
6417
|
initialValue: question.default?.toString() ?? (question.type === "number" ? "0" : ""),
|
|
6601
6418
|
placeholder: question.placeholder,
|
|
@@ -6603,8 +6420,8 @@ async function promptAddonQuestions({ options: options$8, loadedAddons, workspac
|
|
|
6603
6420
|
});
|
|
6604
6421
|
if (question.type === "number") answer = Number(answer);
|
|
6605
6422
|
}
|
|
6606
|
-
if (
|
|
6607
|
-
|
|
6423
|
+
if (Ct(answer)) {
|
|
6424
|
+
Pt("Operation cancelled.");
|
|
6608
6425
|
process$1.exit(1);
|
|
6609
6426
|
}
|
|
6610
6427
|
values[questionId] = answer;
|
|
@@ -6620,7 +6437,8 @@ async function runAddonsApply({ answers, options: options$8, loadedAddons, setup
|
|
|
6620
6437
|
if (loadedAddons.length === 0) return {
|
|
6621
6438
|
nextSteps: [],
|
|
6622
6439
|
argsFormattedAddons: [],
|
|
6623
|
-
filesToFormat: []
|
|
6440
|
+
filesToFormat: [],
|
|
6441
|
+
successfulAddons: []
|
|
6624
6442
|
};
|
|
6625
6443
|
const { filesToFormat, pnpmBuildDependencies, status } = await applyAddons({
|
|
6626
6444
|
loadedAddons,
|
|
@@ -6632,14 +6450,14 @@ async function runAddonsApply({ answers, options: options$8, loadedAddons, setup
|
|
|
6632
6450
|
const canceledAddonIds = [];
|
|
6633
6451
|
for (const [addonId, info] of Object.entries(status)) if (info === "success") addonSuccess.push(addonId);
|
|
6634
6452
|
else {
|
|
6635
|
-
|
|
6453
|
+
R.warn(`Canceled ${addonId}: ${info.join(", ")}`);
|
|
6636
6454
|
canceledAddonIds.push(addonId);
|
|
6637
6455
|
}
|
|
6638
6456
|
const successfulAddons = loadedAddons.filter((a) => !canceledAddonIds.includes(a.addon.id));
|
|
6639
6457
|
if (addonSuccess.length === 0) {
|
|
6640
|
-
|
|
6458
|
+
Pt("All selected add-ons were canceled.");
|
|
6641
6459
|
process$1.exit(1);
|
|
6642
|
-
} else
|
|
6460
|
+
} else R.success(`Successfully setup add-ons: ${addonSuccess.map((c) => color.addon(c)).join(", ")}`);
|
|
6643
6461
|
const packageManager = options$8.install === false ? null : options$8.install === true ? await packageManagerPrompt(options$8.cwd) : options$8.install;
|
|
6644
6462
|
await addPnpmBuildDependencies(workspace.cwd, packageManager, ["esbuild", ...pnpmBuildDependencies]);
|
|
6645
6463
|
const argsFormattedAddons = [];
|
|
@@ -6681,23 +6499,27 @@ async function runAddonsApply({ answers, options: options$8, loadedAddons, setup
|
|
|
6681
6499
|
});
|
|
6682
6500
|
}
|
|
6683
6501
|
return {
|
|
6684
|
-
nextSteps: successfulAddons
|
|
6685
|
-
const addon = loaded.addon;
|
|
6686
|
-
if (!addon.nextSteps) return;
|
|
6687
|
-
const addonOptions$1 = answers[addon.id];
|
|
6688
|
-
const addonNextSteps = addon.nextSteps({
|
|
6689
|
-
...workspace,
|
|
6690
|
-
options: addonOptions$1
|
|
6691
|
-
});
|
|
6692
|
-
if (addonNextSteps.length === 0) return;
|
|
6693
|
-
let addonMessage = `${import_picocolors.default.green(addon.id)}:\n`;
|
|
6694
|
-
addonMessage += ` - ${addonNextSteps.join("\n - ")}`;
|
|
6695
|
-
return addonMessage;
|
|
6696
|
-
}).filter((msg) => msg !== void 0),
|
|
6502
|
+
nextSteps: getNextSteps(successfulAddons, workspace, answers),
|
|
6697
6503
|
argsFormattedAddons,
|
|
6698
|
-
filesToFormat
|
|
6504
|
+
filesToFormat,
|
|
6505
|
+
successfulAddons
|
|
6699
6506
|
};
|
|
6700
6507
|
}
|
|
6508
|
+
function getNextSteps(loadedAddons, workspace, answers) {
|
|
6509
|
+
return loadedAddons.map((loaded) => {
|
|
6510
|
+
const addon = loaded.addon;
|
|
6511
|
+
if (!addon.nextSteps) return;
|
|
6512
|
+
const addonOptions$1 = answers[addon.id];
|
|
6513
|
+
const addonNextSteps = addon.nextSteps({
|
|
6514
|
+
...workspace,
|
|
6515
|
+
options: addonOptions$1
|
|
6516
|
+
});
|
|
6517
|
+
if (addonNextSteps.length === 0) return;
|
|
6518
|
+
let addonMessage = `${color.addon(addon.id)}:\n`;
|
|
6519
|
+
addonMessage += ` - ${addonNextSteps.join("\n - ")}`;
|
|
6520
|
+
return addonMessage;
|
|
6521
|
+
}).filter((msg) => msg !== void 0);
|
|
6522
|
+
}
|
|
6701
6523
|
/**
|
|
6702
6524
|
* Handles passed add-on arguments, accumulating them into an array of AddonInput.
|
|
6703
6525
|
*/
|
|
@@ -6724,7 +6546,7 @@ function getAddonOptionFlags() {
|
|
|
6724
6546
|
const details = getAddonDetails(id);
|
|
6725
6547
|
if (Object.values(details.options).length === 0) continue;
|
|
6726
6548
|
const { defaults, groups } = getOptionChoices(details);
|
|
6727
|
-
const choices = Object.entries(groups).map(([group, choices$1]) => `${
|
|
6549
|
+
const choices = Object.entries(groups).map(([group, choices$1]) => `${color.optional(`${group}:`)} ${color.dim(choices$1.join(", "))}`).join("\n");
|
|
6728
6550
|
const preset = defaults.join(", ") || "none";
|
|
6729
6551
|
options$8.push({
|
|
6730
6552
|
id,
|
|
@@ -6783,7 +6605,7 @@ function getOptionChoices(details) {
|
|
|
6783
6605
|
}
|
|
6784
6606
|
async function resolveNonOfficialAddons(refs, downloadCheck) {
|
|
6785
6607
|
const selectedAddons = [];
|
|
6786
|
-
const { start, stop } =
|
|
6608
|
+
const { start, stop } = Ie();
|
|
6787
6609
|
try {
|
|
6788
6610
|
start(`Resolving ${refs.map((r) => color.addon(r.specifier)).join(", ")} packages`);
|
|
6789
6611
|
const pkgs = await Promise.all(refs.map(async (ref) => {
|
|
@@ -6791,17 +6613,17 @@ async function resolveNonOfficialAddons(refs, downloadCheck) {
|
|
|
6791
6613
|
return await getPackageJSON(ref);
|
|
6792
6614
|
}));
|
|
6793
6615
|
stop("Resolved community add-on packages");
|
|
6794
|
-
for (const { warning } of pkgs) if (warning)
|
|
6795
|
-
|
|
6616
|
+
for (const { warning } of pkgs) if (warning) R.warn(warning);
|
|
6617
|
+
R.warn("Svelte maintainers have not reviewed community add-ons for malicious code. Use at your discretion.");
|
|
6796
6618
|
const paddingName = getPadding(pkgs.map(({ pkg }) => pkg.name));
|
|
6797
6619
|
const paddingVersion = getPadding(pkgs.map(({ pkg }) => `(v${pkg.version})`));
|
|
6798
6620
|
const packageInfos = pkgs.map(({ pkg, repo: _repo }) => {
|
|
6799
|
-
return `${
|
|
6621
|
+
return `${color.warning(pkg.name.padEnd(paddingName))} ${color.dim(`(v${pkg.version})`.padEnd(paddingVersion))} ${color.dim(`(${_repo})`)}`;
|
|
6800
6622
|
});
|
|
6801
|
-
|
|
6623
|
+
R.message(packageInfos.join("\n"));
|
|
6802
6624
|
if (downloadCheck) {
|
|
6803
|
-
if (await
|
|
6804
|
-
|
|
6625
|
+
if (await Mt({ message: "Would you like to continue?" }) !== true) {
|
|
6626
|
+
Pt("Operation cancelled.");
|
|
6805
6627
|
process$1.exit(1);
|
|
6806
6628
|
}
|
|
6807
6629
|
}
|
|
@@ -6824,7 +6646,7 @@ async function resolveNonOfficialAddons(refs, downloadCheck) {
|
|
|
6824
6646
|
}
|
|
6825
6647
|
stop("Downloaded community add-on packages");
|
|
6826
6648
|
} catch (err) {
|
|
6827
|
-
stop("Failed to download community add-on packages"
|
|
6649
|
+
stop("Failed to download community add-on packages");
|
|
6828
6650
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
6829
6651
|
errorAndExit(msg);
|
|
6830
6652
|
}
|
|
@@ -6836,7 +6658,7 @@ async function resolveNonOfficialAddons(refs, downloadCheck) {
|
|
|
6836
6658
|
const TESTING = process$1.env.NODE_ENV?.toLowerCase() === "test";
|
|
6837
6659
|
|
|
6838
6660
|
//#endregion
|
|
6839
|
-
//#region lib/addons/add.ts
|
|
6661
|
+
//#region lib/addons/_engine/add.ts
|
|
6840
6662
|
async function add({ addons, cwd: cwd$1, options: options$8, packageManager = "npm" }) {
|
|
6841
6663
|
const workspace = await createWorkspace({
|
|
6842
6664
|
cwd: cwd$1,
|
|
@@ -6933,7 +6755,7 @@ async function runAddon({ addon, loaded, multiple, workspace, workspaceOptions }
|
|
|
6933
6755
|
const { command, args } = resolveCommand(workspace.packageManager, "execute", commandArgs);
|
|
6934
6756
|
const addonPrefix = multiple ? `${addon.id}: ` : "";
|
|
6935
6757
|
const executedCommand = `${command} ${args.join(" ")}`;
|
|
6936
|
-
if (!TESTING)
|
|
6758
|
+
if (!TESTING) R.step(`${addonPrefix}Running external command ${color.optional(`(${executedCommand})`)}`);
|
|
6937
6759
|
if (workspace.packageManager === "npm") args.unshift("--yes");
|
|
6938
6760
|
try {
|
|
6939
6761
|
await q(command, args, {
|