sv 0.11.4 → 0.12.1
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-BVmpqSBJ.mjs → add-D8995Wsf.mjs} +548 -718
- package/dist/{add-CX9qz1SZ.d.mts → add-DbK6niIm.d.mts} +6 -3
- package/dist/bin.mjs +17 -14
- package/dist/{chunk-BjMGrMj9.mjs → chunk-BcJDCUAU.mjs} +2 -2
- package/dist/{core-BLHPg_eo.d.mts → core-DjIj3YV4.d.mts} +37 -9
- package/dist/lib/core.d.mts +2 -2
- package/dist/lib/core.mjs +2 -2
- package/dist/lib/index.d.mts +2 -2
- package/dist/lib/index.mjs +3 -3
- package/dist/lib/testing.d.mts +3 -2
- package/dist/lib/testing.mjs +3 -3
- package/dist/{package-manager-XDkWi9-7.mjs → package-manager-DYfxv5nk.mjs} +21 -11
- package/dist/shared.json +2 -2
- package/dist/templates/addon/package.json +2 -2
- package/dist/templates/demo/package.json +2 -2
- package/dist/templates/library/package.json +2 -2
- package/dist/templates/minimal/package.json +2 -2
- package/dist/{utils-IP07VUBl.mjs → utils-CnfD6Z1s.mjs} +837 -1693
- package/package.json +2 -2
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { r as __require, t as __commonJSMin } from "./chunk-
|
|
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";
|
|
@@ -609,6 +610,430 @@ function pipe(...pipe$1) {
|
|
|
609
610
|
};
|
|
610
611
|
}
|
|
611
612
|
|
|
613
|
+
//#endregion
|
|
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
|
+
|
|
612
1037
|
//#endregion
|
|
613
1038
|
//#region lib/addons/devtools-json.ts
|
|
614
1039
|
var devtools_json_default = defineAddon({
|
|
@@ -638,7 +1063,7 @@ const PORTS = {
|
|
|
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");
|
|
@@ -735,7 +1160,7 @@ var drizzle_default = defineAddon({
|
|
|
735
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.16.
|
|
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
1166
|
if (options$8.postgresql === "postgres.js") sv.dependency("postgres", "^3.4.8");
|
|
@@ -745,8 +1170,8 @@ var drizzle_default = defineAddon({
|
|
|
745
1170
|
sv.pnpmBuildDependency("better-sqlite3");
|
|
746
1171
|
}
|
|
747
1172
|
if (options$8.sqlite === "libsql" || options$8.sqlite === "turso") sv.devDependency("@libsql/client", "^0.17.0");
|
|
748
|
-
sv.file(".env", (content) => generateEnvFileContent(content, options$8));
|
|
749
|
-
sv.file(".env.example", (content) => generateEnvFileContent(content, options$8));
|
|
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,42 +1433,40 @@ 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
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
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") if (isExample) {
|
|
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 {
|
|
1452
|
+
value = "\"file:local.db\"";
|
|
1453
|
+
comment.push("Replace with your DB credentials!", `${DB_URL_KEY}="libsql://db-name-user.turso.io"`, "A local DB can also be used in dev as well");
|
|
1454
|
+
}
|
|
1455
|
+
else if (opts.database === "mysql") {
|
|
1456
|
+
value = "\"mysql://user:password@host:port/db-name\"";
|
|
1457
|
+
comment.push("Replace with your DB credentials!");
|
|
1458
|
+
} else if (opts.database === "postgresql") {
|
|
1459
|
+
value = "\"postgres://user:password@host:port/db-name\"";
|
|
1460
|
+
comment.push("Replace with your DB credentials!");
|
|
1461
|
+
} else value = "";
|
|
1462
|
+
content = upsert(content, DB_URL_KEY, {
|
|
1463
|
+
value,
|
|
1464
|
+
comment,
|
|
1465
|
+
separator: true
|
|
1466
|
+
});
|
|
1467
|
+
if (opts.sqlite === "turso") content = upsert(content, "DATABASE_AUTH_TOKEN", { value: isExample ? `""` : `"${crypto.randomUUID()}"` });
|
|
1044
1468
|
return content;
|
|
1045
1469
|
}
|
|
1046
|
-
function appendEnvContent(existing, content) {
|
|
1047
|
-
return (!existing.length || existing.endsWith("\n") ? existing : existing + "\n") + content + "\n";
|
|
1048
|
-
}
|
|
1049
1470
|
|
|
1050
1471
|
//#endregion
|
|
1051
1472
|
//#region lib/addons/eslint.ts
|
|
@@ -1058,12 +1479,12 @@ var eslint_default = defineAddon({
|
|
|
1058
1479
|
const typescript = language === "ts";
|
|
1059
1480
|
const prettierInstalled = Boolean(dependencyVersion("prettier"));
|
|
1060
1481
|
sv.devDependency("eslint", "^9.39.2");
|
|
1061
|
-
sv.devDependency("@eslint/compat", "^2.0.
|
|
1482
|
+
sv.devDependency("@eslint/compat", "^2.0.2");
|
|
1062
1483
|
sv.devDependency("eslint-plugin-svelte", "^3.14.0");
|
|
1063
|
-
sv.devDependency("globals", "^17.
|
|
1484
|
+
sv.devDependency("globals", "^17.3.0");
|
|
1064
1485
|
sv.devDependency("@eslint/js", "^9.39.2");
|
|
1065
1486
|
sv.devDependency("@types/node", getNodeTypesVersion());
|
|
1066
|
-
if (typescript) sv.devDependency("typescript-eslint", "^8.
|
|
1487
|
+
if (typescript) sv.devDependency("typescript-eslint", "^8.54.0");
|
|
1067
1488
|
if (prettierInstalled) sv.devDependency("eslint-config-prettier", "^10.1.8");
|
|
1068
1489
|
sv.file(files.package, (content) => {
|
|
1069
1490
|
const { data, generateCode } = parse$1.json(content);
|
|
@@ -1183,606 +1604,6 @@ var eslint_default = defineAddon({
|
|
|
1183
1604
|
}
|
|
1184
1605
|
});
|
|
1185
1606
|
|
|
1186
|
-
//#endregion
|
|
1187
|
-
//#region lib/addons/lucia.ts
|
|
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
|
-
R.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
|
-
R.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
|
-
R.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
|
-
R.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
1607
|
//#endregion
|
|
1787
1608
|
//#region lib/addons/mcp.ts
|
|
1788
1609
|
const options$5 = defineAddonOptions().add("ide", {
|
|
@@ -2007,7 +1828,7 @@ var paraglide_default = defineAddon({
|
|
|
2007
1828
|
run: ({ sv, options: options$8, files, language, kit }) => {
|
|
2008
1829
|
if (!kit) throw new Error("SvelteKit is required");
|
|
2009
1830
|
const paraglideOutDir = "src/lib/paraglide";
|
|
2010
|
-
sv.devDependency("@inlang/paraglide-js", "^2.
|
|
1831
|
+
sv.devDependency("@inlang/paraglide-js", "^2.10.0");
|
|
2011
1832
|
sv.file(files.viteConfig, (content) => {
|
|
2012
1833
|
const { ast, generateCode } = parse$1.script(content);
|
|
2013
1834
|
const vitePluginName = "paraglideVitePlugin";
|
|
@@ -2040,7 +1861,7 @@ var paraglide_default = defineAddon({
|
|
|
2040
1861
|
return generateCode();
|
|
2041
1862
|
});
|
|
2042
1863
|
sv.file(`src/hooks.server.${language}`, (content) => {
|
|
2043
|
-
const { ast, generateCode } = parse$1.script(content);
|
|
1864
|
+
const { ast, generateCode, comments } = parse$1.script(content);
|
|
2044
1865
|
addNamed(ast, {
|
|
2045
1866
|
from: "$lib/paraglide/server",
|
|
2046
1867
|
imports: ["paraglideMiddleware"]
|
|
@@ -2053,7 +1874,8 @@ var paraglide_default = defineAddon({
|
|
|
2053
1874
|
return resolve(event, {
|
|
2054
1875
|
transformPageChunk: ({ html }) => html.replace('%paraglide.lang%', locale)
|
|
2055
1876
|
});
|
|
2056
|
-
})
|
|
1877
|
+
});`,
|
|
1878
|
+
comments
|
|
2057
1879
|
});
|
|
2058
1880
|
return generateCode();
|
|
2059
1881
|
});
|
|
@@ -2069,7 +1891,8 @@ var paraglide_default = defineAddon({
|
|
|
2069
1891
|
});
|
|
2070
1892
|
sv.file(files.gitignore, (content) => {
|
|
2071
1893
|
if (!content) return content;
|
|
2072
|
-
|
|
1894
|
+
content = upsert(content, paraglideOutDir, { comment: "Paraglide" });
|
|
1895
|
+
content = upsert(content, "project.inlang/cache/");
|
|
2073
1896
|
return content;
|
|
2074
1897
|
});
|
|
2075
1898
|
sv.file("project.inlang/settings.json", (content) => {
|
|
@@ -2158,7 +1981,7 @@ var playwright_default = defineAddon({
|
|
|
2158
1981
|
homepage: "https://playwright.dev",
|
|
2159
1982
|
options: {},
|
|
2160
1983
|
run: ({ sv, language, files }) => {
|
|
2161
|
-
sv.devDependency("@playwright/test", "^1.58.
|
|
1984
|
+
sv.devDependency("@playwright/test", "^1.58.1");
|
|
2162
1985
|
sv.file(files.package, (content) => {
|
|
2163
1986
|
const { data, generateCode } = parse$1.json(content);
|
|
2164
1987
|
packageScriptsUpsert(data, "test:e2e", "playwright test");
|
|
@@ -2167,8 +1990,7 @@ var playwright_default = defineAddon({
|
|
|
2167
1990
|
});
|
|
2168
1991
|
sv.file(files.gitignore, (content) => {
|
|
2169
1992
|
if (!content) return content;
|
|
2170
|
-
|
|
2171
|
-
return "test-results\n" + content.trim();
|
|
1993
|
+
return upsert(content, "test-results", { comment: "Playwright" });
|
|
2172
1994
|
});
|
|
2173
1995
|
sv.file(`e2e/demo.test.${language}`, (content) => {
|
|
2174
1996
|
if (content) return content;
|
|
@@ -2409,7 +2231,7 @@ var sveltekit_adapter_default = defineAddon({
|
|
|
2409
2231
|
return generateCode();
|
|
2410
2232
|
});
|
|
2411
2233
|
if (adapter.package === "@sveltejs/adapter-cloudflare") {
|
|
2412
|
-
sv.devDependency("wrangler", "^4.
|
|
2234
|
+
sv.devDependency("wrangler", "^4.63.0");
|
|
2413
2235
|
const configFormat = fileExists(cwd$1, "wrangler.toml") ? "toml" : "jsonc";
|
|
2414
2236
|
sv.file(`wrangler.${configFormat}`, (content) => {
|
|
2415
2237
|
const { data, generateCode } = configFormat === "jsonc" ? parse$1.json(content) : parse$1.toml(content);
|
|
@@ -2436,7 +2258,8 @@ var sveltekit_adapter_default = defineAddon({
|
|
|
2436
2258
|
const jsconfig = fileExists(cwd$1, "jsconfig.json");
|
|
2437
2259
|
if (language === "ts" || jsconfig) {
|
|
2438
2260
|
sv.file(files.gitignore, (content) => {
|
|
2439
|
-
|
|
2261
|
+
if (content.length === 0) return content;
|
|
2262
|
+
return upsert(content, "/worker-configuration.d.ts", { comment: "Cloudflare Types" });
|
|
2440
2263
|
});
|
|
2441
2264
|
sv.file(files.package, (content) => {
|
|
2442
2265
|
const { data, generateCode } = parse$1.json(content);
|
|
@@ -2633,7 +2456,7 @@ var vitest_addon_default = defineAddon({
|
|
|
2633
2456
|
if (componentTesting) {
|
|
2634
2457
|
sv.devDependency("@vitest/browser-playwright", "^4.0.18");
|
|
2635
2458
|
sv.devDependency("vitest-browser-svelte", "^2.0.2");
|
|
2636
|
-
sv.devDependency("playwright", "^1.58.
|
|
2459
|
+
sv.devDependency("playwright", "^1.58.1");
|
|
2637
2460
|
}
|
|
2638
2461
|
sv.file(files.package, (content) => {
|
|
2639
2462
|
const { data, generateCode } = parse$1.json(content);
|
|
@@ -2763,7 +2586,7 @@ const officialAddons$1 = {
|
|
|
2763
2586
|
sveltekitAdapter: sveltekit_adapter_default,
|
|
2764
2587
|
devtoolsJson: devtools_json_default,
|
|
2765
2588
|
drizzle: drizzle_default,
|
|
2766
|
-
|
|
2589
|
+
betterAuth: better_auth_default,
|
|
2767
2590
|
mdsvex: mdsvex_default,
|
|
2768
2591
|
paraglide: paraglide_default,
|
|
2769
2592
|
storybook: storybook_default,
|
|
@@ -3000,11 +2823,11 @@ async function createWorkspace({ cwd: cwd$1, packageManager, override }) {
|
|
|
3000
2823
|
}
|
|
3001
2824
|
}
|
|
3002
2825
|
for (const [key, value] of Object.entries(dependencies)) dependencies[key] = value.replaceAll(/[^\d|.]/g, "");
|
|
3003
|
-
const kit = override?.kit ? override.kit : dependencies["@sveltejs/kit"] ? parseKitOptions(resolvedCwd) : void 0;
|
|
2826
|
+
const kit = override?.kit ? override.kit : dependencies["@sveltejs/kit"] ? parseKitOptions(resolvedCwd, svelteConfig) : void 0;
|
|
3004
2827
|
const stylesheet = kit ? `${kit.routesDirectory}/layout.css` : "src/app.css";
|
|
3005
2828
|
return {
|
|
3006
2829
|
cwd: resolvedCwd,
|
|
3007
|
-
packageManager: packageManager ??
|
|
2830
|
+
packageManager: packageManager ?? await detectPackageManager(cwd$1),
|
|
3008
2831
|
language: typescript ? "ts" : "js",
|
|
3009
2832
|
files: {
|
|
3010
2833
|
viteConfig,
|
|
@@ -3042,11 +2865,11 @@ function findWorkspaceRoot(cwd$1) {
|
|
|
3042
2865
|
}
|
|
3043
2866
|
return cwd$1;
|
|
3044
2867
|
}
|
|
3045
|
-
function parseKitOptions(cwd$1) {
|
|
3046
|
-
const configSource = readFile(cwd$1,
|
|
2868
|
+
function parseKitOptions(cwd$1, svelteConfigPath) {
|
|
2869
|
+
const configSource = readFile(cwd$1, svelteConfigPath);
|
|
3047
2870
|
const { ast } = parse$1.script(configSource);
|
|
3048
2871
|
const defaultExport = ast.body.find((s) => s.type === "ExportDefaultDeclaration");
|
|
3049
|
-
if (!defaultExport) throw Error(`Missing default export in \`${
|
|
2872
|
+
if (!defaultExport) throw Error(`Missing default export in \`${svelteConfigPath}\``);
|
|
3050
2873
|
let objectExpression;
|
|
3051
2874
|
if (defaultExport.declaration.type === "Identifier") {
|
|
3052
2875
|
const identifier = defaultExport.declaration;
|
|
@@ -3056,9 +2879,9 @@ function parseKitOptions(cwd$1) {
|
|
|
3056
2879
|
if (declarator?.init?.type !== "ObjectExpression") continue;
|
|
3057
2880
|
objectExpression = declarator.init;
|
|
3058
2881
|
}
|
|
3059
|
-
if (!objectExpression) throw Error(`Unable to find svelte config object expression from \`${
|
|
2882
|
+
if (!objectExpression) throw Error(`Unable to find svelte config object expression from \`${svelteConfigPath}\``);
|
|
3060
2883
|
} else if (defaultExport.declaration.type === "ObjectExpression") objectExpression = defaultExport.declaration;
|
|
3061
|
-
if (!objectExpression) throw new Error(`Unexpected svelte config shape from \`${
|
|
2884
|
+
if (!objectExpression) throw new Error(`Unexpected svelte config shape from \`${svelteConfigPath}\``);
|
|
3062
2885
|
const kit = property(objectExpression, {
|
|
3063
2886
|
name: "kit",
|
|
3064
2887
|
fallback: create$2({})
|
|
@@ -3084,7 +2907,7 @@ function parseKitOptions(cwd$1) {
|
|
|
3084
2907
|
//#endregion
|
|
3085
2908
|
//#region package.json
|
|
3086
2909
|
var name = "sv";
|
|
3087
|
-
var version = "0.
|
|
2910
|
+
var version = "0.12.1";
|
|
3088
2911
|
|
|
3089
2912
|
//#endregion
|
|
3090
2913
|
//#region lib/cli/utils/errors.ts
|
|
@@ -3255,7 +3078,7 @@ const create = new Command("create").description("scaffolds a new SvelteKit proj
|
|
|
3255
3078
|
let i = 1;
|
|
3256
3079
|
const initialSteps = ["📁 Project steps", ""];
|
|
3257
3080
|
const relative = path.relative(process$1.cwd(), directory);
|
|
3258
|
-
const pm = packageManager ??
|
|
3081
|
+
const pm = packageManager ?? await detectPackageManager(directory);
|
|
3259
3082
|
if (relative !== "") {
|
|
3260
3083
|
const pathHasSpaces = relative.includes(" ");
|
|
3261
3084
|
initialSteps.push(` ${i++}: ${color.command(`cd ${pathHasSpaces ? `"${relative}"` : relative}`)}`);
|
|
@@ -3386,11 +3209,11 @@ async function createProject(cwd$1, options$8) {
|
|
|
3386
3209
|
});
|
|
3387
3210
|
if (options$8.fromPlayground) await createProjectFromPlayground(options$8.fromPlayground, projectPath);
|
|
3388
3211
|
R.success("Project created");
|
|
3389
|
-
let addOnNextSteps = [];
|
|
3390
3212
|
let argsFormattedAddons = [];
|
|
3391
3213
|
let addOnFilesToFormat = [];
|
|
3214
|
+
let addOnSuccessfulAddons = [];
|
|
3392
3215
|
if (template !== "addon" && (options$8.addOns || options$8.add.length > 0)) {
|
|
3393
|
-
const {
|
|
3216
|
+
const { argsFormattedAddons: argsFormatted$1, filesToFormat, successfulAddons } = await runAddonsApply({
|
|
3394
3217
|
answers,
|
|
3395
3218
|
options: {
|
|
3396
3219
|
cwd: projectPath,
|
|
@@ -3406,7 +3229,7 @@ async function createProject(cwd$1, options$8) {
|
|
|
3406
3229
|
});
|
|
3407
3230
|
argsFormattedAddons = argsFormatted$1;
|
|
3408
3231
|
addOnFilesToFormat = filesToFormat;
|
|
3409
|
-
|
|
3232
|
+
addOnSuccessfulAddons = successfulAddons;
|
|
3410
3233
|
}
|
|
3411
3234
|
const packageManager = options$8.install === false ? null : options$8.install === true ? await packageManagerPrompt(projectPath) : options$8.install;
|
|
3412
3235
|
const argsFormatted = [];
|
|
@@ -3417,6 +3240,8 @@ async function createProject(cwd$1, options$8) {
|
|
|
3417
3240
|
if (argsFormattedAddons.length > 0) argsFormatted.push("--add", ...argsFormattedAddons);
|
|
3418
3241
|
const prompt = buildAndLogArgs(packageManager, "create", argsFormatted, [directory]);
|
|
3419
3242
|
updateReadme(directory, prompt);
|
|
3243
|
+
if (packageManager) workspace.packageManager = packageManager;
|
|
3244
|
+
const addOnNextSteps = getNextSteps(addOnSuccessfulAddons, workspace, answers);
|
|
3420
3245
|
await addPnpmBuildDependencies(projectPath, packageManager, ["esbuild"]);
|
|
3421
3246
|
if (packageManager) {
|
|
3422
3247
|
await installDependencies(packageManager, projectPath);
|
|
@@ -6473,7 +6298,7 @@ async function promptAddonQuestions({ options: options$8, loadedAddons, workspac
|
|
|
6473
6298
|
if (addons.length > 0) setupResults = setupAddons(addons, workspace);
|
|
6474
6299
|
if (addons.length === 0) {
|
|
6475
6300
|
const results = setupAddons(officialAddons.map((a) => createLoadedAddon(a)), workspace);
|
|
6476
|
-
const addonOptions$1 = officialAddons.filter(({ id }) => results[id].unsupported.length === 0).map(({ id, homepage, shortDescription }) => ({
|
|
6301
|
+
const addonOptions$1 = officialAddons.filter(({ id, hidden }) => results[id].unsupported.length === 0 && !hidden).map(({ id, homepage, shortDescription }) => ({
|
|
6477
6302
|
label: id,
|
|
6478
6303
|
value: id,
|
|
6479
6304
|
hint: `${shortDescription} - ${homepage}`
|
|
@@ -6616,7 +6441,8 @@ async function runAddonsApply({ answers, options: options$8, loadedAddons, setup
|
|
|
6616
6441
|
if (loadedAddons.length === 0) return {
|
|
6617
6442
|
nextSteps: [],
|
|
6618
6443
|
argsFormattedAddons: [],
|
|
6619
|
-
filesToFormat: []
|
|
6444
|
+
filesToFormat: [],
|
|
6445
|
+
successfulAddons: []
|
|
6620
6446
|
};
|
|
6621
6447
|
const { filesToFormat, pnpmBuildDependencies, status } = await applyAddons({
|
|
6622
6448
|
loadedAddons,
|
|
@@ -6677,23 +6503,27 @@ async function runAddonsApply({ answers, options: options$8, loadedAddons, setup
|
|
|
6677
6503
|
});
|
|
6678
6504
|
}
|
|
6679
6505
|
return {
|
|
6680
|
-
nextSteps: successfulAddons
|
|
6681
|
-
const addon = loaded.addon;
|
|
6682
|
-
if (!addon.nextSteps) return;
|
|
6683
|
-
const addonOptions$1 = answers[addon.id];
|
|
6684
|
-
const addonNextSteps = addon.nextSteps({
|
|
6685
|
-
...workspace,
|
|
6686
|
-
options: addonOptions$1
|
|
6687
|
-
});
|
|
6688
|
-
if (addonNextSteps.length === 0) return;
|
|
6689
|
-
let addonMessage = `${color.addon(addon.id)}:\n`;
|
|
6690
|
-
addonMessage += ` - ${addonNextSteps.join("\n - ")}`;
|
|
6691
|
-
return addonMessage;
|
|
6692
|
-
}).filter((msg) => msg !== void 0),
|
|
6506
|
+
nextSteps: getNextSteps(successfulAddons, workspace, answers),
|
|
6693
6507
|
argsFormattedAddons,
|
|
6694
|
-
filesToFormat
|
|
6508
|
+
filesToFormat,
|
|
6509
|
+
successfulAddons
|
|
6695
6510
|
};
|
|
6696
6511
|
}
|
|
6512
|
+
function getNextSteps(loadedAddons, workspace, answers) {
|
|
6513
|
+
return loadedAddons.map((loaded) => {
|
|
6514
|
+
const addon = loaded.addon;
|
|
6515
|
+
if (!addon.nextSteps) return;
|
|
6516
|
+
const addonOptions$1 = answers[addon.id];
|
|
6517
|
+
const addonNextSteps = addon.nextSteps({
|
|
6518
|
+
...workspace,
|
|
6519
|
+
options: addonOptions$1
|
|
6520
|
+
});
|
|
6521
|
+
if (addonNextSteps.length === 0) return;
|
|
6522
|
+
let addonMessage = `${color.addon(addon.id)}:\n`;
|
|
6523
|
+
addonMessage += ` - ${addonNextSteps.join("\n - ")}`;
|
|
6524
|
+
return addonMessage;
|
|
6525
|
+
}).filter((msg) => msg !== void 0);
|
|
6526
|
+
}
|
|
6697
6527
|
/**
|
|
6698
6528
|
* Handles passed add-on arguments, accumulating them into an array of AddonInput.
|
|
6699
6529
|
*/
|
|
@@ -6779,7 +6609,7 @@ function getOptionChoices(details) {
|
|
|
6779
6609
|
}
|
|
6780
6610
|
async function resolveNonOfficialAddons(refs, downloadCheck) {
|
|
6781
6611
|
const selectedAddons = [];
|
|
6782
|
-
const { start, stop } =
|
|
6612
|
+
const { start, stop } = Ie();
|
|
6783
6613
|
try {
|
|
6784
6614
|
start(`Resolving ${refs.map((r) => color.addon(r.specifier)).join(", ")} packages`);
|
|
6785
6615
|
const pkgs = await Promise.all(refs.map(async (ref) => {
|